From 5dd32d6491e672d1f5ee174036647133b0fed571 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Sat, 5 Dec 2015 23:42:34 -0800 Subject: [PATCH] Add test for running gc during an add License: MIT Signed-off-by: Jeromy --- core/coreunix/add.go | 2 +- core/coreunix/add_test.go | 130 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/core/coreunix/add.go b/core/coreunix/add.go index 80a4bb6ad..64bb6ad30 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -155,7 +155,7 @@ func (params *Adder) PinRoot() error { return nil } - rnk, err := root.Key() + rnk, err := params.node.DAG.Add(root) if err != nil { return err } diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go index 279d7ce74..56c921eeb 100644 --- a/core/coreunix/add_test.go +++ b/core/coreunix/add_test.go @@ -1,10 +1,18 @@ package coreunix import ( + "bytes" + "io" + "io/ioutil" "testing" + "time" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "github.com/ipfs/go-ipfs/blocks/key" + "github.com/ipfs/go-ipfs/commands/files" "github.com/ipfs/go-ipfs/core" + dag "github.com/ipfs/go-ipfs/merkledag" + "github.com/ipfs/go-ipfs/pin/gc" "github.com/ipfs/go-ipfs/repo" "github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/util/testutil" @@ -29,3 +37,125 @@ func TestAddRecursive(t *testing.T) { t.Fatal("keys do not match: ", k) } } + +func TestAddGCLive(t *testing.T) { + r := &repo.Mock{ + C: config.Config{ + Identity: config.Identity{ + PeerID: "Qmfoo", // required by offline node + }, + }, + D: testutil.ThreadSafeCloserMapDatastore(), + } + node, err := core.NewNode(context.Background(), &core.BuildCfg{Repo: r}) + if err != nil { + t.Fatal(err) + } + + errs := make(chan error) + out := make(chan interface{}) + adder, err := NewAdder(context.Background(), node, out) + if err != nil { + t.Fatal(err) + } + + dataa := ioutil.NopCloser(bytes.NewBufferString("testfileA")) + rfa := files.NewReaderFile("a", "a", dataa, nil) + + // make two files with pipes so we can 'pause' the add for timing of the test + piper, pipew := io.Pipe() + hangfile := files.NewReaderFile("b", "b", piper, nil) + + datad := ioutil.NopCloser(bytes.NewBufferString("testfileD")) + rfd := files.NewReaderFile("d", "d", datad, nil) + + slf := files.NewSliceFile("files", "files", []files.File{rfa, hangfile, rfd}) + + addDone := make(chan struct{}) + go func() { + defer close(addDone) + defer close(out) + err := adder.AddFile(slf) + + if err != nil { + t.Fatal(err) + } + + }() + + addedHashes := make(map[string]struct{}) + select { + case o := <-out: + addedHashes[o.(*AddedObject).Hash] = struct{}{} + case <-addDone: + t.Fatal("add shouldnt complete yet") + } + + var gcout <-chan key.Key + gcstarted := make(chan struct{}) + go func() { + defer close(gcstarted) + gcchan, err := gc.GC(context.Background(), node.Blockstore, node.Pinning) + if err != nil { + log.Error("GC ERROR:", err) + errs <- err + return + } + + gcout = gcchan + }() + + // gc shouldnt start until we let the add finish its current file. + pipew.Write([]byte("some data for file b")) + + select { + case <-gcstarted: + t.Fatal("gc shouldnt have started yet") + case err := <-errs: + t.Fatal(err) + default: + } + + time.Sleep(time.Millisecond * 100) // make sure gc gets to requesting lock + + // finish write and unblock gc + pipew.Close() + + // receive next object from adder + select { + case o := <-out: + addedHashes[o.(*AddedObject).Hash] = struct{}{} + case err := <-errs: + t.Fatal(err) + } + + select { + case <-gcstarted: + case err := <-errs: + t.Fatal(err) + } + + for k := range gcout { + if _, ok := addedHashes[k.B58String()]; ok { + t.Fatal("gc'ed a hash we just added") + } + } + + var last key.Key + for a := range out { + // wait for it to finish + last = key.B58KeyDecode(a.(*AddedObject).Hash) + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + root, err := node.DAG.Get(ctx, last) + if err != nil { + t.Fatal(err) + } + + err = dag.EnumerateChildren(ctx, node.DAG, root, key.NewKeySet()) + if err != nil { + t.Fatal(err) + } +}