github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/fuse/readonly/ipfs_test.go (about)

     1  // +build !nofuse
     2  
     3  package readonly
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"math/rand"
    10  	"os"
    11  	"path"
    12  	"sync"
    13  	"testing"
    14  
    15  	fstest "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
    16  
    17  	key "github.com/ipfs/go-ipfs/blocks/key"
    18  	core "github.com/ipfs/go-ipfs/core"
    19  	coreunix "github.com/ipfs/go-ipfs/core/coreunix"
    20  	coremock "github.com/ipfs/go-ipfs/core/mock"
    21  	importer "github.com/ipfs/go-ipfs/importer"
    22  	chunk "github.com/ipfs/go-ipfs/importer/chunk"
    23  	dag "github.com/ipfs/go-ipfs/merkledag"
    24  	uio "github.com/ipfs/go-ipfs/unixfs/io"
    25  	u "github.com/ipfs/go-ipfs/util"
    26  	ci "github.com/ipfs/go-ipfs/util/testutil/ci"
    27  )
    28  
    29  func maybeSkipFuseTests(t *testing.T) {
    30  	if ci.NoFuse() {
    31  		t.Skip("Skipping FUSE tests")
    32  	}
    33  }
    34  
    35  func randObj(t *testing.T, nd *core.IpfsNode, size int64) (*dag.Node, []byte) {
    36  	buf := make([]byte, size)
    37  	u.NewTimeSeededRand().Read(buf)
    38  	read := bytes.NewReader(buf)
    39  	obj, err := importer.BuildTrickleDagFromReader(nd.DAG, chunk.DefaultSplitter(read), nil)
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  
    44  	return obj, buf
    45  }
    46  
    47  func setupIpfsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.Mount) {
    48  	maybeSkipFuseTests(t)
    49  
    50  	var err error
    51  	if node == nil {
    52  		node, err = coremock.NewMockNode()
    53  		if err != nil {
    54  			t.Fatal(err)
    55  		}
    56  	}
    57  
    58  	fs := NewFileSystem(node)
    59  	mnt, err := fstest.MountedT(t, fs)
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	return node, mnt
    65  }
    66  
    67  // Test writing an object and reading it back through fuse
    68  func TestIpfsBasicRead(t *testing.T) {
    69  	if testing.Short() {
    70  		t.SkipNow()
    71  	}
    72  	nd, mnt := setupIpfsTest(t, nil)
    73  	defer mnt.Close()
    74  
    75  	fi, data := randObj(t, nd, 10000)
    76  	k, err := fi.Key()
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  
    81  	fname := path.Join(mnt.Dir, k.String())
    82  	rbuf, err := ioutil.ReadFile(fname)
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  
    87  	if !bytes.Equal(rbuf, data) {
    88  		t.Fatal("Incorrect Read!")
    89  	}
    90  }
    91  
    92  func getPaths(t *testing.T, ipfs *core.IpfsNode, name string, n *dag.Node) []string {
    93  	if len(n.Links) == 0 {
    94  		return []string{name}
    95  	}
    96  	var out []string
    97  	for _, lnk := range n.Links {
    98  		child, err := lnk.GetNode(ipfs.Context(), ipfs.DAG)
    99  		if err != nil {
   100  			t.Fatal(err)
   101  		}
   102  		sub := getPaths(t, ipfs, path.Join(name, lnk.Name), child)
   103  		out = append(out, sub...)
   104  	}
   105  	return out
   106  }
   107  
   108  // Perform a large number of concurrent reads to stress the system
   109  func TestIpfsStressRead(t *testing.T) {
   110  	if testing.Short() {
   111  		t.SkipNow()
   112  	}
   113  	nd, mnt := setupIpfsTest(t, nil)
   114  	defer mnt.Close()
   115  
   116  	var ks []key.Key
   117  	var paths []string
   118  
   119  	nobj := 50
   120  	ndiriter := 50
   121  
   122  	// Make a bunch of objects
   123  	for i := 0; i < nobj; i++ {
   124  		fi, _ := randObj(t, nd, rand.Int63n(50000))
   125  		k, err := fi.Key()
   126  		if err != nil {
   127  			t.Fatal(err)
   128  		}
   129  
   130  		ks = append(ks, k)
   131  		paths = append(paths, k.String())
   132  	}
   133  
   134  	// Now make a bunch of dirs
   135  	for i := 0; i < ndiriter; i++ {
   136  		db := uio.NewDirectory(nd.DAG)
   137  		for j := 0; j < 1+rand.Intn(10); j++ {
   138  			name := fmt.Sprintf("child%d", j)
   139  			err := db.AddChild(name, ks[rand.Intn(len(ks))])
   140  			if err != nil {
   141  				t.Fatal(err)
   142  			}
   143  		}
   144  		newdir := db.GetNode()
   145  		k, err := nd.DAG.Add(newdir)
   146  		if err != nil {
   147  			t.Fatal(err)
   148  		}
   149  
   150  		ks = append(ks, k)
   151  		npaths := getPaths(t, nd, k.String(), newdir)
   152  		paths = append(paths, npaths...)
   153  	}
   154  
   155  	// Now read a bunch, concurrently
   156  	wg := sync.WaitGroup{}
   157  
   158  	for s := 0; s < 4; s++ {
   159  		wg.Add(1)
   160  		go func() {
   161  			defer wg.Done()
   162  
   163  			for i := 0; i < 2000; i++ {
   164  				item := paths[rand.Intn(len(paths))]
   165  				fname := path.Join(mnt.Dir, item)
   166  				rbuf, err := ioutil.ReadFile(fname)
   167  				if err != nil {
   168  					t.Fatal(err)
   169  				}
   170  
   171  				read, err := coreunix.Cat(nd, item)
   172  				if err != nil {
   173  					t.Fatal(err)
   174  				}
   175  
   176  				data, err := ioutil.ReadAll(read)
   177  				if err != nil {
   178  					t.Fatal(err)
   179  				}
   180  
   181  				if !bytes.Equal(rbuf, data) {
   182  					t.Fatal("Incorrect Read!")
   183  				}
   184  			}
   185  		}()
   186  	}
   187  	wg.Wait()
   188  }
   189  
   190  // Test writing a file and reading it back
   191  func TestIpfsBasicDirRead(t *testing.T) {
   192  	if testing.Short() {
   193  		t.SkipNow()
   194  	}
   195  	nd, mnt := setupIpfsTest(t, nil)
   196  	defer mnt.Close()
   197  
   198  	// Make a 'file'
   199  	fi, data := randObj(t, nd, 10000)
   200  	k, err := fi.Key()
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  
   205  	// Make a directory and put that file in it
   206  	db := uio.NewDirectory(nd.DAG)
   207  	err = db.AddChild("actual", k)
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  
   212  	d1nd := db.GetNode()
   213  	d1ndk, err := nd.DAG.Add(d1nd)
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  
   218  	dirname := path.Join(mnt.Dir, d1ndk.String())
   219  	fname := path.Join(dirname, "actual")
   220  	rbuf, err := ioutil.ReadFile(fname)
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  
   225  	dirents, err := ioutil.ReadDir(dirname)
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  	if len(dirents) != 1 {
   230  		t.Fatal("Bad directory entry count")
   231  	}
   232  	if dirents[0].Name() != "actual" {
   233  		t.Fatal("Bad directory entry")
   234  	}
   235  
   236  	if !bytes.Equal(rbuf, data) {
   237  		t.Fatal("Incorrect Read!")
   238  	}
   239  }
   240  
   241  // Test to make sure the filesystem reports file sizes correctly
   242  func TestFileSizeReporting(t *testing.T) {
   243  	if testing.Short() {
   244  		t.SkipNow()
   245  	}
   246  	nd, mnt := setupIpfsTest(t, nil)
   247  	defer mnt.Close()
   248  
   249  	fi, data := randObj(t, nd, 10000)
   250  	k, err := fi.Key()
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  
   255  	fname := path.Join(mnt.Dir, k.String())
   256  
   257  	finfo, err := os.Stat(fname)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	if finfo.Size() != int64(len(data)) {
   263  		t.Fatal("Read incorrect size from stat!")
   264  	}
   265  }