github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/vfs/dir_test.go (about)

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"sort"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/rclone/rclone/fs"
    12  	"github.com/rclone/rclone/fstest"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func dirCreate(t *testing.T, r *fstest.Run) (*VFS, *Dir, fstest.Item) {
    18  	vfs := New(r.Fremote, nil)
    19  
    20  	file1 := r.WriteObject(context.Background(), "dir/file1", "file1 contents", t1)
    21  	fstest.CheckItems(t, r.Fremote, file1)
    22  
    23  	node, err := vfs.Stat("dir")
    24  	require.NoError(t, err)
    25  	require.True(t, node.IsDir())
    26  
    27  	return vfs, node.(*Dir), file1
    28  }
    29  
    30  func TestDirMethods(t *testing.T) {
    31  	r := fstest.NewRun(t)
    32  	defer r.Finalise()
    33  	vfs, dir, _ := dirCreate(t, r)
    34  
    35  	// String
    36  	assert.Equal(t, "dir/", dir.String())
    37  	assert.Equal(t, "<nil *Dir>", (*Dir)(nil).String())
    38  
    39  	// IsDir
    40  	assert.Equal(t, true, dir.IsDir())
    41  
    42  	// IsFile
    43  	assert.Equal(t, false, dir.IsFile())
    44  
    45  	// Mode
    46  	assert.Equal(t, vfs.Opt.DirPerms, dir.Mode())
    47  
    48  	// Name
    49  	assert.Equal(t, "dir", dir.Name())
    50  
    51  	// Path
    52  	assert.Equal(t, "dir", dir.Path())
    53  
    54  	// Sys
    55  	assert.Equal(t, nil, dir.Sys())
    56  
    57  	// SetSys
    58  	dir.SetSys(42)
    59  	assert.Equal(t, 42, dir.Sys())
    60  
    61  	// Inode
    62  	assert.NotEqual(t, uint64(0), dir.Inode())
    63  
    64  	// Node
    65  	assert.Equal(t, dir, dir.Node())
    66  
    67  	// ModTime
    68  	assert.WithinDuration(t, t1, dir.ModTime(), 100*365*24*60*60*time.Second)
    69  
    70  	// Size
    71  	assert.Equal(t, int64(0), dir.Size())
    72  
    73  	// Sync
    74  	assert.NoError(t, dir.Sync())
    75  
    76  	// DirEntry
    77  	assert.Equal(t, dir.entry, dir.DirEntry())
    78  
    79  	// VFS
    80  	assert.Equal(t, vfs, dir.VFS())
    81  }
    82  
    83  func TestDirForgetAll(t *testing.T) {
    84  	r := fstest.NewRun(t)
    85  	defer r.Finalise()
    86  	vfs, dir, file1 := dirCreate(t, r)
    87  
    88  	// Make sure / and dir are in cache
    89  	_, err := vfs.Stat(file1.Path)
    90  	require.NoError(t, err)
    91  
    92  	root, err := vfs.Root()
    93  	require.NoError(t, err)
    94  
    95  	assert.Equal(t, 1, len(root.items))
    96  	assert.Equal(t, 1, len(dir.items))
    97  	assert.False(t, root.read.IsZero())
    98  	assert.False(t, dir.read.IsZero())
    99  
   100  	dir.ForgetAll()
   101  	assert.Equal(t, 1, len(root.items))
   102  	assert.Equal(t, 0, len(dir.items))
   103  	assert.False(t, root.read.IsZero())
   104  	assert.True(t, dir.read.IsZero())
   105  
   106  	root.ForgetAll()
   107  	assert.Equal(t, 0, len(root.items))
   108  	assert.Equal(t, 0, len(dir.items))
   109  	assert.True(t, root.read.IsZero())
   110  }
   111  
   112  func TestDirForgetPath(t *testing.T) {
   113  	r := fstest.NewRun(t)
   114  	defer r.Finalise()
   115  	vfs, dir, file1 := dirCreate(t, r)
   116  
   117  	// Make sure / and dir are in cache
   118  	_, err := vfs.Stat(file1.Path)
   119  	require.NoError(t, err)
   120  
   121  	root, err := vfs.Root()
   122  	require.NoError(t, err)
   123  
   124  	assert.Equal(t, 1, len(root.items))
   125  	assert.Equal(t, 1, len(dir.items))
   126  	assert.False(t, root.read.IsZero())
   127  	assert.False(t, dir.read.IsZero())
   128  
   129  	root.ForgetPath("dir/notfound", fs.EntryObject)
   130  	assert.Equal(t, 1, len(root.items))
   131  	assert.Equal(t, 1, len(dir.items))
   132  	assert.False(t, root.read.IsZero())
   133  	assert.True(t, dir.read.IsZero())
   134  
   135  	root.ForgetPath("dir", fs.EntryDirectory)
   136  	assert.Equal(t, 1, len(root.items))
   137  	assert.Equal(t, 0, len(dir.items))
   138  	assert.True(t, root.read.IsZero())
   139  
   140  	root.ForgetPath("not/in/cache", fs.EntryDirectory)
   141  	assert.Equal(t, 1, len(root.items))
   142  	assert.Equal(t, 0, len(dir.items))
   143  }
   144  
   145  func TestDirWalk(t *testing.T) {
   146  	r := fstest.NewRun(t)
   147  	defer r.Finalise()
   148  	vfs, _, file1 := dirCreate(t, r)
   149  
   150  	file2 := r.WriteObject(context.Background(), "fil/a/b/c", "super long file", t1)
   151  	fstest.CheckItems(t, r.Fremote, file1, file2)
   152  
   153  	root, err := vfs.Root()
   154  	require.NoError(t, err)
   155  
   156  	// Forget the cache since we put another object in
   157  	root.ForgetAll()
   158  
   159  	// Read the directories in
   160  	_, err = vfs.Stat("dir")
   161  	require.NoError(t, err)
   162  	_, err = vfs.Stat("fil/a/b")
   163  	require.NoError(t, err)
   164  	fil, err := vfs.Stat("fil")
   165  	require.NoError(t, err)
   166  
   167  	var result []string
   168  	fn := func(d *Dir) {
   169  		result = append(result, d.path)
   170  	}
   171  
   172  	result = nil
   173  	root.walk(fn)
   174  	sort.Strings(result) // sort as there is a map traversal involved
   175  	assert.Equal(t, []string{"", "dir", "fil", "fil/a", "fil/a/b"}, result)
   176  
   177  	assert.Nil(t, root.cachedDir("not found"))
   178  	if dir := root.cachedDir("dir"); assert.NotNil(t, dir) {
   179  		result = nil
   180  		dir.walk(fn)
   181  		assert.Equal(t, []string{"dir"}, result)
   182  	}
   183  	if dir := root.cachedDir("fil"); assert.NotNil(t, dir) {
   184  		result = nil
   185  		dir.walk(fn)
   186  		assert.Equal(t, []string{"fil/a/b", "fil/a", "fil"}, result)
   187  	}
   188  	if dir := fil.(*Dir); assert.NotNil(t, dir) {
   189  		result = nil
   190  		dir.walk(fn)
   191  		assert.Equal(t, []string{"fil/a/b", "fil/a", "fil"}, result)
   192  	}
   193  	if dir := root.cachedDir("fil/a"); assert.NotNil(t, dir) {
   194  		result = nil
   195  		dir.walk(fn)
   196  		assert.Equal(t, []string{"fil/a/b", "fil/a"}, result)
   197  	}
   198  	if dir := fil.(*Dir).cachedDir("a"); assert.NotNil(t, dir) {
   199  		result = nil
   200  		dir.walk(fn)
   201  		assert.Equal(t, []string{"fil/a/b", "fil/a"}, result)
   202  	}
   203  	if dir := root.cachedDir("fil/a"); assert.NotNil(t, dir) {
   204  		result = nil
   205  		dir.walk(fn)
   206  		assert.Equal(t, []string{"fil/a/b", "fil/a"}, result)
   207  	}
   208  	if dir := root.cachedDir("fil/a/b"); assert.NotNil(t, dir) {
   209  		result = nil
   210  		dir.walk(fn)
   211  		assert.Equal(t, []string{"fil/a/b"}, result)
   212  	}
   213  }
   214  
   215  func TestDirSetModTime(t *testing.T) {
   216  	r := fstest.NewRun(t)
   217  	defer r.Finalise()
   218  	vfs, dir, _ := dirCreate(t, r)
   219  
   220  	err := dir.SetModTime(t1)
   221  	require.NoError(t, err)
   222  	assert.WithinDuration(t, t1, dir.ModTime(), time.Second)
   223  
   224  	err = dir.SetModTime(t2)
   225  	require.NoError(t, err)
   226  	assert.WithinDuration(t, t2, dir.ModTime(), time.Second)
   227  
   228  	vfs.Opt.ReadOnly = true
   229  	err = dir.SetModTime(t2)
   230  	assert.Equal(t, EROFS, err)
   231  }
   232  
   233  func TestDirStat(t *testing.T) {
   234  	r := fstest.NewRun(t)
   235  	defer r.Finalise()
   236  	_, dir, _ := dirCreate(t, r)
   237  
   238  	node, err := dir.Stat("file1")
   239  	require.NoError(t, err)
   240  	_, ok := node.(*File)
   241  	assert.True(t, ok)
   242  	assert.Equal(t, int64(14), node.Size())
   243  	assert.Equal(t, "file1", node.Name())
   244  
   245  	_, err = dir.Stat("not found")
   246  	assert.Equal(t, ENOENT, err)
   247  }
   248  
   249  // This lists dir and checks the listing is as expected
   250  func checkListing(t *testing.T, dir *Dir, want []string) {
   251  	var got []string
   252  	nodes, err := dir.ReadDirAll()
   253  	require.NoError(t, err)
   254  	for _, node := range nodes {
   255  		got = append(got, fmt.Sprintf("%s,%d,%v", node.Name(), node.Size(), node.IsDir()))
   256  	}
   257  	assert.Equal(t, want, got)
   258  }
   259  
   260  func TestDirReadDirAll(t *testing.T) {
   261  	r := fstest.NewRun(t)
   262  	defer r.Finalise()
   263  	vfs := New(r.Fremote, nil)
   264  
   265  	file1 := r.WriteObject(context.Background(), "dir/file1", "file1 contents", t1)
   266  	file2 := r.WriteObject(context.Background(), "dir/file2", "file2- contents", t2)
   267  	file3 := r.WriteObject(context.Background(), "dir/subdir/file3", "file3-- contents", t3)
   268  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
   269  
   270  	node, err := vfs.Stat("dir")
   271  	require.NoError(t, err)
   272  	dir := node.(*Dir)
   273  
   274  	checkListing(t, dir, []string{"file1,14,false", "file2,15,false", "subdir,0,true"})
   275  
   276  	node, err = vfs.Stat("")
   277  	require.NoError(t, err)
   278  	dir = node.(*Dir)
   279  
   280  	checkListing(t, dir, []string{"dir,0,true"})
   281  
   282  	node, err = vfs.Stat("dir/subdir")
   283  	require.NoError(t, err)
   284  	dir = node.(*Dir)
   285  
   286  	checkListing(t, dir, []string{"file3,16,false"})
   287  }
   288  
   289  func TestDirOpen(t *testing.T) {
   290  	r := fstest.NewRun(t)
   291  	defer r.Finalise()
   292  	_, dir, _ := dirCreate(t, r)
   293  
   294  	fd, err := dir.Open(os.O_RDONLY)
   295  	require.NoError(t, err)
   296  	_, ok := fd.(*DirHandle)
   297  	assert.True(t, ok)
   298  	require.NoError(t, fd.Close())
   299  
   300  	_, err = dir.Open(os.O_WRONLY)
   301  	assert.Equal(t, EPERM, err)
   302  }
   303  
   304  func TestDirCreate(t *testing.T) {
   305  	r := fstest.NewRun(t)
   306  	defer r.Finalise()
   307  	vfs, dir, _ := dirCreate(t, r)
   308  
   309  	file, err := dir.Create("potato", os.O_WRONLY|os.O_CREATE)
   310  	require.NoError(t, err)
   311  	assert.Equal(t, int64(0), file.Size())
   312  
   313  	fd, err := file.Open(os.O_WRONLY | os.O_CREATE)
   314  	require.NoError(t, err)
   315  
   316  	// FIXME Note that this fails with the current implementation
   317  	// until the file has been opened.
   318  
   319  	// file2, err := vfs.Stat("dir/potato")
   320  	// require.NoError(t, err)
   321  	// assert.Equal(t, file, file2)
   322  
   323  	n, err := fd.Write([]byte("hello"))
   324  	require.NoError(t, err)
   325  	assert.Equal(t, 5, n)
   326  
   327  	require.NoError(t, fd.Close())
   328  
   329  	file2, err := vfs.Stat("dir/potato")
   330  	require.NoError(t, err)
   331  	assert.Equal(t, int64(5), file2.Size())
   332  
   333  	vfs.Opt.ReadOnly = true
   334  	_, err = dir.Create("sausage", os.O_WRONLY|os.O_CREATE)
   335  	assert.Equal(t, EROFS, err)
   336  }
   337  
   338  func TestDirMkdir(t *testing.T) {
   339  	r := fstest.NewRun(t)
   340  	defer r.Finalise()
   341  	vfs, dir, file1 := dirCreate(t, r)
   342  
   343  	_, err := dir.Mkdir("file1")
   344  	assert.Error(t, err)
   345  
   346  	sub, err := dir.Mkdir("sub")
   347  	assert.NoError(t, err)
   348  
   349  	// check the vfs
   350  	checkListing(t, dir, []string{"file1,14,false", "sub,0,true"})
   351  	checkListing(t, sub, []string(nil))
   352  
   353  	// check the underlying r.Fremote
   354  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir", "dir/sub"}, r.Fremote.Precision())
   355  
   356  	vfs.Opt.ReadOnly = true
   357  	_, err = dir.Mkdir("sausage")
   358  	assert.Equal(t, EROFS, err)
   359  }
   360  
   361  func TestDirMkdirSub(t *testing.T) {
   362  	r := fstest.NewRun(t)
   363  	defer r.Finalise()
   364  	vfs, dir, file1 := dirCreate(t, r)
   365  
   366  	_, err := dir.Mkdir("file1")
   367  	assert.Error(t, err)
   368  
   369  	sub, err := dir.Mkdir("sub")
   370  	assert.NoError(t, err)
   371  
   372  	subsub, err := sub.Mkdir("subsub")
   373  	assert.NoError(t, err)
   374  
   375  	// check the vfs
   376  	checkListing(t, dir, []string{"file1,14,false", "sub,0,true"})
   377  	checkListing(t, sub, []string{"subsub,0,true"})
   378  	checkListing(t, subsub, []string(nil))
   379  
   380  	// check the underlying r.Fremote
   381  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir", "dir/sub", "dir/sub/subsub"}, r.Fremote.Precision())
   382  
   383  	vfs.Opt.ReadOnly = true
   384  	_, err = dir.Mkdir("sausage")
   385  	assert.Equal(t, EROFS, err)
   386  }
   387  
   388  func TestDirRemove(t *testing.T) {
   389  	r := fstest.NewRun(t)
   390  	defer r.Finalise()
   391  	vfs, dir, _ := dirCreate(t, r)
   392  
   393  	// check directory is there
   394  	node, err := vfs.Stat("dir")
   395  	require.NoError(t, err)
   396  	assert.True(t, node.IsDir())
   397  
   398  	err = dir.Remove()
   399  	assert.Equal(t, ENOTEMPTY, err)
   400  
   401  	// Delete the sub file
   402  	node, err = vfs.Stat("dir/file1")
   403  	require.NoError(t, err)
   404  	err = node.Remove()
   405  	require.NoError(t, err)
   406  
   407  	// Remove the now empty directory
   408  	err = dir.Remove()
   409  	require.NoError(t, err)
   410  
   411  	// check directory is not there
   412  	_, err = vfs.Stat("dir")
   413  	assert.Equal(t, ENOENT, err)
   414  
   415  	// check the vfs
   416  	root, err := vfs.Root()
   417  	require.NoError(t, err)
   418  	checkListing(t, root, []string(nil))
   419  
   420  	// check the underlying r.Fremote
   421  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, r.Fremote.Precision())
   422  
   423  	// read only check
   424  	vfs.Opt.ReadOnly = true
   425  	err = dir.Remove()
   426  	assert.Equal(t, EROFS, err)
   427  }
   428  
   429  func TestDirRemoveAll(t *testing.T) {
   430  	r := fstest.NewRun(t)
   431  	defer r.Finalise()
   432  	vfs, dir, _ := dirCreate(t, r)
   433  
   434  	// Remove the directory and contents
   435  	err := dir.RemoveAll()
   436  	require.NoError(t, err)
   437  
   438  	// check the vfs
   439  	root, err := vfs.Root()
   440  	require.NoError(t, err)
   441  	checkListing(t, root, []string(nil))
   442  
   443  	// check the underlying r.Fremote
   444  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, r.Fremote.Precision())
   445  
   446  	// read only check
   447  	vfs.Opt.ReadOnly = true
   448  	err = dir.RemoveAll()
   449  	assert.Equal(t, EROFS, err)
   450  }
   451  
   452  func TestDirRemoveName(t *testing.T) {
   453  	r := fstest.NewRun(t)
   454  	defer r.Finalise()
   455  	vfs, dir, _ := dirCreate(t, r)
   456  
   457  	err := dir.RemoveName("file1")
   458  	require.NoError(t, err)
   459  	checkListing(t, dir, []string(nil))
   460  	root, err := vfs.Root()
   461  	require.NoError(t, err)
   462  	checkListing(t, root, []string{"dir,0,true"})
   463  
   464  	// check the underlying r.Fremote
   465  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"dir"}, r.Fremote.Precision())
   466  
   467  	// read only check
   468  	vfs.Opt.ReadOnly = true
   469  	err = dir.RemoveName("potato")
   470  	assert.Equal(t, EROFS, err)
   471  }
   472  
   473  func TestDirRename(t *testing.T) {
   474  	r := fstest.NewRun(t)
   475  	defer r.Finalise()
   476  
   477  	features := r.Fremote.Features()
   478  	if features.DirMove == nil && features.Move == nil && features.Copy == nil {
   479  		return // skip as can't rename directories
   480  	}
   481  
   482  	vfs, dir, file1 := dirCreate(t, r)
   483  	file3 := r.WriteObject(context.Background(), "dir/file3", "file3 contents!", t1)
   484  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file3}, []string{"dir"}, r.Fremote.Precision())
   485  
   486  	root, err := vfs.Root()
   487  	require.NoError(t, err)
   488  
   489  	err = dir.Rename("not found", "tuba", dir)
   490  	assert.Equal(t, ENOENT, err)
   491  
   492  	// Rename a directory
   493  	err = root.Rename("dir", "dir2", root)
   494  	assert.NoError(t, err)
   495  	checkListing(t, root, []string{"dir2,0,true"})
   496  	checkListing(t, dir, []string{"file1,14,false", "file3,15,false"})
   497  
   498  	// check the underlying r.Fremote
   499  	file1.Path = "dir2/file1"
   500  	file3.Path = "dir2/file3"
   501  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file3}, []string{"dir2"}, r.Fremote.Precision())
   502  
   503  	// refetch dir
   504  	node, err := vfs.Stat("dir2")
   505  	assert.NoError(t, err)
   506  	dir = node.(*Dir)
   507  
   508  	// Rename a file
   509  	err = dir.Rename("file1", "file2", root)
   510  	assert.NoError(t, err)
   511  	checkListing(t, root, []string{"dir2,0,true", "file2,14,false"})
   512  	checkListing(t, dir, []string{"file3,15,false"})
   513  
   514  	// check the underlying r.Fremote
   515  	file1.Path = "file2"
   516  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file3}, []string{"dir2"}, r.Fremote.Precision())
   517  
   518  	// Rename a file on top of another file
   519  	err = root.Rename("file2", "file3", dir)
   520  	assert.NoError(t, err)
   521  	checkListing(t, root, []string{"dir2,0,true"})
   522  	checkListing(t, dir, []string{"file3,14,false"})
   523  
   524  	// check the underlying r.Fremote
   525  	file1.Path = "dir2/file3"
   526  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir2"}, r.Fremote.Precision())
   527  
   528  	// rename an empty directory
   529  	_, err = root.Mkdir("empty directory")
   530  	assert.NoError(t, err)
   531  	checkListing(t, root, []string{
   532  		"dir2,0,true",
   533  		"empty directory,0,true",
   534  	})
   535  	err = root.Rename("empty directory", "renamed empty directory", root)
   536  	assert.NoError(t, err)
   537  	checkListing(t, root, []string{
   538  		"dir2,0,true",
   539  		"renamed empty directory,0,true",
   540  	})
   541  	// ...we don't check the underlying f.Fremote because on
   542  	// bucket based remotes the directory won't be there
   543  
   544  	// read only check
   545  	vfs.Opt.ReadOnly = true
   546  	err = dir.Rename("potato", "tuba", dir)
   547  	assert.Equal(t, EROFS, err)
   548  }