github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/swarm/fuse/swarmfs_test.go (about)

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