From fd4c4122d0a9cfab582b878759d1f5062d0f9982 Mon Sep 17 00:00:00 2001
From: Jeromy <jeromyj@gmail.com>
Date: Sat, 26 Dec 2015 17:24:31 -0800
Subject: [PATCH] add test and locking fix

License: MIT
Signed-off-by: Jeromy <jeromyj@gmail.com>
---
 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)
+		}
+	}
+}
-- 
GitLab