From fd4c4122d0a9cfab582b878759d1f5062d0f9982 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Sat, 26 Dec 2015 17:24:31 -0800 Subject: [PATCH] add test and locking fix License: MIT Signed-off-by: Jeromy --- mfs/dir.go | 15 ++++- mfs/mfs_test.go | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/mfs/dir.go b/mfs/dir.go index 3ec39bf7d..b714cb093 100644 --- a/mfs/dir.go +++ b/mfs/dir.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "path" "sync" "time" @@ -48,7 +49,7 @@ func NewDirectory(ctx context.Context, name string, node *dag.Node, parent child } // closeChild updates the child by the given name to the dag node 'nd' -// and changes its own dag node, then propogates the changes upward +// and changes its own dag node func (d *Directory) closeChild(name string, nd *dag.Node) error { mynd, err := d.closeChildUpdate(name, nd) if err != nil { @@ -300,7 +301,7 @@ func (d *Directory) Unlink(name string) error { return err } - return d.parent.closeChild(d.name, d.node) + return nil } func (d *Directory) Flush() error { @@ -375,6 +376,16 @@ func (d *Directory) sync() error { return nil } +func (d *Directory) Path() string { + cur := d + var out string + for cur != nil { + out = path.Join(cur.name, out) + cur = cur.parent.(*Directory) + } + return out +} + func (d *Directory) GetNode() (*dag.Node, error) { d.lock.Lock() defer d.lock.Unlock() diff --git a/mfs/mfs_test.go b/mfs/mfs_test.go index 62f0d0836..65e1e1a84 100644 --- a/mfs/mfs_test.go +++ b/mfs/mfs_test.go @@ -6,10 +6,12 @@ import ( "fmt" "io" "io/ioutil" + "math/rand" "os" "sort" "testing" + randbo "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" @@ -474,3 +476,146 @@ func TestMfsFile(t *testing.T) { t.Fatal(err) } } + +func randomWalk(d *Directory, n int) (*Directory, error) { + for i := 0; i < n; i++ { + dirents, err := d.List() + if err != nil { + return nil, err + } + + var childdirs []NodeListing + for _, child := range dirents { + if child.Type == int(TDir) { + childdirs = append(childdirs, child) + } + } + if len(childdirs) == 0 { + return d, nil + } + + next := childdirs[rand.Intn(len(childdirs))].Name + + nextD, err := d.Child(next) + if err != nil { + return nil, err + } + + d = nextD.(*Directory) + } + return d, nil +} + +func randomName() string { + set := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_" + length := rand.Intn(10) + 2 + var out string + for i := 0; i < length; i++ { + j := rand.Intn(len(set)) + out += set[j : j+1] + } + return out +} + +func actorMakeFile(d *Directory) error { + d, err := randomWalk(d, rand.Intn(7)) + if err != nil { + return err + } + + name := randomName() + f, err := NewFile(name, &dag.Node{Data: ft.FilePBData(nil, 0)}, d, d.dserv) + if err != nil { + return err + } + + r := io.LimitReader(randbo.New(), int64(77*rand.Intn(123))) + _, err = io.Copy(f, r) + if err != nil { + return err + } + + err = f.Close() + if err != nil { + return err + } + + return nil +} +func actorMkdir(d *Directory) error { + d, err := randomWalk(d, rand.Intn(7)) + if err != nil { + return err + } + + _, err = d.Mkdir(randomName()) + if err != nil { + return err + } + + return nil +} + +func actorRemoveFile(d *Directory) error { + d, err := randomWalk(d, rand.Intn(7)) + if err != nil { + return err + } + + ents, err := d.List() + if err != nil { + return err + } + + if len(ents) == 0 { + return nil + } + + re := ents[rand.Intn(len(ents))] + + return d.Unlink(re.Name) +} + +func testActor(rt *Root, iterations int, errs chan error) { + d := rt.GetValue().(*Directory) + for i := 0; i < iterations; i++ { + switch rand.Intn(4) { + case 0: + if err := actorMkdir(d); err != nil { + errs <- err + return + } + case 1, 2: + if err := actorMakeFile(d); err != nil { + errs <- err + return + } + case 3: + if err := actorRemoveFile(d); err != nil { + errs <- err + return + } + } + } + errs <- nil +} + +func TestMfsStress(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, rt := setupRoot(ctx, t) + + numroutines := 2 + + errs := make(chan error) + for i := 0; i < numroutines; i++ { + go testActor(rt, 50, errs) + } + + for i := 0; i < numroutines; i++ { + err := <-errs + if err != nil { + t.Fatal(err) + } + } +}