gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/filesystem/filesystem_test.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"sort"
    12  	"strings"
    13  	"sync"
    14  	"sync/atomic"
    15  	"testing"
    16  	"time"
    17  
    18  	"gitlab.com/NebulousLabs/errors"
    19  	"gitlab.com/NebulousLabs/fastrand"
    20  	"gitlab.com/NebulousLabs/writeaheadlog"
    21  	skydPersist "gitlab.com/SkynetLabs/skyd/persist"
    22  	"gitlab.com/SkynetLabs/skyd/skymodules"
    23  	"gitlab.com/SkynetLabs/skyd/skymodules/renter/filesystem/siadir"
    24  	"gitlab.com/SkynetLabs/skyd/skymodules/renter/filesystem/siafile"
    25  	"go.sia.tech/siad/crypto"
    26  	"go.sia.tech/siad/persist"
    27  
    28  	"gitlab.com/SkynetLabs/skyd/build"
    29  )
    30  
    31  // CachedListCollect calls CachedList but collects the returned infos into
    32  // slices which are then sorted by siapath. This should only be used in testing
    33  // since it might result in a large memory allocation.
    34  func (fs *FileSystem) CachedListCollect(siaPath skymodules.SiaPath, recursive bool) (fis []skymodules.FileInfo, dis []skymodules.DirectoryInfo, err error) {
    35  	var fmu, dmu sync.Mutex
    36  	flf := func(fi skymodules.FileInfo) {
    37  		fmu.Lock()
    38  		fis = append(fis, fi)
    39  		fmu.Unlock()
    40  	}
    41  	dlf := func(di skymodules.DirectoryInfo) {
    42  		dmu.Lock()
    43  		dis = append(dis, di)
    44  		dmu.Unlock()
    45  	}
    46  	err = fs.CachedList(siaPath, recursive, flf, dlf)
    47  
    48  	// Sort slices by SiaPath.
    49  	sort.Slice(dis, func(i, j int) bool {
    50  		return dis[i].SiaPath.String() < dis[j].SiaPath.String()
    51  	})
    52  	sort.Slice(fis, func(i, j int) bool {
    53  		return fis[i].SiaPath.String() < fis[j].SiaPath.String()
    54  	})
    55  	return
    56  }
    57  
    58  // newTestFileSystemWithFile creates a new FileSystem and SiaFile and makes sure
    59  // that they are linked
    60  func newTestFileSystemWithFile(name string) (*FileNode, *FileSystem, error) {
    61  	dir := testDir(name)
    62  	fs := newTestFileSystem(dir)
    63  	sp := skymodules.RandomSiaPath()
    64  	fs.addTestSiaFile(sp)
    65  	sf, err := fs.OpenSiaFile(sp)
    66  	return sf, fs, err
    67  }
    68  
    69  // newTestFileSystemWithDir creates a new FileSystem and SiaDir and makes sure
    70  // that they are linked
    71  func newTestFileSystemWithDir(name string) (*DirNode, *FileSystem, error) {
    72  	dir := testDir(name)
    73  	fs := newTestFileSystem(dir)
    74  	sp := skymodules.RandomSiaPath()
    75  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); err != nil {
    76  		panic(err) // Reflect behavior of newTestFileSystemWithFile.
    77  	}
    78  	sd, err := fs.OpenSiaDir(sp)
    79  	return sd, fs, err
    80  }
    81  
    82  // testDir creates a testing directory for a filesystem test.
    83  func testDir(name string) string {
    84  	dir := build.TempDir(name, filepath.Join("filesystem"))
    85  	if err := os.MkdirAll(dir, persist.DefaultDiskPermissionsTest); err != nil {
    86  		panic(err)
    87  	}
    88  	return dir
    89  }
    90  
    91  // newSiaPath creates a new siapath from the specified string.
    92  func newSiaPath(path string) skymodules.SiaPath {
    93  	sp, err := skymodules.NewSiaPath(path)
    94  	if err != nil {
    95  		panic(err)
    96  	}
    97  	return sp
    98  }
    99  
   100  // newTestFileSystem creates a new filesystem for testing.
   101  func newTestFileSystem(root string) *FileSystem {
   102  	wal, _ := newTestWAL()
   103  	logger, err := skydPersist.NewLogger(ioutil.Discard)
   104  	if err != nil {
   105  		panic(err.Error())
   106  	}
   107  	fs, err := New(root, logger, wal)
   108  	if err != nil {
   109  		panic(err.Error())
   110  	}
   111  	return fs
   112  }
   113  
   114  // newTestWal is a helper method to create a WAL for testing.
   115  func newTestWAL() (*writeaheadlog.WAL, string) {
   116  	// Create the wal.
   117  	walsDir := filepath.Join(os.TempDir(), "wals")
   118  	if err := os.MkdirAll(walsDir, 0700); err != nil {
   119  		panic(err)
   120  	}
   121  	walFilePath := filepath.Join(walsDir, hex.EncodeToString(fastrand.Bytes(8)))
   122  	_, wal, err := writeaheadlog.New(walFilePath)
   123  	if err != nil {
   124  		panic(err)
   125  	}
   126  	return wal, walFilePath
   127  }
   128  
   129  // addTestSiaFile is a convenience method to add a SiaFile for testing to a
   130  // FileSystem.
   131  func (fs *FileSystem) addTestSiaFile(siaPath skymodules.SiaPath) {
   132  	if err := fs.addTestSiaFileWithErr(siaPath); err != nil {
   133  		panic(err)
   134  	}
   135  }
   136  
   137  // addTestSiaFileWithErr is a convenience method to add a SiaFile for testing to
   138  // a FileSystem.
   139  func (fs *FileSystem) addTestSiaFileWithErr(siaPath skymodules.SiaPath) error {
   140  	ec, err := skymodules.NewRSSubCode(10, 20, crypto.SegmentSize)
   141  	if err != nil {
   142  		return err
   143  	}
   144  	err = fs.NewSiaFile(siaPath, "", ec, crypto.GenerateSiaKey(crypto.TypeDefaultRenter), uint64(fastrand.Intn(100)), persist.DefaultDiskPermissionsTest)
   145  	if err != nil {
   146  		return err
   147  	}
   148  	return nil
   149  }
   150  
   151  // TestNew tests creating a new FileSystem.
   152  func TestNew(t *testing.T) {
   153  	if testing.Short() && !build.VLONG {
   154  		t.SkipNow()
   155  	}
   156  	t.Parallel()
   157  	// Create filesystem.
   158  	root := filepath.Join(testDir(t.Name()), "fs-root")
   159  	fs := newTestFileSystem(root)
   160  	// Check fields.
   161  	if fs.parent != nil {
   162  		t.Fatalf("fs.parent shoud be 'nil' but wasn't")
   163  	}
   164  	if *fs.name != "" {
   165  		t.Fatalf("fs.staticName should be %v but was %v", "", *fs.name)
   166  	}
   167  	if *fs.path != root {
   168  		t.Fatalf("fs.path should be %v but was %v", root, *fs.path)
   169  	}
   170  	if fs.threads == nil || len(fs.threads) != 0 {
   171  		t.Fatal("fs.threads is not an empty initialized map")
   172  	}
   173  	if fs.threadUID != 0 {
   174  		t.Fatalf("fs.threadUID should be 0 but was %v", fs.threadUID)
   175  	}
   176  	if fs.directories == nil || len(fs.directories) != 0 {
   177  		t.Fatal("fs.directories is not an empty initialized map")
   178  	}
   179  	if fs.files == nil || len(fs.files) != 0 {
   180  		t.Fatal("fs.files is not an empty initialized map")
   181  	}
   182  	// Create the filesystem again at the same location.
   183  	_ = newTestFileSystem(*fs.path)
   184  }
   185  
   186  // TestNewSiaDir tests if creating a new directory using NewSiaDir creates the
   187  // correct folder structure.
   188  func TestNewSiaDir(t *testing.T) {
   189  	if testing.Short() && !build.VLONG {
   190  		t.SkipNow()
   191  	}
   192  	t.Parallel()
   193  	// Create filesystem.
   194  	root := filepath.Join(testDir(t.Name()), "fs-root")
   195  	fs := newTestFileSystem(root)
   196  	// Create dir /sub/foo
   197  	sp := newSiaPath("sub/foo")
   198  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	// The whole path should exist.
   202  	if _, err := os.Stat(filepath.Join(root, sp.String())); err != nil {
   203  		t.Fatal(err)
   204  	}
   205  }
   206  
   207  // TestNewSiaFile tests if creating a new file using NewSiaFiles creates the
   208  // correct folder structure and file.
   209  func TestNewSiaFile(t *testing.T) {
   210  	if testing.Short() && !build.VLONG {
   211  		t.SkipNow()
   212  	}
   213  	t.Parallel()
   214  	// Create filesystem.
   215  	root := filepath.Join(testDir(t.Name()), "fs-root")
   216  	fs := newTestFileSystem(root)
   217  	// Create file /sub/foo/file
   218  	sp := newSiaPath("sub/foo/file")
   219  	fs.addTestSiaFile(sp)
   220  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); !errors.Contains(err, ErrExists) {
   221  		t.Fatal("err should be ErrExists but was", err)
   222  	}
   223  	if _, err := os.Stat(filepath.Join(root, sp.String())); !os.IsNotExist(err) {
   224  		t.Fatal("there should be no dir on disk")
   225  	}
   226  	if _, err := os.Stat(filepath.Join(root, sp.String()+skymodules.SiaFileExtension)); err != nil {
   227  		t.Fatal(err)
   228  	}
   229  	// Create a file in the root dir.
   230  	sp = newSiaPath("file")
   231  	fs.addTestSiaFile(sp)
   232  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); !errors.Contains(err, ErrExists) {
   233  		t.Fatal("err should be ErrExists but was", err)
   234  	}
   235  	if _, err := os.Stat(filepath.Join(root, sp.String())); !os.IsNotExist(err) {
   236  		t.Fatal("there should be no dir on disk")
   237  	}
   238  	if _, err := os.Stat(filepath.Join(root, sp.String()+skymodules.SiaFileExtension)); err != nil {
   239  		t.Fatal(err)
   240  	}
   241  }
   242  
   243  func (d *DirNode) checkNode(numThreads, numDirs, numFiles int) error {
   244  	if len(d.threads) != numThreads {
   245  		return fmt.Errorf("Expected d.threads to have length %v but was %v", numThreads, len(d.threads))
   246  	}
   247  	if len(d.directories) != numDirs {
   248  		return fmt.Errorf("Expected %v subdirectories in the root but got %v", numDirs, len(d.directories))
   249  	}
   250  	if len(d.files) != numFiles {
   251  		return fmt.Errorf("Expected %v files in the root but got %v", numFiles, len(d.files))
   252  	}
   253  	return nil
   254  }
   255  
   256  // TestOpenSiaDir confirms that a previoiusly created SiaDir can be opened and
   257  // that the filesystem tree is extended accordingly in the process.
   258  func TestOpenSiaDir(t *testing.T) {
   259  	if testing.Short() && !build.VLONG {
   260  		t.SkipNow()
   261  	}
   262  	t.Parallel()
   263  	// Create filesystem.
   264  	root := filepath.Join(testDir(t.Name()), "fs-root")
   265  	fs := newTestFileSystem(root)
   266  	// Create dir /foo
   267  	sp := newSiaPath("foo")
   268  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); err != nil {
   269  		t.Fatal(err)
   270  	}
   271  	// Open the newly created dir.
   272  	foo, err := fs.OpenSiaDir(sp)
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  	defer func() {
   277  		if err := foo.Close(); err != nil {
   278  			t.Fatal(err)
   279  		}
   280  	}()
   281  	// Create dir /sub/foo. This time don't use NewSiaDir but OpenSiaDir with
   282  	// the create flag set to `true`.
   283  	sp = newSiaPath("sub/foo")
   284  	sd, err := fs.OpenSiaDirCustom(sp, true)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  	defer func() {
   289  		if err := sd.Close(); err != nil {
   290  			t.Fatal(err)
   291  		}
   292  	}()
   293  	// Confirm the integrity of the root node.
   294  	if err := fs.checkNode(0, 2, 0); err != nil {
   295  		t.Fatal(err)
   296  	}
   297  	// Open the root node manually and confirm that they are the same.
   298  	rootSD, err := fs.OpenSiaDir(skymodules.RootSiaPath())
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  	if err := fs.checkNode(len(rootSD.threads), len(rootSD.directories), len(rootSD.files)); err != nil {
   303  		t.Fatal(err)
   304  	}
   305  	// Confirm the integrity of the /sub node.
   306  	subNode, exists := fs.directories["sub"]
   307  	if !exists {
   308  		t.Fatal("expected root to contain the 'sub' node")
   309  	}
   310  	if *subNode.name != "sub" {
   311  		t.Fatalf("subNode name should be 'sub' but was %v", *subNode.name)
   312  	}
   313  	if path := filepath.Join(*subNode.parent.path, *subNode.name); path != *subNode.path {
   314  		t.Fatalf("subNode path should be %v but was %v", path, *subNode.path)
   315  	}
   316  	if err := subNode.checkNode(0, 1, 0); err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	// Confirm the integrity of the /sub/foo node.
   320  	fooNode, exists := subNode.directories["foo"]
   321  	if !exists {
   322  		t.Fatal("expected /sub to contain /sub/foo")
   323  	}
   324  	if *fooNode.name != "foo" {
   325  		t.Fatalf("fooNode name should be 'foo' but was %v", *fooNode.name)
   326  	}
   327  	if path := filepath.Join(*fooNode.parent.path, *fooNode.name); path != *fooNode.path {
   328  		t.Fatalf("fooNode path should be %v but was %v", path, *fooNode.path)
   329  	}
   330  	if err := fooNode.checkNode(1, 0, 0); err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	// Open the newly created dir again.
   334  	sd2, err := fs.OpenSiaDir(sp)
   335  	if err != nil {
   336  		t.Fatal(err)
   337  	}
   338  	defer func() {
   339  		if err := sd2.Close(); err != nil {
   340  			t.Fatal(err)
   341  		}
   342  	}()
   343  	// They should have different UIDs.
   344  	if sd.threadUID == 0 {
   345  		t.Fatal("threaduid shouldn't be 0")
   346  	}
   347  	if sd2.threadUID == 0 {
   348  		t.Fatal("threaduid shouldn't be 0")
   349  	}
   350  	if sd.threadUID == sd2.threadUID {
   351  		t.Fatal("sd and sd2 should have different threaduids")
   352  	}
   353  	if len(sd.threads) != 2 || len(sd2.threads) != 2 {
   354  		t.Fatal("sd and sd2 should both have 2 threads registered")
   355  	}
   356  	_, exists1 := sd.threads[sd.threadUID]
   357  	_, exists2 := sd.threads[sd2.threadUID]
   358  	_, exists3 := sd2.threads[sd.threadUID]
   359  	_, exists4 := sd2.threads[sd2.threadUID]
   360  	if exists := exists1 && exists2 && exists3 && exists4; !exists {
   361  		t.Fatal("sd and sd1's threads don't contain the right uids")
   362  	}
   363  	// Open /sub manually and make sure that subDir and sdSub are consistent.
   364  	sdSub, err := fs.OpenSiaDir(newSiaPath("sub"))
   365  	if err != nil {
   366  		t.Fatal(err)
   367  	}
   368  	defer func() {
   369  		if err := sdSub.Close(); err != nil {
   370  			t.Fatal(err)
   371  		}
   372  	}()
   373  	if err := subNode.checkNode(1, 1, 0); err != nil {
   374  		t.Fatal(err)
   375  	}
   376  	if err := sdSub.checkNode(1, 1, 0); err != nil {
   377  		t.Fatal(err)
   378  	}
   379  }
   380  
   381  // TestOpenSiaFile confirms that a previously created SiaFile can be opened and
   382  // that the filesystem tree is extended accordingly in the process.
   383  func TestOpenSiaFile(t *testing.T) {
   384  	if testing.Short() && !build.VLONG {
   385  		t.SkipNow()
   386  	}
   387  	t.Parallel()
   388  	// Create filesystem.
   389  	root := filepath.Join(testDir(t.Name()), "fs-root")
   390  	fs := newTestFileSystem(root)
   391  	// Create file /file
   392  	sp := newSiaPath("file")
   393  	fs.addTestSiaFile(sp)
   394  	// Open the newly created file.
   395  	sf, err := fs.OpenSiaFile(sp)
   396  	if err != nil {
   397  		t.Fatal(err)
   398  	}
   399  	defer func() {
   400  		if err := sf.Close(); err != nil {
   401  			t.Fatal(err)
   402  		}
   403  	}()
   404  	// Confirm the integrity of the file.
   405  	if *sf.name != "file" {
   406  		t.Fatalf("name of file should be file but was %v", *sf.name)
   407  	}
   408  	if *sf.path != filepath.Join(root, (*sf.name)+skymodules.SiaFileExtension) {
   409  		t.Fatal("file has wrong path", *sf.path)
   410  	}
   411  	if sf.parent != &fs.DirNode {
   412  		t.Fatalf("parent of file should be %v but was %v", &fs.node, sf.parent)
   413  	}
   414  	if sf.threadUID == 0 {
   415  		t.Fatal("threaduid wasn't set")
   416  	}
   417  	if len(sf.threads) != 1 {
   418  		t.Fatalf("len(threads) should be 1 but was %v", len(sf.threads))
   419  	}
   420  	if _, exists := sf.threads[sf.threadUID]; !exists {
   421  		t.Fatal("threaduid doesn't exist in threads map")
   422  	}
   423  	// Confirm the integrity of the root node.
   424  	if len(fs.threads) != 0 {
   425  		t.Fatalf("Expected fs.threads to have length 0 but was %v", len(fs.threads))
   426  	}
   427  	if len(fs.directories) != 0 {
   428  		t.Fatalf("Expected 0 subdirectories in the root but got %v", len(fs.directories))
   429  	}
   430  	if len(fs.files) != 1 {
   431  		t.Fatalf("Expected 1 file in the root but got %v", len(fs.files))
   432  	}
   433  	// Create file /sub/file
   434  	sp = newSiaPath("/sub1/sub2/file")
   435  	fs.addTestSiaFile(sp)
   436  	// Open the newly created file.
   437  	sf2, err := fs.OpenSiaFile(sp)
   438  	if err != nil {
   439  		t.Fatal(err)
   440  	}
   441  	defer func() {
   442  		if err := sf2.Close(); err != nil {
   443  			t.Fatal(err)
   444  		}
   445  	}()
   446  	// Confirm the integrity of the file.
   447  	if *sf2.name != "file" {
   448  		t.Fatalf("name of file should be file but was %v", *sf2.name)
   449  	}
   450  	if *sf2.parent.name != "sub2" {
   451  		t.Fatalf("parent of file should be %v but was %v", "sub", *sf2.parent.name)
   452  	}
   453  	if sf2.threadUID == 0 {
   454  		t.Fatal("threaduid wasn't set")
   455  	}
   456  	if len(sf2.threads) != 1 {
   457  		t.Fatalf("len(threads) should be 1 but was %v", len(sf2.threads))
   458  	}
   459  	// Confirm the integrity of the "sub2" folder.
   460  	sub2 := sf2.parent
   461  	if err := sub2.checkNode(0, 0, 1); err != nil {
   462  		t.Fatal(err)
   463  	}
   464  	if _, exists := sf2.threads[sf2.threadUID]; !exists {
   465  		t.Fatal("threaduid doesn't exist in threads map")
   466  	}
   467  	// Confirm the integrity of the "sub1" folder.
   468  	sub1 := sub2.parent
   469  	if err := sub1.checkNode(0, 1, 0); err != nil {
   470  		t.Fatal(err)
   471  	}
   472  	if _, exists := sf2.threads[sf2.threadUID]; !exists {
   473  		t.Fatal("threaduid doesn't exist in threads map")
   474  	}
   475  }
   476  
   477  // TestCloseSiaDir tests that closing an opened directory shrinks the tree
   478  // accordingly.
   479  func TestCloseSiaDir(t *testing.T) {
   480  	if testing.Short() && !build.VLONG {
   481  		t.SkipNow()
   482  	}
   483  	t.Parallel()
   484  	// Create filesystem.
   485  	root := filepath.Join(testDir(t.Name()), "fs-root")
   486  	fs := newTestFileSystem(root)
   487  	// Create dir /sub/foo
   488  	sp := newSiaPath("sub1/foo")
   489  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); err != nil {
   490  		t.Fatal(err)
   491  	}
   492  	// Open the newly created dir.
   493  	sd, err := fs.OpenSiaDir(sp)
   494  	if err != nil {
   495  		t.Fatal(err)
   496  	}
   497  	if len(sd.threads) != 1 {
   498  		t.Fatalf("There should be 1 thread in sd.threads but got %v", len(sd.threads))
   499  	}
   500  	if len(sd.parent.threads) != 0 {
   501  		t.Fatalf("The parent shouldn't have any threads but had %v", len(sd.parent.threads))
   502  	}
   503  	if len(fs.directories) != 1 {
   504  		t.Fatalf("There should be 1 directory in fs.directories but got %v", len(fs.directories))
   505  	}
   506  	if len(sd.parent.directories) != 1 {
   507  		t.Fatalf("The parent should have 1 directory but got %v", len(sd.parent.directories))
   508  	}
   509  	// After closing it the thread should be gone.
   510  	sd.Close()
   511  	if err := fs.checkNode(0, 0, 0); err != nil {
   512  		t.Fatal(err)
   513  	}
   514  	// Open the dir again. This time twice.
   515  	sd1, err := fs.OpenSiaDir(sp)
   516  	if err != nil {
   517  		t.Fatal(err)
   518  	}
   519  	sd2, err := fs.OpenSiaDirCustom(sp, true)
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  	if len(sd1.threads) != 2 || len(sd2.threads) != 2 {
   524  		t.Fatalf("There should be 2 threads in sd.threads but got %v", len(sd1.threads))
   525  	}
   526  	if len(fs.directories) != 1 {
   527  		t.Fatalf("There should be 1 directory in fs.directories but got %v", len(fs.directories))
   528  	}
   529  	if len(sd1.parent.directories) != 1 || len(sd2.parent.directories) != 1 {
   530  		t.Fatalf("The parent should have 1 directory but got %v", len(sd.parent.directories))
   531  	}
   532  	// Close one instance.
   533  	sd1.Close()
   534  	if len(sd1.threads) != 1 || len(sd2.threads) != 1 {
   535  		t.Fatalf("There should be 1 thread in sd.threads but got %v", len(sd1.threads))
   536  	}
   537  	if len(fs.directories) != 1 {
   538  		t.Fatalf("There should be 1 directory in fs.directories but got %v", len(fs.directories))
   539  	}
   540  	if len(sd1.parent.directories) != 1 || len(sd2.parent.directories) != 1 {
   541  		t.Fatalf("The parent should have 1 directory but got %v", len(sd.parent.directories))
   542  	}
   543  	// Close the second one.
   544  	if err := sd2.Close(); err != nil {
   545  		t.Fatal(err)
   546  	}
   547  	if len(fs.threads) != 0 {
   548  		t.Fatalf("There should be 0 threads in fs.threads but got %v", len(fs.threads))
   549  	}
   550  	if len(sd1.threads) != 0 || len(sd2.threads) != 0 {
   551  		t.Fatalf("There should be 0 threads in sd.threads but got %v", len(sd1.threads))
   552  	}
   553  	if len(fs.directories) != 0 {
   554  		t.Fatalf("There should be 0 directories in fs.directories but got %v", len(fs.directories))
   555  	}
   556  }
   557  
   558  // TestCloseSiaFile tests that closing an opened file shrinks the tree
   559  // accordingly.
   560  func TestCloseSiaFile(t *testing.T) {
   561  	if testing.Short() && !build.VLONG {
   562  		t.SkipNow()
   563  	}
   564  	t.Parallel()
   565  	// Create filesystem.
   566  	root := filepath.Join(testDir(t.Name()), "fs-root")
   567  	fs := newTestFileSystem(root)
   568  	// Create file /sub/file
   569  	sp := newSiaPath("sub/file")
   570  	fs.addTestSiaFile(sp)
   571  	// Open the newly created file.
   572  	sf, err := fs.OpenSiaFile(sp)
   573  	if err != nil {
   574  		t.Fatal(err)
   575  	}
   576  	if len(sf.threads) != 1 {
   577  		t.Fatalf("There should be 1 thread in sf.threads but got %v", len(sf.threads))
   578  	}
   579  	if len(sf.parent.threads) != 0 {
   580  		t.Fatalf("The parent shouldn't have any threads but had %v", len(sf.parent.threads))
   581  	}
   582  	if len(fs.directories) != 1 {
   583  		t.Fatalf("There should be 1 directory in fs.directories but got %v", len(fs.directories))
   584  	}
   585  	if len(sf.parent.files) != 1 {
   586  		t.Fatalf("The parent should have 1 file but got %v", len(sf.parent.files))
   587  	}
   588  	// After closing it the thread should be gone.
   589  	sf.Close()
   590  	if len(fs.threads) != 0 {
   591  		t.Fatalf("There should be 0 threads in fs.threads but got %v", len(fs.threads))
   592  	}
   593  	if len(sf.threads) != 0 {
   594  		t.Fatalf("There should be 0 threads in sd.threads but got %v", len(sf.threads))
   595  	}
   596  	if len(fs.files) != 0 {
   597  		t.Fatalf("There should be 0 files in fs.files but got %v", len(fs.files))
   598  	}
   599  	// Open the file again. This time twice.
   600  	sf1, err := fs.OpenSiaFile(sp)
   601  	if err != nil {
   602  		t.Fatal(err)
   603  	}
   604  	sf2, err := fs.OpenSiaFile(sp)
   605  	if err != nil {
   606  		t.Fatal(err)
   607  	}
   608  	if len(sf1.threads) != 2 || len(sf2.threads) != 2 {
   609  		t.Fatalf("There should be 2 threads in sf1.threads but got %v", len(sf1.threads))
   610  	}
   611  	if len(fs.directories) != 1 {
   612  		t.Fatalf("There should be 1 directory in fs.directories but got %v", len(fs.directories))
   613  	}
   614  	if len(sf1.parent.files) != 1 || len(sf2.parent.files) != 1 {
   615  		t.Fatalf("The parent should have 1 file but got %v", len(sf1.parent.files))
   616  	}
   617  	// Close one instance.
   618  	sf1.Close()
   619  	if len(sf1.threads) != 1 || len(sf2.threads) != 1 {
   620  		t.Fatalf("There should be 1 thread in sf1.threads but got %v", len(sf1.threads))
   621  	}
   622  	if len(fs.directories) != 1 {
   623  		t.Fatalf("There should be 1 dir in fs.directories but got %v", len(fs.directories))
   624  	}
   625  	if len(sf1.parent.files) != 1 || len(sf2.parent.files) != 1 {
   626  		t.Fatalf("The parent should have 1 file but got %v", len(sf1.parent.files))
   627  	}
   628  	if len(sf1.parent.parent.directories) != 1 {
   629  		t.Fatalf("The root should have 1 directory but had %v", len(sf1.parent.parent.directories))
   630  	}
   631  	// Close the second one.
   632  	sf2.Close()
   633  	if len(fs.threads) != 0 {
   634  		t.Fatalf("There should be 0 threads in fs.threads but got %v", len(fs.threads))
   635  	}
   636  	if len(sf1.threads) != 0 || len(sf2.threads) != 0 {
   637  		t.Fatalf("There should be 0 threads in sd.threads but got %v", len(sf1.threads))
   638  	}
   639  	if len(fs.directories) != 0 {
   640  		t.Fatalf("There should be 0 directories in fs.directories but got %v", len(fs.directories))
   641  	}
   642  	if len(sf1.parent.files) != 0 || len(sf2.parent.files) != 0 {
   643  		t.Fatalf("The parent should have 0 files but got %v", len(sf1.parent.files))
   644  	}
   645  	if len(sf1.parent.parent.directories) != 0 {
   646  		t.Fatalf("The root should have 0 directories but had %v", len(sf1.parent.parent.directories))
   647  	}
   648  }
   649  
   650  // TestDeleteFile tests that deleting a file works as expected and that certain
   651  // edge cases are covered.
   652  func TestDeleteFile(t *testing.T) {
   653  	if testing.Short() && !build.VLONG {
   654  		t.SkipNow()
   655  	}
   656  	t.Parallel()
   657  	// Create filesystem.
   658  	root := filepath.Join(testDir(t.Name()), "fs-root")
   659  	fs := newTestFileSystem(root)
   660  	// Add a file to the root dir.
   661  	sp := newSiaPath("foo")
   662  	fs.addTestSiaFile(sp)
   663  	// Open the file.
   664  	sf, err := fs.OpenSiaFile(sp)
   665  	if err != nil {
   666  		t.Fatal(err)
   667  	}
   668  	// File shouldn't be deleted yet.
   669  	if sf.Deleted() {
   670  		t.Fatal("foo is deleted before calling delete")
   671  	}
   672  	// Delete it using the filesystem.
   673  	if err := fs.DeleteFile(sp); err != nil {
   674  		t.Fatal(err)
   675  	}
   676  	// Check that the open instance is marked as deleted.
   677  	if !sf.Deleted() {
   678  		t.Fatal("foo should be marked as deleted but wasn't")
   679  	}
   680  	// Check that we can't open another instance of foo and that we can't create
   681  	// a new file at the same path.
   682  	if _, err := fs.OpenSiaFile(sp); !errors.Contains(err, ErrNotExist) {
   683  		t.Fatal("err should be ErrNotExist but was:", err)
   684  	}
   685  	if err := fs.addTestSiaFileWithErr(sp); err != nil {
   686  		t.Fatal("err should be nil but was:", err)
   687  	}
   688  }
   689  
   690  // TestDeleteDirectory tests if deleting a directory correctly and recursively
   691  // removes the dir.
   692  func TestDeleteDirectory(t *testing.T) {
   693  	if testing.Short() && !build.VLONG {
   694  		t.SkipNow()
   695  	}
   696  	t.Parallel()
   697  	// Create filesystem.
   698  	root := filepath.Join(testDir(t.Name()), "fs-root")
   699  	fs := newTestFileSystem(root)
   700  	// Add some files.
   701  	fs.addTestSiaFile(newSiaPath("dir/foo/bar/file1"))
   702  	fs.addTestSiaFile(newSiaPath("dir/foo/bar/file2"))
   703  	fs.addTestSiaFile(newSiaPath("dir/foo/bar/file3"))
   704  	// Delete "foo"
   705  	if err := fs.DeleteDir(newSiaPath("/dir/foo")); err != nil {
   706  		t.Fatal(err)
   707  	}
   708  	// Check that /dir still exists.
   709  	if _, err := os.Stat(filepath.Join(root, "dir")); err != nil {
   710  		t.Fatal(err)
   711  	}
   712  	// Check that /dir is empty.
   713  	if fis, err := ioutil.ReadDir(filepath.Join(root, "dir")); err != nil {
   714  		t.Fatal(err)
   715  	} else if len(fis) != 1 {
   716  		for i, fi := range fis {
   717  			t.Logf("fi%v: %v", i, fi.Name())
   718  		}
   719  		t.Fatalf("expected 1 file in 'dir' but contains %v files", len(fis))
   720  	}
   721  }
   722  
   723  // TestRenameFile tests if renaming a single file works as expected.
   724  func TestRenameFile(t *testing.T) {
   725  	if testing.Short() && !build.VLONG {
   726  		t.SkipNow()
   727  	}
   728  	t.Parallel()
   729  	// Create filesystem.
   730  	root := filepath.Join(testDir(t.Name()), "fs-root")
   731  	fs := newTestFileSystem(root)
   732  	// Add a file to the root dir.
   733  	foo := newSiaPath("foo")
   734  	foobar := newSiaPath("foobar")
   735  	barfoo := newSiaPath("bar/foo")
   736  	fs.addTestSiaFile(foo)
   737  	// Rename the file.
   738  	if err := fs.RenameFile(foo, foobar); err != nil {
   739  		t.Fatal(err)
   740  	}
   741  	// Check if the file was renamed.
   742  	if _, err := fs.OpenSiaFile(foo); !errors.Contains(err, ErrNotExist) {
   743  		t.Fatal("expected ErrNotExist but got:", err)
   744  	}
   745  	sf, err := fs.OpenSiaFile(foobar)
   746  	if err != nil {
   747  		t.Fatal("expected ErrNotExist but got:", err)
   748  	}
   749  	sf.Close()
   750  	// Rename the file again. This time it changes to a non-existent folder.
   751  	if err := fs.RenameFile(foobar, barfoo); err != nil {
   752  		t.Fatal(err)
   753  	}
   754  	sf, err = fs.OpenSiaFile(barfoo)
   755  	if err != nil {
   756  		t.Fatal("expected ErrNotExist but got:", err)
   757  	}
   758  	sf.Close()
   759  }
   760  
   761  // TestThreadedAccess tests rapidly opening and closing files and directories
   762  // from multiple threads to check the locking conventions.
   763  func TestThreadedAccess(t *testing.T) {
   764  	if testing.Short() && !build.VLONG {
   765  		t.SkipNow()
   766  	}
   767  	t.Parallel()
   768  	// Specify the file structure for the test.
   769  	filePaths := []string{
   770  		"f0",
   771  		"f1",
   772  		"f2",
   773  
   774  		"d0/f0", "d0/f1", "d0/f2",
   775  		"d1/f0", "d1/f1", "d1/f2",
   776  		"d2/f0", "d2/f1", "d2/f2",
   777  
   778  		"d0/d0/f0", "d0/d0/f1", "d0/d0/f2",
   779  		"d0/d1/f0", "d0/d1/f1", "d0/d1/f2",
   780  		"d0/d2/f0", "d0/d2/f1", "d0/d2/f2",
   781  
   782  		"d1/d0/f0", "d1/d0/f1", "d1/d0/f2",
   783  		"d1/d1/f0", "d1/d1/f1", "d1/d1/f2",
   784  		"d1/d2/f0", "d1/d2/f1", "d1/d2/f2",
   785  
   786  		"d2/d0/f0", "d2/d0/f1", "d2/d0/f2",
   787  		"d2/d1/f0", "d2/d1/f1", "d2/d1/f2",
   788  		"d2/d2/f0", "d2/d2/f1", "d2/d2/f2",
   789  	}
   790  	// Create filesystem.
   791  	root := filepath.Join(testDir(t.Name()), "fs-root")
   792  	fs := newTestFileSystem(root)
   793  	for _, fp := range filePaths {
   794  		fs.addTestSiaFile(newSiaPath(fp))
   795  	}
   796  	// Create a few threads which open files
   797  	var wg sync.WaitGroup
   798  	numThreads := 5
   799  	maxNumActions := uint64(50000)
   800  	numActions := uint64(0)
   801  	for i := 0; i < numThreads; i++ {
   802  		wg.Add(1)
   803  		go func() {
   804  			defer wg.Done()
   805  			for {
   806  				if atomic.LoadUint64(&numActions) >= maxNumActions {
   807  					break
   808  				}
   809  				atomic.AddUint64(&numActions, 1)
   810  				sp := newSiaPath(filePaths[fastrand.Intn(len(filePaths))])
   811  				sf, err := fs.OpenSiaFile(sp)
   812  				if err != nil {
   813  					t.Error(err)
   814  					return
   815  				}
   816  				sf.Close()
   817  			}
   818  		}()
   819  	}
   820  	// Create a few threads which open dirs
   821  	for i := 0; i < numThreads; i++ {
   822  		wg.Add(1)
   823  		go func() {
   824  			defer wg.Done()
   825  			for {
   826  				if atomic.LoadUint64(&numActions) >= maxNumActions {
   827  					break
   828  				}
   829  				atomic.AddUint64(&numActions, 1)
   830  				sp := newSiaPath(filePaths[fastrand.Intn(len(filePaths))])
   831  				sp, err := sp.Dir()
   832  				if err != nil {
   833  					t.Error(err)
   834  					return
   835  				}
   836  				sd, err := fs.OpenSiaDir(sp)
   837  				if err != nil {
   838  					t.Error(err)
   839  					return
   840  				}
   841  				sd.Close()
   842  			}
   843  		}()
   844  	}
   845  	wg.Wait()
   846  
   847  	// Check the root's integrity. Since all files and dirs were closed, the
   848  	// node's maps should reflect that.
   849  	if len(fs.threads) != 0 {
   850  		t.Fatalf("fs should have 0 threads but had %v", len(fs.threads))
   851  	}
   852  	if len(fs.directories) != 0 {
   853  		t.Fatalf("fs should have 0 directories but had %v", len(fs.directories))
   854  	}
   855  	if len(fs.files) != 0 {
   856  		t.Fatalf("fs should have 0 files but had %v", len(fs.files))
   857  	}
   858  }
   859  
   860  // TestSiaDirRename tests the Rename method of the siadirset.
   861  func TestSiaDirRename(t *testing.T) {
   862  	if testing.Short() {
   863  		t.SkipNow()
   864  	}
   865  
   866  	// Prepare a filesystem.
   867  	root := filepath.Join(testDir(t.Name()), "fs-root")
   868  	os.RemoveAll(root)
   869  	fs := newTestFileSystem(root)
   870  
   871  	// Specify a directory structure for this test.
   872  	var dirStructure = []string{
   873  		"dir1",
   874  		"dir1/subdir1",
   875  		"dir1/subdir1/subsubdir1",
   876  		"dir1/subdir1/subsubdir2",
   877  		"dir1/subdir1/subsubdir3",
   878  		"dir1/subdir2",
   879  		"dir1/subdir2/subsubdir1",
   880  		"dir1/subdir2/subsubdir2",
   881  		"dir1/subdir2/subsubdir3",
   882  		"dir1/subdir3",
   883  		"dir1/subdir3/subsubdir1",
   884  		"dir1/subdir3/subsubdir2",
   885  		"dir1/subdir3/subsubdir3",
   886  	}
   887  	// Specify a function that's executed in parallel which continuously saves dirs
   888  	// to disk.
   889  	stop := make(chan struct{})
   890  	wg := new(sync.WaitGroup)
   891  	f := func(entry *DirNode) {
   892  		defer wg.Done()
   893  		defer func() {
   894  			if err := entry.Close(); err != nil {
   895  				t.Error(err)
   896  				return
   897  			}
   898  		}()
   899  		for {
   900  			select {
   901  			case <-stop:
   902  				return
   903  			default:
   904  			}
   905  			err := entry.UpdateMetadata(siadir.Metadata{})
   906  			if err != nil {
   907  				t.Error(err)
   908  				return
   909  			}
   910  			time.Sleep(50 * time.Millisecond)
   911  		}
   912  	}
   913  	// Create the structure and spawn a goroutine that keeps saving the structure
   914  	// to disk for each directory.
   915  	for _, dir := range dirStructure {
   916  		sp, err := skymodules.NewSiaPath(dir)
   917  		if err != nil {
   918  			t.Fatal(err)
   919  		}
   920  		err = fs.NewSiaDir(sp, skymodules.DefaultDirPerm)
   921  		if err != nil {
   922  			t.Fatal(err)
   923  		}
   924  		entry, err := fs.OpenSiaDir(sp)
   925  		if err != nil {
   926  			t.Fatal(err)
   927  		}
   928  		// 50% chance to spawn goroutine. It's not realistic to assume that all dirs
   929  		// are loaded.
   930  		if fastrand.Intn(2) == 0 {
   931  			wg.Add(1)
   932  			go f(entry)
   933  		} else {
   934  			if err := entry.Close(); err != nil {
   935  				t.Fatal(err)
   936  			}
   937  		}
   938  	}
   939  	// Wait a second for the goroutines to write to disk a few times.
   940  	time.Sleep(time.Second)
   941  	// Rename dir1 to dir2.
   942  	oldPath, err1 := skymodules.NewSiaPath(dirStructure[0])
   943  	newPath, err2 := skymodules.NewSiaPath("dir2")
   944  	if err := errors.Compose(err1, err2); err != nil {
   945  		t.Fatal(err)
   946  	}
   947  	if err := fs.RenameDir(oldPath, newPath); err != nil {
   948  		t.Fatal(err)
   949  	}
   950  	// Wait another second for more writes to disk after renaming the dir before
   951  	// killing the goroutines.
   952  	time.Sleep(time.Second)
   953  	close(stop)
   954  	wg.Wait()
   955  	time.Sleep(time.Second)
   956  	// Make sure we can't open any of the old folders on disk but we can open the
   957  	// new ones.
   958  	for _, dir := range dirStructure {
   959  		oldDir, err1 := skymodules.NewSiaPath(dir)
   960  		newDir, err2 := oldDir.Rebase(oldPath, newPath)
   961  		if err := errors.Compose(err1, err2); err != nil {
   962  			t.Fatal(err)
   963  		}
   964  		// Open entry with old dir. Shouldn't work.
   965  		_, err := fs.OpenSiaDir(oldDir)
   966  		if !errors.Contains(err, ErrNotExist) {
   967  			t.Fatal("shouldn't be able to open old path", oldDir.String(), err)
   968  		}
   969  		// Open entry with new dir. Should succeed.
   970  		entry, err := fs.OpenSiaDir(newDir)
   971  		if err != nil {
   972  			t.Fatal(err)
   973  		}
   974  		defer func() {
   975  			if err := entry.Close(); err != nil {
   976  				t.Fatal(err)
   977  			}
   978  		}()
   979  		// Check path of entry.
   980  		if expectedPath := fs.DirPath(newDir); *entry.path != expectedPath {
   981  			t.Fatalf("entry should have path '%v' but was '%v'", expectedPath, entry.path)
   982  		}
   983  	}
   984  }
   985  
   986  // TestAddSiaFileFromReader tests the AddSiaFileFromReader method's behavior.
   987  func TestAddSiaFileFromReader(t *testing.T) {
   988  	if testing.Short() {
   989  		t.SkipNow()
   990  	}
   991  	t.Parallel()
   992  	// Create a fileset with file.
   993  	sf, sfs, err := newTestFileSystemWithFile(t.Name())
   994  	if err != nil {
   995  		t.Fatal(err)
   996  	}
   997  	// Add the existing file to the set again this shouldn't do anything.
   998  	sr, err := sf.SnapshotReader()
   999  	if err != nil {
  1000  		t.Fatal(err)
  1001  	}
  1002  	d, err := ioutil.ReadAll(sr)
  1003  	sr.Close()
  1004  	if err != nil {
  1005  		t.Fatal(err)
  1006  	}
  1007  	if err := sfs.AddSiaFileFromReader(bytes.NewReader(d), sfs.FileSiaPath(sf)); err != nil {
  1008  		t.Fatal(err)
  1009  	}
  1010  	numSiaFiles := 0
  1011  	err = sfs.Walk(skymodules.RootSiaPath(), func(path string, info os.FileInfo, err error) error {
  1012  		if filepath.Ext(path) == skymodules.SiaFileExtension {
  1013  			numSiaFiles++
  1014  		}
  1015  		return nil
  1016  	})
  1017  	if err != nil {
  1018  		t.Fatal(err)
  1019  	}
  1020  	// There should be 1 siafile.
  1021  	if numSiaFiles != 1 {
  1022  		t.Fatalf("Found %v siafiles but expected %v", numSiaFiles, 1)
  1023  	}
  1024  	// Load the same siafile again, but change the UID.
  1025  	b, err := ioutil.ReadFile(sf.SiaFilePath())
  1026  	if err != nil {
  1027  		t.Fatal(err)
  1028  	}
  1029  	reader := bytes.NewReader(b)
  1030  	newSF, newChunks, err := siafile.LoadSiaFileFromReaderWithChunks(reader, sf.SiaFilePath(), sfs.staticWal)
  1031  	if err != nil {
  1032  		t.Fatal(err)
  1033  	}
  1034  	// Save the file to a temporary location with the new uid.
  1035  	newSF.UpdateUniqueID()
  1036  	newSF.SetSiaFilePath(sf.SiaFilePath() + "_tmp")
  1037  	if err := newSF.SaveWithChunks(newChunks); err != nil {
  1038  		t.Fatal(err)
  1039  	}
  1040  	// Grab the pre-import UID after changing it.
  1041  	preImportUID := newSF.UID()
  1042  	// Import the file. This should work because the files no longer share the same
  1043  	// UID.
  1044  	b, err = ioutil.ReadFile(newSF.SiaFilePath())
  1045  	if err != nil {
  1046  		t.Fatal(err)
  1047  	}
  1048  	// Remove file at temporary location after reading it.
  1049  	if err := os.Remove(newSF.SiaFilePath()); err != nil {
  1050  		t.Fatal(err)
  1051  	}
  1052  	reader = bytes.NewReader(b)
  1053  	var newSFSiaPath skymodules.SiaPath
  1054  	if err := newSFSiaPath.FromSysPath(sf.SiaFilePath(), sfs.Root()); err != nil {
  1055  		t.Fatal(err)
  1056  	}
  1057  	if err := sfs.AddSiaFileFromReader(reader, newSFSiaPath); err != nil {
  1058  		t.Fatal(err)
  1059  	}
  1060  	// Reload newSF with the new expected path.
  1061  	newSFPath := filepath.Join(filepath.Dir(sf.SiaFilePath()), newSFSiaPath.String()+"_1"+skymodules.SiaFileExtension)
  1062  	newSF, err = siafile.LoadSiaFile(newSFPath, sfs.staticWal)
  1063  	if err != nil {
  1064  		t.Fatal(err)
  1065  	}
  1066  	// sf and newSF should have the same pieces.
  1067  	for chunkIndex := uint64(0); chunkIndex < sf.NumChunks(); chunkIndex++ {
  1068  		piecesOld, err1 := sf.Pieces(chunkIndex)
  1069  		piecesNew, err2 := newSF.Pieces(chunkIndex)
  1070  		if err := errors.Compose(err1, err2); err != nil {
  1071  			t.Fatal(err)
  1072  		}
  1073  		if !reflect.DeepEqual(piecesOld, piecesNew) {
  1074  			t.Log("piecesOld: ", piecesOld)
  1075  			t.Log("piecesNew: ", piecesNew)
  1076  			t.Fatal("old pieces don't match new pieces")
  1077  		}
  1078  	}
  1079  	numSiaFiles = 0
  1080  	err = sfs.Walk(skymodules.RootSiaPath(), func(path string, info os.FileInfo, err error) error {
  1081  		if filepath.Ext(path) == skymodules.SiaFileExtension {
  1082  			numSiaFiles++
  1083  		}
  1084  		return nil
  1085  	})
  1086  	if err != nil {
  1087  		t.Fatal(err)
  1088  	}
  1089  	// There should be 2 siafiles.
  1090  	if numSiaFiles != 2 {
  1091  		t.Fatalf("Found %v siafiles but expected %v", numSiaFiles, 2)
  1092  	}
  1093  	// The UID should have changed.
  1094  	if newSF.UID() == preImportUID {
  1095  		t.Fatal("newSF UID should have changed after importing the file")
  1096  	}
  1097  	if !strings.HasSuffix(newSF.SiaFilePath(), "_1"+skymodules.SiaFileExtension) {
  1098  		t.Fatal("SiaFile should have a suffix but didn't")
  1099  	}
  1100  	// Should be able to open the new file from disk.
  1101  	if _, err := os.Stat(newSF.SiaFilePath()); err != nil {
  1102  		t.Fatal(err)
  1103  	}
  1104  }
  1105  
  1106  // TestSiaFileSetDeleteOpen checks that deleting an entry from the set followed
  1107  // by creating a Siafile with the same name without closing the deleted entry
  1108  // works as expected.
  1109  func TestSiaFileSetDeleteOpen(t *testing.T) {
  1110  	if testing.Short() {
  1111  		t.SkipNow()
  1112  	}
  1113  	t.Parallel()
  1114  
  1115  	// Create filesystem.
  1116  	sfs := newTestFileSystem(testDir(t.Name()))
  1117  	siaPath := skymodules.RandomSiaPath()
  1118  	rc, _ := skymodules.NewRSSubCode(10, 20, crypto.SegmentSize)
  1119  	fileSize := uint64(100)
  1120  	source := ""
  1121  	sk := crypto.GenerateSiaKey(crypto.TypeDefaultRenter)
  1122  	fileMode := os.FileMode(persist.DefaultDiskPermissionsTest)
  1123  
  1124  	// Repeatedly create a SiaFile and delete it while still keeping the entry
  1125  	// around. That should only be possible without errors if the correctly
  1126  	// delete the entry from the set.
  1127  	var entries []*FileNode
  1128  	for i := 0; i < 10; i++ {
  1129  		// Create SiaFile
  1130  		up := skymodules.FileUploadParams{
  1131  			Source:      source,
  1132  			SiaPath:     siaPath,
  1133  			ErasureCode: rc,
  1134  		}
  1135  		err := sfs.NewSiaFile(up.SiaPath, up.Source, up.ErasureCode, sk, fileSize, fileMode)
  1136  		if err != nil {
  1137  			t.Fatal(err)
  1138  		}
  1139  		entry, err := sfs.OpenSiaFile(up.SiaPath)
  1140  		if err != nil {
  1141  			t.Fatal(err)
  1142  		}
  1143  		// Delete SiaFile
  1144  		if err := sfs.DeleteFile(sfs.FileSiaPath(entry)); err != nil {
  1145  			t.Fatal(err)
  1146  		}
  1147  		// The map should be empty.
  1148  		if len(sfs.files) != 0 {
  1149  			t.Fatal("SiaFileMap should have 1 file")
  1150  		}
  1151  		// Append the entry to make sure we can close it later.
  1152  		entries = append(entries, entry)
  1153  	}
  1154  	// The SiaFile shouldn't exist anymore.
  1155  	_, err := sfs.OpenSiaFile(siaPath)
  1156  	if !errors.Contains(err, ErrNotExist) {
  1157  		t.Fatal("SiaFile shouldn't exist anymore")
  1158  	}
  1159  	// Close the entries.
  1160  	for _, entry := range entries {
  1161  		if err := entry.Close(); err != nil {
  1162  			t.Fatal(err)
  1163  		}
  1164  	}
  1165  }
  1166  
  1167  // TestSiaFileSetOpenClose tests that the threadCount of the siafile is
  1168  // incremented and decremented properly when Open() and Close() are called
  1169  func TestSiaFileSetOpenClose(t *testing.T) {
  1170  	if testing.Short() {
  1171  		t.SkipNow()
  1172  	}
  1173  	t.Parallel()
  1174  
  1175  	// Create SiaFileSet with SiaFile
  1176  	entry, sfs, err := newTestFileSystemWithFile(t.Name())
  1177  	if err != nil {
  1178  		t.Fatal(err)
  1179  	}
  1180  	siaPath := sfs.FileSiaPath(entry)
  1181  	exists, _ := sfs.FileExists(siaPath)
  1182  	if !exists {
  1183  		t.Fatal("No SiaFileSetEntry found")
  1184  	}
  1185  	if err != nil {
  1186  		t.Fatal(err)
  1187  	}
  1188  
  1189  	// Confirm 1 file is in memory
  1190  	if len(sfs.files) != 1 {
  1191  		t.Fatalf("Expected SiaFileSet map to be of length 1, instead is length %v", len(sfs.files))
  1192  	}
  1193  
  1194  	// Confirm threadCount is incremented properly
  1195  	if len(entry.threads) != 1 {
  1196  		t.Fatalf("Expected threadMap to be of length 1, got %v", len(entry.threads))
  1197  	}
  1198  
  1199  	// Close SiaFileSetEntry
  1200  	if err := entry.Close(); err != nil {
  1201  		t.Fatal(err)
  1202  	}
  1203  
  1204  	// Confirm that threadCount was decremented
  1205  	if len(entry.threads) != 0 {
  1206  		t.Fatalf("Expected threadCount to be 0, got %v", len(entry.threads))
  1207  	}
  1208  
  1209  	// Confirm file was removed from memory
  1210  	if len(sfs.files) != 0 {
  1211  		t.Fatalf("Expected SiaFileSet map to contain 0 files, instead is length %v", len(sfs.files))
  1212  	}
  1213  
  1214  	// Open siafile again and confirm threadCount was incremented
  1215  	entry, err = sfs.OpenSiaFile(siaPath)
  1216  	if err != nil {
  1217  		t.Fatal(err)
  1218  	}
  1219  	if len(entry.threads) != 1 {
  1220  		t.Fatalf("Expected threadCount to be 1, got %v", len(entry.threads))
  1221  	}
  1222  }
  1223  
  1224  // TestFilesInMemory confirms that files are added and removed from memory
  1225  // as expected when files are in use and not in use
  1226  func TestFilesInMemory(t *testing.T) {
  1227  	if testing.Short() {
  1228  		t.SkipNow()
  1229  	}
  1230  	t.Parallel()
  1231  
  1232  	// Create SiaFileSet with SiaFile
  1233  	entry, sfs, err := newTestFileSystemWithFile(t.Name())
  1234  	if err != nil {
  1235  		t.Fatal(err)
  1236  	}
  1237  	siaPath := sfs.FileSiaPath(entry)
  1238  	exists, _ := sfs.FileExists(siaPath)
  1239  	if !exists {
  1240  		t.Fatal("No SiaFileSetEntry found")
  1241  	}
  1242  	if err != nil {
  1243  		t.Fatal(err)
  1244  	}
  1245  	// Confirm there is 1 file in memory.
  1246  	if len(sfs.files) != 1 {
  1247  		t.Fatal("Expected 1 files in memory, got:", len(sfs.files))
  1248  	}
  1249  	// Close File
  1250  	if err := entry.Close(); err != nil {
  1251  		t.Fatal(err)
  1252  	}
  1253  	// Confirm there are no files in memory
  1254  	if len(sfs.files) != 0 {
  1255  		t.Fatal("Expected 0 files in memory, got:", len(sfs.files))
  1256  	}
  1257  
  1258  	// Test accessing the same file from two separate threads
  1259  	//
  1260  	// Open file
  1261  	entry1, err := sfs.OpenSiaFile(siaPath)
  1262  	if err != nil {
  1263  		t.Fatal(err)
  1264  	}
  1265  	// Confirm there is 1 file in memory
  1266  	if len(sfs.files) != 1 {
  1267  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1268  	}
  1269  	// Access the file again
  1270  	entry2, err := sfs.OpenSiaFile(siaPath)
  1271  	if err != nil {
  1272  		t.Fatal(err)
  1273  	}
  1274  	// Confirm there is still only has 1 file in memory
  1275  	if len(sfs.files) != 1 {
  1276  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1277  	}
  1278  	// Close one of the file instances
  1279  	entry1.Close()
  1280  	// Confirm there is still only has 1 file in memory
  1281  	if len(sfs.files) != 1 {
  1282  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1283  	}
  1284  
  1285  	// Confirm closing out remaining files removes all files from memory
  1286  	//
  1287  	// Close last instance of the first file
  1288  	entry2.Close()
  1289  	// Confirm there is no file in memory
  1290  	if len(sfs.files) != 0 {
  1291  		t.Fatal("Expected 0 files in memory, got:", len(sfs.files))
  1292  	}
  1293  }
  1294  
  1295  // TestRenameFileInMemory confirms that threads that have access to a file
  1296  // will continue to have access to the file even it another thread renames it
  1297  func TestRenameFileInMemory(t *testing.T) {
  1298  	if testing.Short() {
  1299  		t.SkipNow()
  1300  	}
  1301  	t.Parallel()
  1302  
  1303  	// Create FileSystem with corresponding siafile.
  1304  	entry, sfs, err := newTestFileSystemWithFile(t.Name())
  1305  	if err != nil {
  1306  		t.Fatal(err)
  1307  	}
  1308  	siaPath := sfs.FileSiaPath(entry)
  1309  	exists, _ := sfs.FileExists(siaPath)
  1310  	if !exists {
  1311  		t.Fatal("No SiaFile found")
  1312  	}
  1313  	if err != nil {
  1314  		t.Fatal(err)
  1315  	}
  1316  
  1317  	// Confirm there is 1 file in memory.
  1318  	if len(sfs.files) != 1 {
  1319  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1320  	}
  1321  
  1322  	// Test renaming an instance of a file
  1323  	//
  1324  	// Access file with another instance
  1325  	entry2, err := sfs.OpenSiaFile(siaPath)
  1326  	if err != nil {
  1327  		t.Fatal(err)
  1328  	}
  1329  	// Confirm that renter still only has 1 file in memory.
  1330  	if len(sfs.files) != 1 {
  1331  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1332  	}
  1333  	_, err = os.Stat(entry.SiaFilePath())
  1334  	if err != nil {
  1335  		t.Fatal(err)
  1336  	}
  1337  	// Rename second instance
  1338  	newSiaPath := skymodules.RandomSiaPath()
  1339  	err = sfs.RenameFile(siaPath, newSiaPath)
  1340  	if err != nil {
  1341  		t.Fatal(err)
  1342  	}
  1343  	// Confirm there are still only 1 file in memory as renaming doesn't add
  1344  	// the new name to memory
  1345  	if len(sfs.files) != 1 {
  1346  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1347  	}
  1348  	// Close instance of renamed file
  1349  	err = entry2.Close()
  1350  	if err != nil {
  1351  		t.Fatal(err)
  1352  	}
  1353  	// Confirm there are still only 1 file in memory
  1354  	if len(sfs.files) != 1 {
  1355  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1356  	}
  1357  	// Close other instance of second file
  1358  	err = entry.Close()
  1359  	if err != nil {
  1360  		t.Fatal(err)
  1361  	}
  1362  	// Confirm there is no file in memory
  1363  	if len(sfs.files) != 0 {
  1364  		t.Fatal("Expected 0 files in memory, got:", len(sfs.files))
  1365  	}
  1366  }
  1367  
  1368  // TestDeleteFileInMemory confirms that threads that have access to a file
  1369  // will continue to have access to the file even if another thread deletes it
  1370  func TestDeleteFileInMemory(t *testing.T) {
  1371  	if testing.Short() {
  1372  		t.SkipNow()
  1373  	}
  1374  	t.Parallel()
  1375  
  1376  	// Create FileSystem with SiaFile
  1377  	entry, sfs, err := newTestFileSystemWithFile(t.Name())
  1378  	if err != nil {
  1379  		t.Fatal(err)
  1380  	}
  1381  	siaPath := sfs.FileSiaPath(entry)
  1382  	exists, _ := sfs.FileExists(siaPath)
  1383  	if !exists {
  1384  		t.Fatal("No SiaFileSetEntry found")
  1385  	}
  1386  	if err != nil {
  1387  		t.Fatal(err)
  1388  	}
  1389  
  1390  	// Confirm there is 1 file in memory
  1391  	if len(sfs.files) != 1 {
  1392  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1393  	}
  1394  
  1395  	// Test deleting an instance of a file
  1396  	//
  1397  	// Access the file again
  1398  	entry2, err := sfs.OpenSiaFile(siaPath)
  1399  	if err != nil {
  1400  		t.Fatal(err)
  1401  	}
  1402  	// Confirm there is still only has 1 file in memory
  1403  	if len(sfs.files) != 1 {
  1404  		t.Fatal("Expected 1 file in memory, got:", len(sfs.files))
  1405  	}
  1406  	// Delete and close instance of file.
  1407  	if err := sfs.DeleteFile(siaPath); err != nil {
  1408  		t.Fatal(err)
  1409  	}
  1410  	err = entry2.Close()
  1411  	if err != nil {
  1412  		t.Fatal(err)
  1413  	}
  1414  	// There should be no file in the filesystem after deleting it.
  1415  	if len(sfs.files) != 0 {
  1416  		t.Fatal("Expected 0 files in memory, got:", len(sfs.files))
  1417  	}
  1418  	// Confirm other instance is still in memory by calling methods on it.
  1419  	if !entry.Deleted() {
  1420  		t.Fatal("Expected file to be deleted")
  1421  	}
  1422  
  1423  	// Confirm closing out remaining files removes all files from memory
  1424  	//
  1425  	// Close last instance of the first file
  1426  	err = entry.Close()
  1427  	if err != nil {
  1428  		t.Fatal(err)
  1429  	}
  1430  	// Confirm renter has one file in memory
  1431  	if len(sfs.files) != 0 {
  1432  		t.Fatal("Expected 0 file in memory, got:", len(sfs.files))
  1433  	}
  1434  }
  1435  
  1436  // TestDeleteCorruptSiaFile confirms that the siafileset will delete a siafile
  1437  // even if it cannot be opened
  1438  func TestDeleteCorruptSiaFile(t *testing.T) {
  1439  	if testing.Short() {
  1440  		t.SkipNow()
  1441  	}
  1442  	t.Parallel()
  1443  
  1444  	// Create siafileset
  1445  	_, sfs, err := newTestFileSystemWithFile(t.Name())
  1446  	if err != nil {
  1447  		t.Fatal(err)
  1448  	}
  1449  
  1450  	// Create siafile on disk with random bytes
  1451  	siaPath, err := skymodules.NewSiaPath("badFile")
  1452  	if err != nil {
  1453  		t.Fatal(err)
  1454  	}
  1455  	siaFilePath := siaPath.SiaFileSysPath(sfs.Root())
  1456  	err = ioutil.WriteFile(siaFilePath, fastrand.Bytes(100), persist.DefaultDiskPermissionsTest)
  1457  	if err != nil {
  1458  		t.Fatal(err)
  1459  	}
  1460  
  1461  	// Confirm the siafile cannot be opened
  1462  	_, err = sfs.OpenSiaFile(siaPath)
  1463  	if err == nil || errors.Contains(err, ErrNotExist) {
  1464  		t.Fatal("expected open to fail for read error but instead got:", err)
  1465  	}
  1466  
  1467  	// Delete the siafile
  1468  	err = sfs.DeleteFile(siaPath)
  1469  	if err != nil {
  1470  		t.Fatal(err)
  1471  	}
  1472  
  1473  	// Confirm the file is no longer on disk
  1474  	_, err = os.Stat(siaFilePath)
  1475  	if !os.IsNotExist(err) {
  1476  		t.Fatal("Expected err to be that file does not exists but was:", err)
  1477  	}
  1478  }
  1479  
  1480  // TestSiaDirDelete tests the DeleteDir method of the siafileset.
  1481  func TestSiaDirDelete(t *testing.T) {
  1482  	if testing.Short() {
  1483  		t.SkipNow()
  1484  	}
  1485  	t.Parallel()
  1486  
  1487  	// Prepare a siadirset
  1488  	root := filepath.Join(testDir(t.Name()), "fs-root")
  1489  	os.RemoveAll(root)
  1490  	fs := newTestFileSystem(root)
  1491  
  1492  	// Specify a directory structure for this test.
  1493  	var dirStructure = []string{
  1494  		"dir1",
  1495  		"dir1/subdir1",
  1496  		"dir1/subdir1/subsubdir1",
  1497  		"dir1/subdir1/subsubdir2",
  1498  		"dir1/subdir1/subsubdir3",
  1499  		"dir1/subdir2",
  1500  		"dir1/subdir2/subsubdir1",
  1501  		"dir1/subdir2/subsubdir2",
  1502  		"dir1/subdir2/subsubdir3",
  1503  		"dir1/subdir3",
  1504  		"dir1/subdir3/subsubdir1",
  1505  		"dir1/subdir3/subsubdir2",
  1506  		"dir1/subdir3/subsubdir3",
  1507  	}
  1508  	// Specify a function that's executed in parallel which continuously saves a
  1509  	// file to disk.
  1510  	stop := make(chan struct{})
  1511  	wg := new(sync.WaitGroup)
  1512  	f := func(entry *FileNode) {
  1513  		defer wg.Done()
  1514  		defer func() {
  1515  			if err := entry.Close(); err != nil {
  1516  				t.Error(err)
  1517  				return
  1518  			}
  1519  		}()
  1520  		for {
  1521  			select {
  1522  			case <-stop:
  1523  				return
  1524  			default:
  1525  			}
  1526  			err := entry.SaveHeader()
  1527  			if err != nil && !errors.Contains(err, siafile.ErrDeleted) {
  1528  				t.Error(err)
  1529  				return
  1530  			}
  1531  			time.Sleep(50 * time.Millisecond)
  1532  		}
  1533  	}
  1534  	// Create the structure and spawn a goroutine that keeps saving the structure
  1535  	// to disk for each directory.
  1536  	for _, dir := range dirStructure {
  1537  		sp, err := skymodules.NewSiaPath(dir)
  1538  		if err != nil {
  1539  			t.Fatal(err)
  1540  		}
  1541  		err = fs.NewSiaDir(sp, skymodules.DefaultDirPerm)
  1542  		if err != nil {
  1543  			t.Fatal(err)
  1544  		}
  1545  		entry, err := fs.OpenSiaDir(sp)
  1546  		if err != nil {
  1547  			t.Fatal(err)
  1548  		}
  1549  		// 50% chance to close the dir.
  1550  		if fastrand.Intn(2) == 0 {
  1551  			if err := entry.Close(); err != nil {
  1552  				t.Fatal(err)
  1553  			}
  1554  		}
  1555  		// Create a file in the dir.
  1556  		fileSP, err := sp.Join(hex.EncodeToString(fastrand.Bytes(16)))
  1557  		if err != nil {
  1558  			t.Fatal(err)
  1559  		}
  1560  		ec, _ := skymodules.NewRSSubCode(10, 20, crypto.SegmentSize)
  1561  		up := skymodules.FileUploadParams{Source: "", SiaPath: fileSP, ErasureCode: ec}
  1562  		err = fs.NewSiaFile(up.SiaPath, up.Source, up.ErasureCode, crypto.GenerateSiaKey(crypto.TypeDefaultRenter), 100, persist.DefaultDiskPermissionsTest)
  1563  		if err != nil {
  1564  			t.Fatal(err)
  1565  		}
  1566  		sf, err := fs.OpenSiaFile(up.SiaPath)
  1567  		if err != nil {
  1568  			t.Fatal(err)
  1569  		}
  1570  		// 50% chance to spawn goroutine. It's not realistic to assume that all dirs
  1571  		// are loaded.
  1572  		if fastrand.Intn(2) == 0 {
  1573  			wg.Add(1)
  1574  			go f(sf)
  1575  		} else {
  1576  			sf.Close()
  1577  		}
  1578  	}
  1579  	// Wait a second for the goroutines to write to disk a few times.
  1580  	time.Sleep(time.Second)
  1581  	// Delete dir1.
  1582  	sp, err := skymodules.NewSiaPath("dir1")
  1583  	if err != nil {
  1584  		t.Fatal(err)
  1585  	}
  1586  	if err := fs.DeleteDir(sp); err != nil {
  1587  		t.Fatal(err)
  1588  	}
  1589  
  1590  	// Wait another second for more writes to disk after renaming the dir before
  1591  	// killing the goroutines.
  1592  	time.Sleep(time.Second)
  1593  	close(stop)
  1594  	wg.Wait()
  1595  	time.Sleep(time.Second)
  1596  	// The root siafile dir should be empty except for 1 .siadir file.
  1597  	files, err := fs.ReadDir(skymodules.RootSiaPath())
  1598  	if err != nil {
  1599  		t.Fatal(err)
  1600  	}
  1601  	if len(files) != 1 {
  1602  		for _, file := range files {
  1603  			t.Log("Found ", file.Name())
  1604  		}
  1605  		t.Fatalf("There should be %v files/folders in the root dir but found %v\n", 1, len(files))
  1606  	}
  1607  	for _, file := range files {
  1608  		if filepath.Ext(file.Name()) != skymodules.SiaDirExtension {
  1609  			t.Fatal("Encountered unexpected file:", file.Name())
  1610  		}
  1611  	}
  1612  }
  1613  
  1614  // TestSiaDirRenameWithFiles tests the RenameDir method of the filesystem with
  1615  // files.
  1616  func TestSiaDirRenameWithFiles(t *testing.T) {
  1617  	if testing.Short() {
  1618  		t.SkipNow()
  1619  	}
  1620  	t.Parallel()
  1621  
  1622  	// Prepare a filesystem.
  1623  	root := filepath.Join(testDir(t.Name()), "fs-root")
  1624  	os.RemoveAll(root)
  1625  	fs := newTestFileSystem(root)
  1626  
  1627  	// Prepare parameters for siafiles.
  1628  	rc, _ := skymodules.NewRSSubCode(10, 20, crypto.SegmentSize)
  1629  	fileSize := uint64(100)
  1630  	source := ""
  1631  	sk := crypto.GenerateSiaKey(crypto.TypeDefaultRenter)
  1632  	fileMode := os.FileMode(persist.DefaultDiskPermissionsTest)
  1633  
  1634  	// Specify a directory structure for this test.
  1635  	var dirStructure = []string{
  1636  		"dir1",
  1637  		"dir1/subdir1",
  1638  		"dir1/subdir1/subsubdir1",
  1639  		"dir1/subdir1/subsubdir2",
  1640  		"dir1/subdir1/subsubdir3",
  1641  		"dir1/subdir2",
  1642  		"dir1/subdir2/subsubdir1",
  1643  		"dir1/subdir2/subsubdir2",
  1644  		"dir1/subdir2/subsubdir3",
  1645  		"dir1/subdir3",
  1646  		"dir1/subdir3/subsubdir1",
  1647  		"dir1/subdir3/subsubdir2",
  1648  		"dir1/subdir3/subsubdir3",
  1649  	}
  1650  	// Specify a function that's executed in parallel which continuously saves a
  1651  	// file to disk.
  1652  	stop := make(chan struct{})
  1653  	wg := new(sync.WaitGroup)
  1654  	f := func(entry *FileNode) {
  1655  		defer wg.Done()
  1656  		defer func() {
  1657  			if err := entry.Close(); err != nil {
  1658  				t.Error(err)
  1659  				return
  1660  			}
  1661  		}()
  1662  		for {
  1663  			select {
  1664  			case <-stop:
  1665  				return
  1666  			default:
  1667  			}
  1668  			err := entry.SaveHeader()
  1669  			if err != nil {
  1670  				t.Error(err)
  1671  				return
  1672  			}
  1673  			time.Sleep(50 * time.Millisecond)
  1674  		}
  1675  	}
  1676  	// Create the structure and spawn a goroutine that keeps saving the structure
  1677  	// to disk for each directory.
  1678  	for _, dir := range dirStructure {
  1679  		sp, err := skymodules.NewSiaPath(dir)
  1680  		if err != nil {
  1681  			t.Fatal(err)
  1682  		}
  1683  		err = fs.NewSiaDir(sp, skymodules.DefaultDirPerm)
  1684  		if err != nil {
  1685  			t.Fatal(err)
  1686  		}
  1687  		entry, err := fs.OpenSiaDir(sp)
  1688  		// 50% chance to close the dir.
  1689  		if fastrand.Intn(2) == 0 {
  1690  			if err := entry.Close(); err != nil {
  1691  				t.Fatal(err)
  1692  			}
  1693  		}
  1694  		// Create a file in the dir.
  1695  		fileSP, err := sp.Join(hex.EncodeToString(fastrand.Bytes(16)))
  1696  		if err != nil {
  1697  			t.Fatal(err)
  1698  		}
  1699  		err = fs.NewSiaFile(fileSP, source, rc, sk, fileSize, fileMode)
  1700  		if err != nil {
  1701  			t.Fatal(err)
  1702  		}
  1703  		sf, err := fs.OpenSiaFile(fileSP)
  1704  		if err != nil {
  1705  			t.Fatal(err)
  1706  		}
  1707  		// 50% chance to spawn goroutine. It's not realistic to assume that all dirs
  1708  		// are loaded.
  1709  		if fastrand.Intn(2) == 0 {
  1710  			wg.Add(1)
  1711  			go f(sf)
  1712  		} else {
  1713  			sf.Close()
  1714  		}
  1715  	}
  1716  	// Wait a second for the goroutines to write to disk a few times.
  1717  	time.Sleep(time.Second)
  1718  	// Rename dir1 to dir2.
  1719  	oldPath, err1 := skymodules.NewSiaPath(dirStructure[0])
  1720  	newPath, err2 := skymodules.NewSiaPath("dir2")
  1721  	if err := errors.Compose(err1, err2); err != nil {
  1722  		t.Fatal(err)
  1723  	}
  1724  	if err := fs.RenameDir(oldPath, newPath); err != nil {
  1725  		t.Fatal(err)
  1726  	}
  1727  	// Wait another second for more writes to disk after renaming the dir before
  1728  	// killing the goroutines.
  1729  	time.Sleep(time.Second)
  1730  	close(stop)
  1731  	wg.Wait()
  1732  	time.Sleep(time.Second)
  1733  	// Make sure we can't open any of the old folders/files on disk but we can open
  1734  	// the new ones.
  1735  	for _, dir := range dirStructure {
  1736  		oldDir, err1 := skymodules.NewSiaPath(dir)
  1737  		newDir, err2 := oldDir.Rebase(oldPath, newPath)
  1738  		if err := errors.Compose(err1, err2); err != nil {
  1739  			t.Fatal(err)
  1740  		}
  1741  		// Open entry with old dir. Shouldn't work.
  1742  		_, err := fs.OpenSiaDir(oldDir)
  1743  		if !errors.Contains(err, ErrNotExist) {
  1744  			t.Fatal("shouldn't be able to open old path", oldDir.String(), err)
  1745  		}
  1746  		// Old dir shouldn't exist.
  1747  		if _, err = fs.Stat(oldDir); !os.IsNotExist(err) {
  1748  			t.Fatal(err)
  1749  		}
  1750  		// Open entry with new dir. Should succeed.
  1751  		entry, err := fs.OpenSiaDir(newDir)
  1752  		if err != nil {
  1753  			t.Fatal(err)
  1754  		}
  1755  		defer func() {
  1756  			err = entry.Close()
  1757  			if err != nil {
  1758  				t.Fatal(err)
  1759  			}
  1760  		}()
  1761  		// New dir should contain 1 siafile.
  1762  		fis, err := fs.ReadDir(newDir)
  1763  		if err != nil {
  1764  			t.Fatal(err)
  1765  		}
  1766  		numFiles := 0
  1767  		for _, fi := range fis {
  1768  			if !fi.IsDir() && filepath.Ext(fi.Name()) == skymodules.SiaFileExtension {
  1769  				numFiles++
  1770  			}
  1771  		}
  1772  		if numFiles != 1 {
  1773  			t.Fatalf("there should be 1 file in the new dir not %v", numFiles)
  1774  		}
  1775  		// Check siapath of entry.
  1776  		if entry.managedAbsPath() != fs.DirPath(newDir) {
  1777  			t.Fatalf("entry should have path '%v' but was '%v'", fs.DirPath(newDir), entry.managedAbsPath())
  1778  		}
  1779  	}
  1780  }
  1781  
  1782  // TestRenameDirInMemory confirms that threads that have access to a dir
  1783  // will continue to have access to the dir even if the dir is renamed.
  1784  func TestRenameDirInMemory(t *testing.T) {
  1785  	if testing.Short() {
  1786  		t.SkipNow()
  1787  	}
  1788  	t.Parallel()
  1789  
  1790  	// Create FileSystem with corresponding siadir.
  1791  	entry, fs, err := newTestFileSystemWithDir(t.Name())
  1792  	if err != nil {
  1793  		t.Fatal(err)
  1794  	}
  1795  	siaPath := fs.DirSiaPath(entry)
  1796  	exists, _ := fs.DirExists(siaPath)
  1797  	if !exists {
  1798  		t.Fatal("No SiaDir found")
  1799  	}
  1800  
  1801  	// Confirm there are 1 dir in memory
  1802  	if len(fs.directories) != 1 {
  1803  		t.Fatal("Expected 1 dir in memory, got:", len(fs.directories))
  1804  	}
  1805  
  1806  	// Access dir with another instance
  1807  	entry2, err := fs.OpenSiaDir(siaPath)
  1808  	if err != nil {
  1809  		t.Fatal(err)
  1810  	}
  1811  	// Confirm that renter still only has 1 dir in memory
  1812  	if len(fs.directories) != 1 {
  1813  		t.Fatal("Expected 1 dir in memory, got:", len(fs.directories))
  1814  	}
  1815  	path, err := entry2.Path()
  1816  	if err != nil {
  1817  		t.Fatal(err)
  1818  	}
  1819  	_, err = os.Stat(path)
  1820  	if err != nil {
  1821  		t.Fatal(err)
  1822  	}
  1823  	// Rename the directory.
  1824  	newSiaPath := skymodules.RandomSiaPath()
  1825  	err = fs.RenameDir(siaPath, newSiaPath)
  1826  	if err != nil {
  1827  		t.Fatal(err)
  1828  	}
  1829  	// Confirm both instances are still in memory.
  1830  	deleted, err := entry.Deleted()
  1831  	if err != nil {
  1832  		t.Fatal(err)
  1833  	}
  1834  	if deleted {
  1835  		t.Fatal("Expected file to not be deleted")
  1836  	}
  1837  	deleted, err = entry2.Deleted()
  1838  	if err != nil {
  1839  		t.Fatal(err)
  1840  	}
  1841  	if deleted {
  1842  		t.Fatal("Expected file to not be deleted")
  1843  	}
  1844  
  1845  	// Create a new dir at the same path.
  1846  	err = fs.NewSiaDir(siaPath, skymodules.DefaultDirPerm)
  1847  	if err != nil {
  1848  		t.Fatal(err)
  1849  	}
  1850  	// Confirm the directory is still in memory.
  1851  	deleted, err = entry.Deleted()
  1852  	if err != nil {
  1853  		t.Fatal(err)
  1854  	}
  1855  	if deleted {
  1856  		t.Fatal("Expected file to not be deleted")
  1857  	}
  1858  
  1859  	// Confirm there is still only 1 dir in memory as renaming doesn't add
  1860  	// the new name to memory.
  1861  	if len(fs.directories) != 1 {
  1862  		t.Fatal("Expected 1 dir in memory, got:", len(fs.directories))
  1863  	}
  1864  	// Close instance of renamed dir.
  1865  	err = entry2.Close()
  1866  	if err != nil {
  1867  		t.Fatal(err)
  1868  	}
  1869  	// Confirm there are still only 1 dir in memory.
  1870  	if len(fs.directories) != 1 {
  1871  		t.Fatal("Expected 1 dir in memory, got:", len(fs.directories))
  1872  	}
  1873  	// Close other instance of second dir.
  1874  	err = entry.Close()
  1875  	if err != nil {
  1876  		t.Fatal(err)
  1877  	}
  1878  	// Confirm there is no dir in memory.
  1879  	if len(fs.directories) != 0 {
  1880  		t.Fatal("Expected 0 dirs in memory, got:", len(fs.directories))
  1881  	}
  1882  }
  1883  
  1884  // TestDeleteDirInMemory confirms that threads that have access to a dir
  1885  // will continue to have access to the dir even if another thread deletes it
  1886  func TestDeleteDirInMemory(t *testing.T) {
  1887  	if testing.Short() {
  1888  		t.SkipNow()
  1889  	}
  1890  	t.Parallel()
  1891  
  1892  	// Create FileSystem with corresponding siadir.
  1893  	entry, fs, err := newTestFileSystemWithDir(t.Name())
  1894  	if err != nil {
  1895  		t.Fatal(err)
  1896  	}
  1897  	dirPath := fs.DirSiaPath(entry)
  1898  	exists, _ := fs.DirExists(dirPath)
  1899  	if !exists {
  1900  		t.Fatal("No SiaDirSetEntry found")
  1901  	}
  1902  
  1903  	// Confirm there is 1 dir in memory
  1904  	if len(fs.directories) != 1 {
  1905  		t.Fatal("Expected 1 dir in memory, got:", len(fs.directories))
  1906  	}
  1907  
  1908  	// Add files to the dir and open them.
  1909  	filepath1, err := dirPath.Join("file1")
  1910  	if err != nil {
  1911  		t.Fatal(err)
  1912  	}
  1913  	fs.addTestSiaFile(filepath1)
  1914  	fileEntry1, err := fs.OpenSiaFile(filepath1)
  1915  	if err != nil {
  1916  		t.Fatal(err)
  1917  	}
  1918  	filepath2, err := dirPath.Join("file2")
  1919  	if err != nil {
  1920  		t.Fatal(err)
  1921  	}
  1922  	fs.addTestSiaFile(filepath2)
  1923  	fileEntry2, err := fs.OpenSiaFile(filepath2)
  1924  	if err != nil {
  1925  		t.Fatal(err)
  1926  	}
  1927  
  1928  	// Confirm the files are in the filesystem.
  1929  	if len(entry.files) != 2 {
  1930  		t.Fatal("Expected 2 files in memory, got:", len(entry.files))
  1931  	}
  1932  
  1933  	// Test deleting an instance of a dir
  1934  	//
  1935  	// Access the dir again
  1936  	entry2, err := fs.OpenSiaDir(dirPath)
  1937  	if err != nil {
  1938  		t.Fatal(err)
  1939  	}
  1940  	// Confirm there is still only has 1 dir in memory
  1941  	if len(fs.directories) != 1 {
  1942  		t.Fatal("Expected 1 dir in memory, got:", len(fs.directories))
  1943  	}
  1944  	// The files should not have been deleted yet.
  1945  	if fileEntry1.Deleted() {
  1946  		t.Fatal("expected file1 not to be marked deleted")
  1947  	}
  1948  	if fileEntry2.Deleted() {
  1949  		t.Fatal("expected file2 not to be marked deleted")
  1950  	}
  1951  	// Delete and close instance of dir.
  1952  	err = fs.DeleteDir(dirPath)
  1953  	if err != nil {
  1954  		t.Fatal(err)
  1955  	}
  1956  	err = entry2.Close()
  1957  	if err != nil {
  1958  		t.Fatal(err)
  1959  	}
  1960  	// There should be no dir in the filesystem after deleting it.
  1961  	if len(fs.directories) != 0 {
  1962  		t.Fatal("Expected 0 dirs in memory, got:", len(fs.directories))
  1963  	}
  1964  	// The files should have been deleted as well.
  1965  	if !fileEntry1.Deleted() {
  1966  		t.Fatal("expected file1 to be marked deleted")
  1967  	}
  1968  	if !fileEntry2.Deleted() {
  1969  		t.Fatal("expected file2 to be marked deleted")
  1970  	}
  1971  
  1972  	// Confirm other instance is still in memory by calling methods on it.
  1973  	deleted, err := entry.Deleted()
  1974  	if err != nil {
  1975  		t.Fatal(err)
  1976  	}
  1977  	if !deleted {
  1978  		t.Fatal("Expected dir to be deleted")
  1979  	}
  1980  
  1981  	// Create a new dir at the same path.
  1982  	err = fs.NewSiaDir(dirPath, skymodules.DefaultDirPerm)
  1983  	if err != nil {
  1984  		t.Fatal(err)
  1985  	}
  1986  	// Get the entry.
  1987  	entry3, err := fs.OpenSiaDir(dirPath)
  1988  	if err != nil {
  1989  		t.Fatal(err)
  1990  	}
  1991  	// Confirm the other instance is still in memory.
  1992  	deleted, err = entry.Deleted()
  1993  	if err != nil {
  1994  		t.Fatal(err)
  1995  	}
  1996  	if !deleted {
  1997  		t.Fatal("Expected dir to be deleted")
  1998  	}
  1999  
  2000  	// New dir should not link to the files of the old dir.
  2001  	if len(entry3.files) != 0 {
  2002  		t.Fatal("Expected 0 files in memory, got:", len(entry3.files))
  2003  	}
  2004  
  2005  	// Confirm closing out remaining dirs removes all dirs from memory
  2006  	//
  2007  	// Close last instance of the first dir
  2008  	err = entry.Close()
  2009  	if err != nil {
  2010  		t.Fatal(err)
  2011  	}
  2012  	err = entry3.Close()
  2013  	if err != nil {
  2014  		t.Fatal(err)
  2015  	}
  2016  	// Confirm renter has no dirs in memory
  2017  	if len(fs.directories) != 0 {
  2018  		t.Fatal("Expected 0 dirs in memory, got:", len(fs.directories))
  2019  	}
  2020  }
  2021  
  2022  // TestLazySiaDir tests that siaDir correctly reads and sets the lazySiaDir
  2023  // field.
  2024  func TestLazySiaDir(t *testing.T) {
  2025  	if testing.Short() && !build.VLONG {
  2026  		t.SkipNow()
  2027  	}
  2028  	t.Parallel()
  2029  	// Create filesystem.
  2030  	root := filepath.Join(testDir(t.Name()), "fs-root")
  2031  	fs := newTestFileSystem(root)
  2032  	// Create dir /foo
  2033  	sp := newSiaPath("foo")
  2034  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); err != nil {
  2035  		t.Fatal(err)
  2036  	}
  2037  	// Open the newly created dir.
  2038  	foo, err := fs.OpenSiaDir(sp)
  2039  	if err != nil {
  2040  		t.Fatal(err)
  2041  	}
  2042  	defer func() {
  2043  		if err := foo.Close(); err != nil {
  2044  			t.Fatal(err)
  2045  		}
  2046  	}()
  2047  	// Get the siadir.
  2048  	sd, err := foo.siaDir()
  2049  	if err != nil {
  2050  		t.Fatal(err)
  2051  	}
  2052  	// Lazydir should be set.
  2053  	if *foo.lazySiaDir != sd {
  2054  		t.Fatal(err)
  2055  	}
  2056  	// Fetching foo from root should also have lazydir set.
  2057  	fooRoot := fs.directories["foo"]
  2058  	if *fooRoot.lazySiaDir != sd {
  2059  		t.Fatal("fooRoot doesn't have lazydir set")
  2060  	}
  2061  	// Open foo again.
  2062  	foo2, err := fs.OpenSiaDir(sp)
  2063  	if err != nil {
  2064  		t.Fatal(err)
  2065  	}
  2066  	defer func() {
  2067  		if err := foo2.Close(); err != nil {
  2068  			t.Fatal(err)
  2069  		}
  2070  	}()
  2071  	// Lazydir should already be loaded.
  2072  	if *foo2.lazySiaDir != sd {
  2073  		t.Fatal("foo2.lazySiaDir isn't set correctly", foo2.lazySiaDir)
  2074  	}
  2075  }
  2076  
  2077  // TestLazySiaDir tests that siaDir correctly reads and sets the lazySiaDir
  2078  // field.
  2079  func TestOpenCloseRoot(t *testing.T) {
  2080  	if testing.Short() && !build.VLONG {
  2081  		t.SkipNow()
  2082  	}
  2083  	t.Parallel()
  2084  	// Create filesystem.
  2085  	root := filepath.Join(testDir(t.Name()), "fs-root")
  2086  	fs := newTestFileSystem(root)
  2087  
  2088  	rootNode, err := fs.OpenSiaDir(skymodules.RootSiaPath())
  2089  	if err != nil {
  2090  		t.Fatal(err)
  2091  	}
  2092  	err = rootNode.Close()
  2093  	if err != nil {
  2094  		t.Fatal(err)
  2095  	}
  2096  }
  2097  
  2098  // TestFailedOpenFileFolder makes sure that a failed call to OpenSiaFile or
  2099  // OpensiaDir doesn't leave any nodes dangling in memory.
  2100  func TestFailedOpenFileFolder(t *testing.T) {
  2101  	if testing.Short() && !build.VLONG {
  2102  		t.SkipNow()
  2103  	}
  2104  	t.Parallel()
  2105  	// Create filesystem.
  2106  	root := filepath.Join(testDir(t.Name()), "fs-root")
  2107  	fs := newTestFileSystem(root)
  2108  	// Create dir /sub1/sub2
  2109  	sp := newSiaPath("sub1/sub2")
  2110  	if err := fs.NewSiaDir(sp, skymodules.DefaultDirPerm); err != nil {
  2111  		t.Fatal(err)
  2112  	}
  2113  	// Prepare a path to "foo"
  2114  	foo, err := sp.Join("foo")
  2115  	if err != nil {
  2116  		t.Fatal(err)
  2117  	}
  2118  	// Open "foo" as a dir.
  2119  	_, err = fs.OpenSiaDir(foo)
  2120  	if !errors.Contains(err, ErrNotExist) {
  2121  		t.Fatal("err should be ErrNotExist but was", err)
  2122  	}
  2123  	if len(fs.files) != 0 || len(fs.directories) != 0 {
  2124  		t.Fatal("Expected 0 files and folders but got", len(fs.files), len(fs.directories))
  2125  	}
  2126  	// Open "foo" as a file.
  2127  	_, err = fs.OpenSiaFile(foo)
  2128  	if !errors.Contains(err, ErrNotExist) {
  2129  		t.Fatal("err should be ErrNotExist but was", err)
  2130  	}
  2131  	if len(fs.files) != 0 || len(fs.directories) != 0 {
  2132  		t.Fatal("Expected 0 files and folders but got", len(fs.files), len(fs.directories))
  2133  	}
  2134  }
  2135  
  2136  // TestFileDirConflict makes sure that files and dirs cannot share the same
  2137  // name.
  2138  func TestFileDirConflict(t *testing.T) {
  2139  	if testing.Short() {
  2140  		t.SkipNow()
  2141  	}
  2142  
  2143  	testFileDirConflict(t, false)
  2144  	testFileDirConflict(t, true)
  2145  }
  2146  
  2147  // testFileDirConflict runs a subtest for TestFileDirConflict. When `open` is
  2148  // true we first open the already existing file/dir before trying to produce
  2149  // `ErrExist` and delete it.
  2150  func testFileDirConflict(t *testing.T, open bool) {
  2151  	// Prepare a filesystem.
  2152  	root := filepath.Join(testDir(t.Name()), fmt.Sprintf("open-%v", open), "fs-root")
  2153  	err := os.RemoveAll(root)
  2154  	if err != nil {
  2155  		t.Fatal(err)
  2156  	}
  2157  	fs := newTestFileSystem(root)
  2158  
  2159  	// Create a file.
  2160  	filepath := newSiaPath("dir1/file1")
  2161  	fs.addTestSiaFile(filepath)
  2162  
  2163  	if open {
  2164  		// Open the file. This shouldn't affect later checks.
  2165  		node, err := fs.OpenSiaFile(filepath)
  2166  		if err != nil {
  2167  			t.Fatal(err)
  2168  		}
  2169  		defer func() {
  2170  			err := node.Close()
  2171  			if err != nil {
  2172  				t.Fatal(err)
  2173  			}
  2174  		}()
  2175  	}
  2176  
  2177  	// Make sure we can't create another file with the same name.
  2178  	err = fs.addTestSiaFileWithErr(filepath)
  2179  	if !errors.Contains(err, ErrExists) {
  2180  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2181  	}
  2182  
  2183  	// Make sure we can't rename another file to the same name.
  2184  	filepath2 := newSiaPath("dir1/file2")
  2185  	fs.addTestSiaFile(filepath2)
  2186  	err = fs.RenameFile(filepath2, filepath)
  2187  	if !errors.Contains(err, ErrExists) {
  2188  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2189  	}
  2190  
  2191  	// Make sure we (still) can't create another file with the same name.
  2192  	err = fs.addTestSiaFileWithErr(filepath)
  2193  	if !errors.Contains(err, ErrExists) {
  2194  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2195  	}
  2196  
  2197  	// Make sure we can't create a dir with the same name.
  2198  	err = fs.NewSiaDir(filepath, skymodules.DefaultDirPerm)
  2199  	if !errors.Contains(err, ErrExists) {
  2200  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2201  	}
  2202  
  2203  	// Create a dir.
  2204  	dirpath := newSiaPath("dir2/dir3")
  2205  	err = fs.NewSiaDir(dirpath, skymodules.DefaultDirPerm)
  2206  	if err != nil {
  2207  		t.Fatal(err)
  2208  	}
  2209  
  2210  	if open {
  2211  		// Open the dir. This shouldn't affect later checks.
  2212  		node, err := fs.OpenSiaDir(dirpath)
  2213  		if err != nil {
  2214  			t.Fatal(err)
  2215  		}
  2216  		defer func() {
  2217  			err := node.Close()
  2218  			if err != nil {
  2219  				t.Fatal(err)
  2220  			}
  2221  		}()
  2222  	}
  2223  
  2224  	// Make sure we CAN create another dir with the same name as the first
  2225  	// dir.
  2226  	err = fs.NewSiaDir(dirpath, skymodules.DefaultDirPerm)
  2227  	if err != nil {
  2228  		t.Fatal(err)
  2229  	}
  2230  
  2231  	// Make sure we can't rename a dir to the same name as the first file.
  2232  	err = fs.RenameDir(dirpath, filepath)
  2233  	if !errors.Contains(err, ErrExists) {
  2234  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2235  	}
  2236  
  2237  	// Make sure we still CAN create another dir with the same name as the first
  2238  	// dir.
  2239  	err = fs.NewSiaDir(dirpath, skymodules.DefaultDirPerm)
  2240  	if err != nil {
  2241  		t.Fatal(err)
  2242  	}
  2243  
  2244  	// Make sure we can't create a file with the same name as the dir.
  2245  	err = fs.addTestSiaFileWithErr(dirpath)
  2246  	if !errors.Contains(err, ErrExists) {
  2247  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2248  	}
  2249  
  2250  	// Make sure we can't rename a file to the same name as the first dir.
  2251  	err = fs.RenameFile(filepath, dirpath)
  2252  	if !errors.Contains(err, ErrExists) {
  2253  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2254  	}
  2255  
  2256  	// Make sure we can't rename another dir to the same name as the first dir.
  2257  	dirpath2 := newSiaPath("dir2/dir4")
  2258  	err = fs.NewSiaDir(dirpath2, skymodules.DefaultDirPerm)
  2259  	if err != nil {
  2260  		t.Fatal(err)
  2261  	}
  2262  	err = fs.RenameDir(dirpath2, dirpath)
  2263  	if !errors.Contains(err, ErrExists) {
  2264  		t.Fatalf("Expected err %v, got %v", ErrExists, err)
  2265  	}
  2266  }
  2267  
  2268  // TestList tests that the list method of the filesystem returns the correct
  2269  // number of file and directory information
  2270  func TestList(t *testing.T) {
  2271  	if testing.Short() {
  2272  		t.SkipNow()
  2273  	}
  2274  	// Prepare a siadirset
  2275  	root := filepath.Join(testDir(t.Name()), "fs-root")
  2276  	os.RemoveAll(root)
  2277  	fs := newTestFileSystem(root)
  2278  
  2279  	// Specify a directory structure for this test.
  2280  	var dirStructure = []string{
  2281  		"dir1",
  2282  		"dir1/subdir1",
  2283  		"dir1/subdir1/subsubdir1",
  2284  		"dir1/subdir1/subsubdir2",
  2285  		"dir1/subdir1/subsubdir3",
  2286  		"dir1/subdir2",
  2287  		"dir1/subdir2/subsubdir1",
  2288  		"dir1/subdir2/subsubdir2",
  2289  		"dir1/subdir2/subsubdir3",
  2290  		"dir1/subdir3",
  2291  		"dir1/subdir3/subsubdir1",
  2292  		"dir1/subdir3/subsubdir2",
  2293  		"dir1/subdir3/subsubdir3",
  2294  	}
  2295  
  2296  	// Create filesystem
  2297  	for _, d := range dirStructure {
  2298  		// Create directory
  2299  		siaPath := newSiaPath(d)
  2300  		err := fs.NewSiaDir(siaPath, persist.DefaultDiskPermissionsTest)
  2301  		if err != nil {
  2302  			t.Fatal(err)
  2303  		}
  2304  
  2305  		// Add a file
  2306  		fileSiaPath, err := siaPath.Join("file")
  2307  		if err != nil {
  2308  			t.Fatal(err)
  2309  		}
  2310  		fs.addTestSiaFile(fileSiaPath)
  2311  	}
  2312  
  2313  	// Get the cached information
  2314  	fis, dis, err := fs.CachedListCollect(newSiaPath(dirStructure[0]), true)
  2315  	if err != nil {
  2316  		t.Fatal(err)
  2317  	}
  2318  	if len(fis) != len(dirStructure) {
  2319  		t.Fatal("wrong number of files", len(fis), len(dirStructure))
  2320  	}
  2321  	if len(dis) != len(dirStructure) {
  2322  		t.Fatal("wrong number of dirs", len(dis), len(dirStructure))
  2323  	}
  2324  }