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

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"io/ioutil"
     6  	"os"
     7  	"testing"
     8  
     9  	"github.com/rclone/rclone/fs"
    10  	"github.com/rclone/rclone/fs/operations"
    11  	"github.com/rclone/rclone/fstest"
    12  	"github.com/rclone/rclone/fstest/mockfs"
    13  	"github.com/rclone/rclone/fstest/mockobject"
    14  	"github.com/rclone/rclone/vfs/vfscommon"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func fileCreate(t *testing.T, r *fstest.Run, mode vfscommon.CacheMode) (*VFS, *File, fstest.Item) {
    20  	opt := vfscommon.DefaultOpt
    21  	opt.CacheMode = mode
    22  	vfs := New(r.Fremote, &opt)
    23  
    24  	file1 := r.WriteObject(context.Background(), "dir/file1", "file1 contents", t1)
    25  	fstest.CheckItems(t, r.Fremote, file1)
    26  
    27  	node, err := vfs.Stat("dir/file1")
    28  	require.NoError(t, err)
    29  	require.True(t, node.Mode().IsRegular())
    30  
    31  	return vfs, node.(*File), file1
    32  }
    33  
    34  func TestFileMethods(t *testing.T) {
    35  	r := fstest.NewRun(t)
    36  	defer r.Finalise()
    37  	vfs, file, _ := fileCreate(t, r, vfscommon.CacheModeOff)
    38  
    39  	// String
    40  	assert.Equal(t, "dir/file1", file.String())
    41  	assert.Equal(t, "<nil *File>", (*File)(nil).String())
    42  
    43  	// IsDir
    44  	assert.Equal(t, false, file.IsDir())
    45  
    46  	// IsFile
    47  	assert.Equal(t, true, file.IsFile())
    48  
    49  	// Mode
    50  	assert.Equal(t, vfs.Opt.FilePerms, file.Mode())
    51  
    52  	// Name
    53  	assert.Equal(t, "file1", file.Name())
    54  
    55  	// Path
    56  	assert.Equal(t, "dir/file1", file.Path())
    57  
    58  	// Sys
    59  	assert.Equal(t, nil, file.Sys())
    60  
    61  	// SetSys
    62  	file.SetSys(42)
    63  	assert.Equal(t, 42, file.Sys())
    64  
    65  	// Inode
    66  	assert.NotEqual(t, uint64(0), file.Inode())
    67  
    68  	// Node
    69  	assert.Equal(t, file, file.Node())
    70  
    71  	// ModTime
    72  	assert.WithinDuration(t, t1, file.ModTime(), r.Fremote.Precision())
    73  
    74  	// Size
    75  	assert.Equal(t, int64(14), file.Size())
    76  
    77  	// Sync
    78  	assert.NoError(t, file.Sync())
    79  
    80  	// DirEntry
    81  	assert.Equal(t, file.o, file.DirEntry())
    82  
    83  	// Dir
    84  	assert.Equal(t, file.d, file.Dir())
    85  
    86  	// VFS
    87  	assert.Equal(t, vfs, file.VFS())
    88  }
    89  
    90  func TestFileSetModTime(t *testing.T) {
    91  	r := fstest.NewRun(t)
    92  	if !canSetModTime(t, r) {
    93  		return
    94  	}
    95  	defer r.Finalise()
    96  	vfs, file, file1 := fileCreate(t, r, vfscommon.CacheModeOff)
    97  
    98  	err := file.SetModTime(t2)
    99  	require.NoError(t, err)
   100  
   101  	file1.ModTime = t2
   102  	fstest.CheckItems(t, r.Fremote, file1)
   103  
   104  	vfs.Opt.ReadOnly = true
   105  	err = file.SetModTime(t2)
   106  	assert.Equal(t, EROFS, err)
   107  }
   108  
   109  func fileCheckContents(t *testing.T, file *File) {
   110  	fd, err := file.Open(os.O_RDONLY)
   111  	require.NoError(t, err)
   112  
   113  	contents, err := ioutil.ReadAll(fd)
   114  	require.NoError(t, err)
   115  	assert.Equal(t, "file1 contents", string(contents))
   116  
   117  	require.NoError(t, fd.Close())
   118  }
   119  
   120  func TestFileOpenRead(t *testing.T) {
   121  	r := fstest.NewRun(t)
   122  	defer r.Finalise()
   123  	_, file, _ := fileCreate(t, r, vfscommon.CacheModeOff)
   124  
   125  	fileCheckContents(t, file)
   126  }
   127  
   128  func TestFileOpenReadUnknownSize(t *testing.T) {
   129  	var (
   130  		contents = []byte("file contents")
   131  		remote   = "file.txt"
   132  		ctx      = context.Background()
   133  	)
   134  
   135  	// create a mock object which returns size -1
   136  	o := mockobject.New(remote).WithContent(contents, mockobject.SeekModeNone)
   137  	o.SetUnknownSize(true)
   138  	assert.Equal(t, int64(-1), o.Size())
   139  
   140  	// add it to a mock fs
   141  	f := mockfs.NewFs("test", "root")
   142  	f.AddObject(o)
   143  	testObj, err := f.NewObject(ctx, remote)
   144  	require.NoError(t, err)
   145  	assert.Equal(t, int64(-1), testObj.Size())
   146  
   147  	// create a VFS from that mockfs
   148  	vfs := New(f, nil)
   149  
   150  	// find the file
   151  	node, err := vfs.Stat(remote)
   152  	require.NoError(t, err)
   153  	require.True(t, node.IsFile())
   154  	file := node.(*File)
   155  
   156  	// open it
   157  	fd, err := file.openRead()
   158  	require.NoError(t, err)
   159  	assert.Equal(t, int64(0), fd.Size())
   160  
   161  	// check the contents are not empty even though size is empty
   162  	gotContents, err := ioutil.ReadAll(fd)
   163  	require.NoError(t, err)
   164  	assert.Equal(t, contents, gotContents)
   165  	t.Logf("gotContents = %q", gotContents)
   166  
   167  	// check that file size has been updated
   168  	assert.Equal(t, int64(len(contents)), fd.Size())
   169  
   170  	require.NoError(t, fd.Close())
   171  }
   172  
   173  func TestFileOpenWrite(t *testing.T) {
   174  	r := fstest.NewRun(t)
   175  	defer r.Finalise()
   176  	vfs, file, _ := fileCreate(t, r, vfscommon.CacheModeOff)
   177  
   178  	fd, err := file.openWrite(os.O_WRONLY | os.O_TRUNC)
   179  	require.NoError(t, err)
   180  
   181  	newContents := []byte("this is some new contents")
   182  	n, err := fd.Write(newContents)
   183  	require.NoError(t, err)
   184  	assert.Equal(t, len(newContents), n)
   185  	require.NoError(t, fd.Close())
   186  
   187  	assert.Equal(t, int64(25), file.Size())
   188  
   189  	vfs.Opt.ReadOnly = true
   190  	_, err = file.openWrite(os.O_WRONLY | os.O_TRUNC)
   191  	assert.Equal(t, EROFS, err)
   192  }
   193  
   194  func TestFileRemove(t *testing.T) {
   195  	r := fstest.NewRun(t)
   196  	defer r.Finalise()
   197  	vfs, file, _ := fileCreate(t, r, vfscommon.CacheModeOff)
   198  
   199  	err := file.Remove()
   200  	require.NoError(t, err)
   201  
   202  	fstest.CheckItems(t, r.Fremote)
   203  
   204  	vfs.Opt.ReadOnly = true
   205  	err = file.Remove()
   206  	assert.Equal(t, EROFS, err)
   207  }
   208  
   209  func TestFileRemoveAll(t *testing.T) {
   210  	r := fstest.NewRun(t)
   211  	defer r.Finalise()
   212  	vfs, file, _ := fileCreate(t, r, vfscommon.CacheModeOff)
   213  
   214  	err := file.RemoveAll()
   215  	require.NoError(t, err)
   216  
   217  	fstest.CheckItems(t, r.Fremote)
   218  
   219  	vfs.Opt.ReadOnly = true
   220  	err = file.RemoveAll()
   221  	assert.Equal(t, EROFS, err)
   222  }
   223  
   224  func TestFileOpen(t *testing.T) {
   225  	r := fstest.NewRun(t)
   226  	defer r.Finalise()
   227  	_, file, _ := fileCreate(t, r, vfscommon.CacheModeOff)
   228  
   229  	fd, err := file.Open(os.O_RDONLY)
   230  	require.NoError(t, err)
   231  	_, ok := fd.(*ReadFileHandle)
   232  	assert.True(t, ok)
   233  	require.NoError(t, fd.Close())
   234  
   235  	fd, err = file.Open(os.O_WRONLY)
   236  	assert.NoError(t, err)
   237  	_, ok = fd.(*WriteFileHandle)
   238  	assert.True(t, ok)
   239  	require.NoError(t, fd.Close())
   240  
   241  	fd, err = file.Open(os.O_RDWR)
   242  	assert.NoError(t, err)
   243  	_, ok = fd.(*WriteFileHandle)
   244  	assert.True(t, ok)
   245  
   246  	_, err = file.Open(3)
   247  	assert.Equal(t, EPERM, err)
   248  }
   249  
   250  func testFileRename(t *testing.T, mode vfscommon.CacheMode) {
   251  	r := fstest.NewRun(t)
   252  	defer r.Finalise()
   253  	vfs, file, item := fileCreate(t, r, mode)
   254  
   255  	if !operations.CanServerSideMove(r.Fremote) {
   256  		t.Skip("skip as can't rename files")
   257  	}
   258  
   259  	rootDir, err := vfs.Root()
   260  	require.NoError(t, err)
   261  
   262  	// check file in cache
   263  	if mode != vfscommon.CacheModeOff {
   264  		// read contents to get file in cache
   265  		fileCheckContents(t, file)
   266  		assert.True(t, vfs.cache.Exists(item.Path))
   267  	}
   268  
   269  	dir := file.Dir()
   270  
   271  	// start with "dir/file1"
   272  	fstest.CheckItems(t, r.Fremote, item)
   273  
   274  	// rename file to "newLeaf"
   275  	err = dir.Rename("file1", "newLeaf", rootDir)
   276  	require.NoError(t, err)
   277  
   278  	item.Path = "newLeaf"
   279  	fstest.CheckItems(t, r.Fremote, item)
   280  
   281  	// check file in cache
   282  	if mode != vfscommon.CacheModeOff {
   283  		assert.True(t, vfs.cache.Exists(item.Path))
   284  	}
   285  
   286  	// check file exists in the vfs layer at its new name
   287  	_, err = vfs.Stat("newLeaf")
   288  	require.NoError(t, err)
   289  
   290  	// rename it back to "dir/file1"
   291  	err = rootDir.Rename("newLeaf", "file1", dir)
   292  	require.NoError(t, err)
   293  
   294  	item.Path = "dir/file1"
   295  	fstest.CheckItems(t, r.Fremote, item)
   296  
   297  	// check file in cache
   298  	if mode != vfscommon.CacheModeOff {
   299  		assert.True(t, vfs.cache.Exists(item.Path))
   300  	}
   301  
   302  	// now try renaming it with the file open
   303  	// first open it and write to it but don't close it
   304  	fd, err := file.Open(os.O_WRONLY | os.O_TRUNC)
   305  	require.NoError(t, err)
   306  	newContents := []byte("this is some new contents")
   307  	_, err = fd.Write(newContents)
   308  	require.NoError(t, err)
   309  
   310  	// rename file to "newLeaf"
   311  	err = dir.Rename("file1", "newLeaf", rootDir)
   312  	require.NoError(t, err)
   313  	newItem := fstest.NewItem("newLeaf", string(newContents), item.ModTime)
   314  
   315  	// check file has been renamed immediately in the cache
   316  	if mode != vfscommon.CacheModeOff {
   317  		assert.True(t, vfs.cache.Exists("newLeaf"))
   318  	}
   319  
   320  	// check file exists in the vfs layer at its new name
   321  	_, err = vfs.Stat("newLeaf")
   322  	require.NoError(t, err)
   323  
   324  	// Close the file
   325  	require.NoError(t, fd.Close())
   326  
   327  	// Check file has now been renamed on the remote
   328  	item.Path = "newLeaf"
   329  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{newItem}, nil, fs.ModTimeNotSupported)
   330  }
   331  
   332  func TestFileRename(t *testing.T) {
   333  	t.Run("CacheModeOff", func(t *testing.T) {
   334  		testFileRename(t, vfscommon.CacheModeOff)
   335  	})
   336  	t.Run("CacheModeFull", func(t *testing.T) {
   337  		testFileRename(t, vfscommon.CacheModeFull)
   338  	})
   339  }