github.com/gochain-io/gochain@v2.2.26+incompatible/swarm/fuse/swarmfs_test.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // +build linux darwin freebsd
    18  
    19  package fuse
    20  
    21  import (
    22  	"bytes"
    23  	"crypto/rand"
    24  	"io"
    25  	"io/ioutil"
    26  	"os"
    27  	"path/filepath"
    28  	"testing"
    29  
    30  	"github.com/gochain-io/gochain/swarm/api"
    31  	"github.com/gochain-io/gochain/swarm/storage"
    32  )
    33  
    34  type fileInfo struct {
    35  	perm     uint64
    36  	uid      int
    37  	gid      int
    38  	contents []byte
    39  }
    40  
    41  func createTestFilesAndUploadToSwarm(t *testing.T, api *api.Api, files map[string]fileInfo, uploadDir string) string {
    42  	os.RemoveAll(uploadDir)
    43  
    44  	for fname, finfo := range files {
    45  		actualPath := filepath.Join(uploadDir, fname)
    46  		filePath := filepath.Dir(actualPath)
    47  
    48  		err := os.MkdirAll(filePath, 0777)
    49  		if err != nil {
    50  			t.Fatalf("Error creating directory '%v' : %v", filePath, err)
    51  		}
    52  
    53  		fd, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(finfo.perm))
    54  		if err1 != nil {
    55  			t.Fatalf("Error creating file %v: %v", actualPath, err1)
    56  		}
    57  
    58  		fd.Write(finfo.contents)
    59  		fd.Chown(finfo.uid, finfo.gid)
    60  		fd.Chmod(os.FileMode(finfo.perm))
    61  		fd.Sync()
    62  		fd.Close()
    63  	}
    64  
    65  	bzzhash, err := api.Upload(uploadDir, "")
    66  	if err != nil {
    67  		t.Fatalf("Error uploading directory %v: %v", uploadDir, err)
    68  	}
    69  
    70  	return bzzhash
    71  }
    72  
    73  func mountDir(t *testing.T, api *api.Api, files map[string]fileInfo, bzzHash string, mountDir string) *SwarmFS {
    74  	os.RemoveAll(mountDir)
    75  	os.MkdirAll(mountDir, 0777)
    76  	swarmfs := NewSwarmFS(api)
    77  	_, err := swarmfs.Mount(bzzHash, mountDir)
    78  	if isFUSEUnsupportedError(err) {
    79  		t.Skip("FUSE not supported:", err)
    80  	} else if err != nil {
    81  		t.Fatalf("Error mounting hash %v: %v", bzzHash, err)
    82  	}
    83  
    84  	found := false
    85  	mi := swarmfs.Listmounts()
    86  	for _, minfo := range mi {
    87  		if minfo.MountPoint == mountDir {
    88  			minfo.LatestManifestMu.RLock()
    89  			lm := minfo.LatestManifest
    90  			minfo.LatestManifestMu.RUnlock()
    91  			if minfo.StartManifest != bzzHash || lm != bzzHash || minfo.fuseConnection == nil {
    92  				t.Fatalf("Error mounting: exp(%s): act(%s)", bzzHash, minfo.StartManifest)
    93  			}
    94  			found = true
    95  		}
    96  	}
    97  
    98  	// Test listMounts
    99  	if !found {
   100  		t.Fatalf("Error getting mounts information for %v: %v", mountDir, err)
   101  	}
   102  
   103  	// Check if file and their attributes are as expected
   104  	compareGeneratedFileWithFileInMount(t, files, mountDir)
   105  
   106  	return swarmfs
   107  }
   108  
   109  func compareGeneratedFileWithFileInMount(t *testing.T, files map[string]fileInfo, mountDir string) {
   110  	err := filepath.Walk(mountDir, func(path string, f os.FileInfo, err error) error {
   111  		if f.IsDir() {
   112  			return nil
   113  		}
   114  		fname := path[len(mountDir)+1:]
   115  		if _, ok := files[fname]; !ok {
   116  			t.Fatalf(" file %v present in mount dir and is not expected", fname)
   117  		}
   118  		return nil
   119  	})
   120  	if err != nil {
   121  		t.Fatalf("Error walking dir %v", mountDir)
   122  	}
   123  
   124  	for fname, finfo := range files {
   125  		destinationFile := filepath.Join(mountDir, fname)
   126  
   127  		dfinfo, err := os.Stat(destinationFile)
   128  		if err != nil {
   129  			t.Fatalf("Destination file %v missing in mount: %v", fname, err)
   130  		}
   131  
   132  		if int64(len(finfo.contents)) != dfinfo.Size() {
   133  			t.Fatalf("file %v Size mismatch  source (%v) vs destination(%v)", fname, int64(len(finfo.contents)), dfinfo.Size())
   134  		}
   135  
   136  		if dfinfo.Mode().Perm().String() != "-rwx------" {
   137  			t.Fatalf("file %v Permission mismatch source (-rwx------) vs destination(%v)", fname, dfinfo.Mode().Perm())
   138  		}
   139  
   140  		fileContents, err := ioutil.ReadFile(filepath.Join(mountDir, fname))
   141  		if err != nil {
   142  			t.Fatalf("Could not readfile %v : %v", fname, err)
   143  		}
   144  		if !bytes.Equal(fileContents, finfo.contents) {
   145  			t.Fatalf("File %v contents mismatch: %v , %v", fname, fileContents, finfo.contents)
   146  
   147  		}
   148  		// TODO: check uid and gid
   149  	}
   150  }
   151  
   152  func checkFile(t *testing.T, testMountDir, fname string, contents []byte) {
   153  	destinationFile := filepath.Join(testMountDir, fname)
   154  	dfinfo, err1 := os.Stat(destinationFile)
   155  	if err1 != nil {
   156  		t.Fatalf("Could not stat file %v", destinationFile)
   157  	}
   158  	if dfinfo.Size() != int64(len(contents)) {
   159  		t.Fatalf("Mismatch in size  actual(%v) vs expected(%v)", dfinfo.Size(), int64(len(contents)))
   160  	}
   161  
   162  	fd, err2 := os.OpenFile(destinationFile, os.O_RDONLY, os.FileMode(0665))
   163  	if err2 != nil {
   164  		t.Fatalf("Could not open file %v", destinationFile)
   165  	}
   166  	newcontent := make([]byte, len(contents))
   167  	fd.Read(newcontent)
   168  	fd.Close()
   169  
   170  	if !bytes.Equal(contents, newcontent) {
   171  		t.Fatalf("File content mismatch expected (%v): received (%v) ", contents, newcontent)
   172  	}
   173  }
   174  
   175  func getRandomBtes(size int) []byte {
   176  	contents := make([]byte, size)
   177  	rand.Read(contents)
   178  	return contents
   179  }
   180  
   181  func isDirEmpty(name string) bool {
   182  	f, err := os.Open(name)
   183  	if err != nil {
   184  		return false
   185  	}
   186  	defer f.Close()
   187  
   188  	_, err = f.Readdirnames(1)
   189  
   190  	return err == io.EOF
   191  }
   192  
   193  type testAPI struct {
   194  	api *api.Api
   195  }
   196  
   197  func (ta *testAPI) mountListAndUnmount(t *testing.T) {
   198  	files := make(map[string]fileInfo)
   199  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "fuse-source")
   200  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "fuse-dest")
   201  
   202  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   203  	files["2.txt"] = fileInfo{0711, 333, 444, getRandomBtes(10)}
   204  	files["3.txt"] = fileInfo{0622, 333, 444, getRandomBtes(100)}
   205  	files["4.txt"] = fileInfo{0533, 333, 444, getRandomBtes(1024)}
   206  	files["5.txt"] = fileInfo{0544, 333, 444, getRandomBtes(10)}
   207  	files["6.txt"] = fileInfo{0555, 333, 444, getRandomBtes(10)}
   208  	files["7.txt"] = fileInfo{0666, 333, 444, getRandomBtes(10)}
   209  	files["8.txt"] = fileInfo{0777, 333, 333, getRandomBtes(10)}
   210  	files["11.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)}
   211  	files["111.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)}
   212  	files["two/2.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)}
   213  	files["two/2/2.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)}
   214  	files["two/2./2.txt"] = fileInfo{0777, 444, 444, getRandomBtes(10)}
   215  	files["twice/2.txt"] = fileInfo{0777, 444, 333, getRandomBtes(200)}
   216  	files["one/two/three/four/five/six/seven/eight/nine/10.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10240)}
   217  	files["one/two/three/four/five/six/six"] = fileInfo{0777, 333, 444, getRandomBtes(10)}
   218  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   219  
   220  	swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir)
   221  	defer swarmfs.Stop()
   222  
   223  	// Check unmount
   224  	_, err := swarmfs.Unmount(testMountDir)
   225  	if err != nil {
   226  		t.Fatalf("could not unmount  %v", bzzHash)
   227  	}
   228  	if !isDirEmpty(testMountDir) {
   229  		t.Fatalf("unmount didnt work for %v", testMountDir)
   230  	}
   231  
   232  }
   233  
   234  func (ta *testAPI) maxMounts(t *testing.T) {
   235  	files := make(map[string]fileInfo)
   236  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   237  	uploadDir1, _ := ioutil.TempDir(os.TempDir(), "max-upload1")
   238  	bzzHash1 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir1)
   239  	mount1, _ := ioutil.TempDir(os.TempDir(), "max-mount1")
   240  	swarmfs1 := mountDir(t, ta.api, files, bzzHash1, mount1)
   241  	defer swarmfs1.Stop()
   242  
   243  	files["2.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   244  	uploadDir2, _ := ioutil.TempDir(os.TempDir(), "max-upload2")
   245  	bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir2)
   246  	mount2, _ := ioutil.TempDir(os.TempDir(), "max-mount2")
   247  	swarmfs2 := mountDir(t, ta.api, files, bzzHash2, mount2)
   248  	defer swarmfs2.Stop()
   249  
   250  	files["3.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   251  	uploadDir3, _ := ioutil.TempDir(os.TempDir(), "max-upload3")
   252  	bzzHash3 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir3)
   253  	mount3, _ := ioutil.TempDir(os.TempDir(), "max-mount3")
   254  	swarmfs3 := mountDir(t, ta.api, files, bzzHash3, mount3)
   255  	defer swarmfs3.Stop()
   256  
   257  	files["4.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   258  	uploadDir4, _ := ioutil.TempDir(os.TempDir(), "max-upload4")
   259  	bzzHash4 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir4)
   260  	mount4, _ := ioutil.TempDir(os.TempDir(), "max-mount4")
   261  	swarmfs4 := mountDir(t, ta.api, files, bzzHash4, mount4)
   262  	defer swarmfs4.Stop()
   263  
   264  	files["5.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   265  	uploadDir5, _ := ioutil.TempDir(os.TempDir(), "max-upload5")
   266  	bzzHash5 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir5)
   267  	mount5, _ := ioutil.TempDir(os.TempDir(), "max-mount5")
   268  	swarmfs5 := mountDir(t, ta.api, files, bzzHash5, mount5)
   269  	defer swarmfs5.Stop()
   270  
   271  	files["6.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   272  	uploadDir6, _ := ioutil.TempDir(os.TempDir(), "max-upload6")
   273  	bzzHash6 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir6)
   274  	mount6, _ := ioutil.TempDir(os.TempDir(), "max-mount6")
   275  
   276  	os.RemoveAll(mount6)
   277  	os.MkdirAll(mount6, 0777)
   278  	_, err := swarmfs.Mount(bzzHash6, mount6)
   279  	if err == nil {
   280  		t.Fatalf("Error: Going beyond max mounts  %v", bzzHash6)
   281  	}
   282  
   283  }
   284  
   285  func (ta *testAPI) remount(t *testing.T) {
   286  	files := make(map[string]fileInfo)
   287  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   288  	uploadDir1, _ := ioutil.TempDir(os.TempDir(), "re-upload1")
   289  	bzzHash1 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir1)
   290  	testMountDir1, _ := ioutil.TempDir(os.TempDir(), "re-mount1")
   291  	swarmfs := mountDir(t, ta.api, files, bzzHash1, testMountDir1)
   292  	defer swarmfs.Stop()
   293  
   294  	uploadDir2, _ := ioutil.TempDir(os.TempDir(), "re-upload2")
   295  	bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir2)
   296  	testMountDir2, _ := ioutil.TempDir(os.TempDir(), "re-mount2")
   297  
   298  	// try mounting the same hash second time
   299  	os.RemoveAll(testMountDir2)
   300  	os.MkdirAll(testMountDir2, 0777)
   301  	_, err := swarmfs.Mount(bzzHash1, testMountDir2)
   302  	if err != nil {
   303  		t.Fatalf("Error mounting hash  %v", bzzHash1)
   304  	}
   305  
   306  	// mount a different hash in already mounted point
   307  	_, err = swarmfs.Mount(bzzHash2, testMountDir1)
   308  	if err == nil {
   309  		t.Fatalf("Error mounting hash  %v", bzzHash2)
   310  	}
   311  
   312  	// mount nonexistent hash
   313  	_, err = swarmfs.Mount("0xfea11223344", testMountDir1)
   314  	if err == nil {
   315  		t.Fatalf("Error mounting hash  %v", bzzHash2)
   316  	}
   317  }
   318  
   319  func (ta *testAPI) unmount(t *testing.T) {
   320  	files := make(map[string]fileInfo)
   321  	uploadDir, _ := ioutil.TempDir(os.TempDir(), "ex-upload")
   322  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "ex-mount")
   323  
   324  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   325  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir)
   326  
   327  	swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir)
   328  	defer swarmfs.Stop()
   329  
   330  	swarmfs.Unmount(testMountDir)
   331  
   332  	mi := swarmfs.Listmounts()
   333  	for _, minfo := range mi {
   334  		if minfo.MountPoint == testMountDir {
   335  			t.Fatalf("mount state not cleaned up in unmount case %v", testMountDir)
   336  		}
   337  	}
   338  }
   339  
   340  func (ta *testAPI) unmountWhenResourceBusy(t *testing.T) {
   341  	files := make(map[string]fileInfo)
   342  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "ex-upload")
   343  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "ex-mount")
   344  
   345  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   346  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   347  
   348  	swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir)
   349  	defer swarmfs.Stop()
   350  
   351  	actualPath := filepath.Join(testMountDir, "2.txt")
   352  	d, err := os.OpenFile(actualPath, os.O_RDWR, os.FileMode(0700))
   353  	d.Write(getRandomBtes(10))
   354  
   355  	_, err = swarmfs.Unmount(testMountDir)
   356  	if err != nil {
   357  		t.Fatalf("could not unmount  %v", bzzHash)
   358  	}
   359  	d.Close()
   360  
   361  	mi := swarmfs.Listmounts()
   362  	for _, minfo := range mi {
   363  		if minfo.MountPoint == testMountDir {
   364  			t.Fatalf("mount state not cleaned up in unmount case %v", testMountDir)
   365  		}
   366  	}
   367  }
   368  
   369  func (ta *testAPI) seekInMultiChunkFile(t *testing.T) {
   370  	files := make(map[string]fileInfo)
   371  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "seek-upload")
   372  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "seek-mount")
   373  
   374  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10240)}
   375  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   376  
   377  	swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir)
   378  	defer swarmfs.Stop()
   379  
   380  	// Create a new file seek the second chunk
   381  	actualPath := filepath.Join(testMountDir, "1.txt")
   382  	d, _ := os.OpenFile(actualPath, os.O_RDONLY, os.FileMode(0700))
   383  
   384  	d.Seek(5000, 0)
   385  
   386  	contents := make([]byte, 1024)
   387  	d.Read(contents)
   388  	finfo := files["1.txt"]
   389  
   390  	if !bytes.Equal(finfo.contents[:6024][5000:], contents) {
   391  		t.Fatalf("File seek contents mismatch")
   392  	}
   393  	d.Close()
   394  }
   395  
   396  func (ta *testAPI) createNewFile(t *testing.T) {
   397  	files := make(map[string]fileInfo)
   398  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "create-upload")
   399  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "create-mount")
   400  
   401  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   402  	files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   403  	files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   404  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   405  
   406  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   407  	defer swarmfs1.Stop()
   408  
   409  	// Create a new file in the root dir and check
   410  	actualPath := filepath.Join(testMountDir, "2.txt")
   411  	d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665))
   412  	if err1 != nil {
   413  		t.Fatalf("Could not create file %s : %v", actualPath, err1)
   414  	}
   415  	contents := make([]byte, 11)
   416  	rand.Read(contents)
   417  	d.Write(contents)
   418  	d.Close()
   419  
   420  	mi, err2 := swarmfs1.Unmount(testMountDir)
   421  	if err2 != nil {
   422  		t.Fatalf("Could not unmount %v", err2)
   423  	}
   424  
   425  	// mount again and see if things are okay
   426  	files["2.txt"] = fileInfo{0700, 333, 444, contents}
   427  	mi.LatestManifestMu.RLock()
   428  	lm := mi.LatestManifest
   429  	mi.LatestManifestMu.RUnlock()
   430  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   431  	defer swarmfs2.Stop()
   432  
   433  	checkFile(t, testMountDir, "2.txt", contents)
   434  }
   435  
   436  func (ta *testAPI) createNewFileInsideDirectory(t *testing.T) {
   437  	files := make(map[string]fileInfo)
   438  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "createinsidedir-upload")
   439  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "createinsidedir-mount")
   440  
   441  	files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   442  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   443  
   444  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   445  	defer swarmfs1.Stop()
   446  
   447  	// Create a new file inside a existing dir and check
   448  	dirToCreate := filepath.Join(testMountDir, "one")
   449  	actualPath := filepath.Join(dirToCreate, "2.txt")
   450  	d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665))
   451  	if err1 != nil {
   452  		t.Fatalf("Could not create file %s : %v", actualPath, err1)
   453  	}
   454  	contents := make([]byte, 11)
   455  	rand.Read(contents)
   456  	d.Write(contents)
   457  	d.Close()
   458  
   459  	mi, err2 := swarmfs1.Unmount(testMountDir)
   460  	if err2 != nil {
   461  		t.Fatalf("Could not unmount %v", err2)
   462  	}
   463  
   464  	// mount again and see if things are okay
   465  	files["one/2.txt"] = fileInfo{0700, 333, 444, contents}
   466  	mi.LatestManifestMu.RLock()
   467  	lm := mi.LatestManifest
   468  	mi.LatestManifestMu.RUnlock()
   469  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   470  	defer swarmfs2.Stop()
   471  
   472  	checkFile(t, testMountDir, "one/2.txt", contents)
   473  }
   474  
   475  func (ta *testAPI) createNewFileInsideNewDirectory(t *testing.T) {
   476  	files := make(map[string]fileInfo)
   477  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "createinsidenewdir-upload")
   478  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "createinsidenewdir-mount")
   479  
   480  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   481  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   482  
   483  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   484  	defer swarmfs1.Stop()
   485  
   486  	// Create a new file inside a existing dir and check
   487  	dirToCreate := filepath.Join(testMountDir, "one")
   488  	os.MkdirAll(dirToCreate, 0777)
   489  	actualPath := filepath.Join(dirToCreate, "2.txt")
   490  	d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665))
   491  	if err1 != nil {
   492  		t.Fatalf("Could not create file %s : %v", actualPath, err1)
   493  	}
   494  	contents := make([]byte, 11)
   495  	rand.Read(contents)
   496  	d.Write(contents)
   497  	d.Close()
   498  
   499  	mi, err2 := swarmfs1.Unmount(testMountDir)
   500  	if err2 != nil {
   501  		t.Fatalf("Could not unmount %v", err2)
   502  	}
   503  
   504  	// mount again and see if things are okay
   505  	files["one/2.txt"] = fileInfo{0700, 333, 444, contents}
   506  	mi.LatestManifestMu.RLock()
   507  	lm := mi.LatestManifest
   508  	mi.LatestManifestMu.RUnlock()
   509  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   510  	defer swarmfs2.Stop()
   511  
   512  	checkFile(t, testMountDir, "one/2.txt", contents)
   513  }
   514  
   515  func (ta *testAPI) removeExistingFile(t *testing.T) {
   516  	files := make(map[string]fileInfo)
   517  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "remove-upload")
   518  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "remove-mount")
   519  
   520  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   521  	files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   522  	files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   523  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   524  
   525  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   526  	defer swarmfs1.Stop()
   527  
   528  	// Remove a file in the root dir and check
   529  	actualPath := filepath.Join(testMountDir, "five.txt")
   530  	os.Remove(actualPath)
   531  
   532  	mi, err2 := swarmfs1.Unmount(testMountDir)
   533  	if err2 != nil {
   534  		t.Fatalf("Could not unmount %v", err2)
   535  	}
   536  
   537  	// mount again and see if things are okay
   538  	delete(files, "five.txt")
   539  	mi.LatestManifestMu.RLock()
   540  	lm := mi.LatestManifest
   541  	mi.LatestManifestMu.RUnlock()
   542  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   543  	defer swarmfs2.Stop()
   544  }
   545  
   546  func (ta *testAPI) removeExistingFileInsideDir(t *testing.T) {
   547  	files := make(map[string]fileInfo)
   548  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "remove-upload")
   549  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "remove-mount")
   550  
   551  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   552  	files["one/five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   553  	files["one/six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   554  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   555  
   556  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   557  	defer swarmfs1.Stop()
   558  
   559  	// Remove a file in the root dir and check
   560  	actualPath := filepath.Join(testMountDir, "one/five.txt")
   561  	os.Remove(actualPath)
   562  
   563  	mi, err2 := swarmfs1.Unmount(testMountDir)
   564  	if err2 != nil {
   565  		t.Fatalf("Could not unmount %v", err2)
   566  	}
   567  
   568  	// mount again and see if things are okay
   569  	delete(files, "one/five.txt")
   570  	mi.LatestManifestMu.RLock()
   571  	lm := mi.LatestManifest
   572  	mi.LatestManifestMu.RUnlock()
   573  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   574  	defer swarmfs2.Stop()
   575  }
   576  
   577  func (ta *testAPI) removeNewlyAddedFile(t *testing.T) {
   578  
   579  	files := make(map[string]fileInfo)
   580  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "removenew-upload")
   581  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "removenew-mount")
   582  
   583  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   584  	files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   585  	files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   586  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   587  
   588  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   589  	defer swarmfs1.Stop()
   590  
   591  	// Adda a new file and remove it
   592  	dirToCreate := filepath.Join(testMountDir, "one")
   593  	os.MkdirAll(dirToCreate, os.FileMode(0665))
   594  	actualPath := filepath.Join(dirToCreate, "2.txt")
   595  	d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665))
   596  	if err1 != nil {
   597  		t.Fatalf("Could not create file %s : %v", actualPath, err1)
   598  	}
   599  	contents := make([]byte, 11)
   600  	rand.Read(contents)
   601  	d.Write(contents)
   602  	d.Close()
   603  
   604  	checkFile(t, testMountDir, "one/2.txt", contents)
   605  
   606  	os.Remove(actualPath)
   607  
   608  	mi, err2 := swarmfs1.Unmount(testMountDir)
   609  	if err2 != nil {
   610  		t.Fatalf("Could not unmount %v", err2)
   611  	}
   612  
   613  	// mount again and see if things are okay
   614  	mi.LatestManifestMu.RLock()
   615  	lm := mi.LatestManifest
   616  	mi.LatestManifestMu.RUnlock()
   617  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   618  	defer swarmfs2.Stop()
   619  
   620  	if bzzHash != lm {
   621  		t.Fatalf("same contents different hash orig(%v): new(%v)", bzzHash, lm)
   622  	}
   623  }
   624  
   625  func (ta *testAPI) addNewFileAndModifyContents(t *testing.T) {
   626  	files := make(map[string]fileInfo)
   627  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "modifyfile-upload")
   628  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "modifyfile-mount")
   629  
   630  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   631  	files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   632  	files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   633  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   634  
   635  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   636  	defer swarmfs1.Stop()
   637  
   638  	// Create a new file in the root dir and check
   639  	actualPath := filepath.Join(testMountDir, "2.txt")
   640  	d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665))
   641  	if err1 != nil {
   642  		t.Fatalf("Could not create file %s : %v", actualPath, err1)
   643  	}
   644  	line1 := []byte("Line 1")
   645  	rand.Read(line1)
   646  	d.Write(line1)
   647  	d.Close()
   648  
   649  	mi1, err2 := swarmfs1.Unmount(testMountDir)
   650  	if err2 != nil {
   651  		t.Fatalf("Could not unmount %v", err2)
   652  	}
   653  
   654  	// mount again and see if things are okay
   655  	files["2.txt"] = fileInfo{0700, 333, 444, line1}
   656  	mi1.LatestManifestMu.RLock()
   657  	lm := mi1.LatestManifest
   658  	mi1.LatestManifestMu.RUnlock()
   659  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   660  	defer swarmfs2.Stop()
   661  
   662  	checkFile(t, testMountDir, "2.txt", line1)
   663  
   664  	mi2, err3 := swarmfs2.Unmount(testMountDir)
   665  	if err3 != nil {
   666  		t.Fatalf("Could not unmount %v", err3)
   667  	}
   668  
   669  	// mount again and modify
   670  	mi2.LatestManifestMu.RLock()
   671  	lm = mi2.LatestManifest
   672  	mi2.LatestManifestMu.RUnlock()
   673  	swarmfs3 := mountDir(t, ta.api, files, lm, testMountDir)
   674  	defer swarmfs3.Stop()
   675  
   676  	fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665))
   677  	if err4 != nil {
   678  		t.Fatalf("Could not create file %s : %v", actualPath, err4)
   679  	}
   680  	line2 := []byte("Line 2")
   681  	rand.Read(line2)
   682  	fd.Seek(int64(len(line1)), 0)
   683  	fd.Write(line2)
   684  	fd.Close()
   685  
   686  	mi3, err5 := swarmfs3.Unmount(testMountDir)
   687  	if err5 != nil {
   688  		t.Fatalf("Could not unmount %v", err5)
   689  	}
   690  
   691  	// mount again and see if things are okay
   692  	b := [][]byte{line1, line2}
   693  	line1and2 := bytes.Join(b, []byte(""))
   694  	files["2.txt"] = fileInfo{0700, 333, 444, line1and2}
   695  	mi3.LatestManifestMu.RLock()
   696  	lm = mi3.LatestManifest
   697  	mi3.LatestManifestMu.RUnlock()
   698  	swarmfs4 := mountDir(t, ta.api, files, lm, testMountDir)
   699  	defer swarmfs4.Stop()
   700  
   701  	checkFile(t, testMountDir, "2.txt", line1and2)
   702  }
   703  
   704  func (ta *testAPI) removeEmptyDir(t *testing.T) {
   705  	files := make(map[string]fileInfo)
   706  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-upload")
   707  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-mount")
   708  
   709  	files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   710  	files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   711  	files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   712  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   713  
   714  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   715  	defer swarmfs1.Stop()
   716  
   717  	os.MkdirAll(filepath.Join(testMountDir, "newdir"), 0777)
   718  
   719  	mi, err3 := swarmfs1.Unmount(testMountDir)
   720  	if err3 != nil {
   721  		t.Fatalf("Could not unmount %v", err3)
   722  	}
   723  	mi.LatestManifestMu.RLock()
   724  	lm := mi.LatestManifest
   725  	mi.LatestManifestMu.RUnlock()
   726  	if bzzHash != lm {
   727  		t.Fatalf("same contents different hash orig(%v): new(%v)", bzzHash, lm)
   728  	}
   729  }
   730  
   731  func (ta *testAPI) removeDirWhichHasFiles(t *testing.T) {
   732  	files := make(map[string]fileInfo)
   733  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-upload")
   734  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-mount")
   735  
   736  	files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   737  	files["two/five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   738  	files["two/six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   739  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   740  
   741  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   742  	defer swarmfs1.Stop()
   743  
   744  	dirPath := filepath.Join(testMountDir, "two")
   745  	os.RemoveAll(dirPath)
   746  
   747  	mi, err2 := swarmfs1.Unmount(testMountDir)
   748  	if err2 != nil {
   749  		t.Fatalf("Could not unmount %v ", err2)
   750  	}
   751  
   752  	// mount again and see if things are okay
   753  	delete(files, "two/five.txt")
   754  	delete(files, "two/six.txt")
   755  
   756  	mi.LatestManifestMu.RLock()
   757  	lm := mi.LatestManifest
   758  	mi.LatestManifestMu.RUnlock()
   759  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   760  	defer swarmfs2.Stop()
   761  }
   762  
   763  func (ta *testAPI) removeDirWhichHasSubDirs(t *testing.T) {
   764  	files := make(map[string]fileInfo)
   765  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmsubdir-upload")
   766  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmsubdir-mount")
   767  
   768  	files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   769  	files["two/three/2.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   770  	files["two/three/3.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   771  	files["two/four/5.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   772  	files["two/four/6.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   773  	files["two/four/six/7.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)}
   774  
   775  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   776  
   777  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   778  	defer swarmfs1.Stop()
   779  
   780  	dirPath := filepath.Join(testMountDir, "two")
   781  	os.RemoveAll(dirPath)
   782  
   783  	mi, err2 := swarmfs1.Unmount(testMountDir)
   784  	if err2 != nil {
   785  		t.Fatalf("Could not unmount %v ", err2)
   786  	}
   787  
   788  	// mount again and see if things are okay
   789  	delete(files, "two/three/2.txt")
   790  	delete(files, "two/three/3.txt")
   791  	delete(files, "two/four/5.txt")
   792  	delete(files, "two/four/6.txt")
   793  	delete(files, "two/four/six/7.txt")
   794  
   795  	mi.LatestManifestMu.RLock()
   796  	lm := mi.LatestManifest
   797  	mi.LatestManifestMu.RUnlock()
   798  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   799  	defer swarmfs2.Stop()
   800  }
   801  
   802  func (ta *testAPI) appendFileContentsToEnd(t *testing.T) {
   803  	files := make(map[string]fileInfo)
   804  	testUploadDir, _ := ioutil.TempDir(os.TempDir(), "appendlargefile-upload")
   805  	testMountDir, _ := ioutil.TempDir(os.TempDir(), "appendlargefile-mount")
   806  
   807  	line1 := make([]byte, 10)
   808  	rand.Read(line1)
   809  	files["1.txt"] = fileInfo{0700, 333, 444, line1}
   810  	bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir)
   811  
   812  	swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir)
   813  	defer swarmfs1.Stop()
   814  
   815  	actualPath := filepath.Join(testMountDir, "1.txt")
   816  	fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665))
   817  	if err4 != nil {
   818  		t.Fatalf("Could not create file %s : %v", actualPath, err4)
   819  	}
   820  	line2 := make([]byte, 5)
   821  	rand.Read(line2)
   822  	fd.Seek(int64(len(line1)), 0)
   823  	fd.Write(line2)
   824  	fd.Close()
   825  
   826  	mi1, err5 := swarmfs1.Unmount(testMountDir)
   827  	if err5 != nil {
   828  		t.Fatalf("Could not unmount %v ", err5)
   829  	}
   830  
   831  	// mount again and see if things are okay
   832  	b := [][]byte{line1, line2}
   833  	line1and2 := bytes.Join(b, []byte(""))
   834  	files["1.txt"] = fileInfo{0700, 333, 444, line1and2}
   835  	mi1.LatestManifestMu.RLock()
   836  	lm := mi1.LatestManifest
   837  	mi1.LatestManifestMu.RUnlock()
   838  	swarmfs2 := mountDir(t, ta.api, files, lm, testMountDir)
   839  	defer swarmfs2.Stop()
   840  
   841  	checkFile(t, testMountDir, "1.txt", line1and2)
   842  }
   843  
   844  func TestFUSE(t *testing.T) {
   845  	datadir, err := ioutil.TempDir("", "fuse")
   846  	if err != nil {
   847  		t.Fatalf("unable to create temp dir: %v", err)
   848  	}
   849  	os.RemoveAll(datadir)
   850  
   851  	dpa, err := storage.NewLocalDPA(datadir)
   852  	if err != nil {
   853  		t.Fatal(err)
   854  	}
   855  	ta := &testAPI{api: api.NewApi(dpa, nil)}
   856  	dpa.Start()
   857  	defer dpa.Stop()
   858  
   859  	t.Run("mountListAndUmount", ta.mountListAndUnmount)
   860  	t.Run("maxMounts", ta.maxMounts)
   861  	t.Run("remount", ta.remount)
   862  	t.Run("unmount", ta.unmount)
   863  	t.Run("unmountWhenResourceBusy", ta.unmountWhenResourceBusy)
   864  	t.Run("seekInMultiChunkFile", ta.seekInMultiChunkFile)
   865  	t.Run("createNewFile", ta.createNewFile)
   866  	t.Run("createNewFileInsideDirectory", ta.createNewFileInsideDirectory)
   867  	t.Run("createNewFileInsideNewDirectory", ta.createNewFileInsideNewDirectory)
   868  	t.Run("removeExistingFile", ta.removeExistingFile)
   869  	t.Run("removeExistingFileInsideDir", ta.removeExistingFileInsideDir)
   870  	t.Run("removeNewlyAddedFile", ta.removeNewlyAddedFile)
   871  	t.Run("addNewFileAndModifyContents", ta.addNewFileAndModifyContents)
   872  	t.Run("removeEmptyDir", ta.removeEmptyDir)
   873  	t.Run("removeDirWhichHasFiles", ta.removeDirWhichHasFiles)
   874  	t.Run("removeDirWhichHasSubDirs", ta.removeDirWhichHasSubDirs)
   875  	t.Run("appendFileContentsToEnd", ta.appendFileContentsToEnd)
   876  }