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