github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/vfs/read_write_test.go (about)

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/rclone/rclone/fs"
    13  	"github.com/rclone/rclone/fs/operations"
    14  	"github.com/rclone/rclone/fstest"
    15  	"github.com/rclone/rclone/vfs/vfscommon"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  // Check interfaces
    21  var (
    22  	_ io.Reader   = (*RWFileHandle)(nil)
    23  	_ io.ReaderAt = (*RWFileHandle)(nil)
    24  	_ io.Writer   = (*RWFileHandle)(nil)
    25  	_ io.WriterAt = (*RWFileHandle)(nil)
    26  	_ io.Seeker   = (*RWFileHandle)(nil)
    27  	_ io.Closer   = (*RWFileHandle)(nil)
    28  	_ Handle      = (*RWFileHandle)(nil)
    29  )
    30  
    31  // Create a file and open it with the flags passed in
    32  func rwHandleCreateFlags(t *testing.T, create bool, filename string, flags int) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) {
    33  	opt := vfscommon.DefaultOpt
    34  	opt.CacheMode = vfscommon.CacheModeFull
    35  	opt.WriteBack = writeBackDelay
    36  	r, vfs = newTestVFSOpt(t, &opt)
    37  
    38  	if create {
    39  		file1 := r.WriteObject(context.Background(), filename, "0123456789abcdef", t1)
    40  		r.CheckRemoteItems(t, file1)
    41  	}
    42  
    43  	h, err := vfs.OpenFile(filename, flags, 0777)
    44  	require.NoError(t, err)
    45  	fh, ok := h.(*RWFileHandle)
    46  	require.True(t, ok)
    47  
    48  	return r, vfs, fh
    49  }
    50  
    51  // Open a file for read
    52  func rwHandleCreateReadOnly(t *testing.T) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) {
    53  	return rwHandleCreateFlags(t, true, "dir/file1", os.O_RDONLY)
    54  }
    55  
    56  // Open a file for write
    57  func rwHandleCreateWriteOnly(t *testing.T) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) {
    58  	return rwHandleCreateFlags(t, false, "file1", os.O_WRONLY|os.O_CREATE)
    59  }
    60  
    61  // read data from the string
    62  func rwReadString(t *testing.T, fh *RWFileHandle, n int) string {
    63  	buf := make([]byte, n)
    64  	n, err := fh.Read(buf)
    65  	if err != io.EOF {
    66  		assert.NoError(t, err)
    67  	}
    68  	return string(buf[:n])
    69  }
    70  
    71  func TestRWFileHandleMethodsRead(t *testing.T) {
    72  	_, _, fh := rwHandleCreateReadOnly(t)
    73  
    74  	// String
    75  	assert.Equal(t, "dir/file1 (rw)", fh.String())
    76  	assert.Equal(t, "<nil *RWFileHandle>", (*RWFileHandle)(nil).String())
    77  	assert.Equal(t, "<nil *RWFileHandle.file>", new(RWFileHandle).String())
    78  
    79  	// Node
    80  	node := fh.Node()
    81  	assert.Equal(t, "file1", node.Name())
    82  
    83  	// Size
    84  	assert.Equal(t, int64(16), fh.Size())
    85  
    86  	// Read 1
    87  	assert.Equal(t, "0", rwReadString(t, fh, 1))
    88  
    89  	// Read remainder
    90  	assert.Equal(t, "123456789abcdef", rwReadString(t, fh, 256))
    91  
    92  	// Read EOF
    93  	buf := make([]byte, 16)
    94  	_, err := fh.Read(buf)
    95  	assert.Equal(t, io.EOF, err)
    96  
    97  	// Sync
    98  	err = fh.Sync()
    99  	assert.NoError(t, err)
   100  
   101  	// Stat
   102  	var fi os.FileInfo
   103  	fi, err = fh.Stat()
   104  	assert.NoError(t, err)
   105  	assert.Equal(t, int64(16), fi.Size())
   106  	assert.Equal(t, "file1", fi.Name())
   107  
   108  	// Close
   109  	assert.False(t, fh.closed)
   110  	assert.Equal(t, nil, fh.Close())
   111  	assert.True(t, fh.closed)
   112  
   113  	// Close again
   114  	assert.Equal(t, ECLOSED, fh.Close())
   115  }
   116  
   117  func TestRWFileHandleSeek(t *testing.T) {
   118  	_, _, fh := rwHandleCreateReadOnly(t)
   119  
   120  	assert.Equal(t, fh.opened, false)
   121  
   122  	// Check null seeks don't open the file
   123  	n, err := fh.Seek(0, io.SeekStart)
   124  	assert.NoError(t, err)
   125  	assert.Equal(t, int64(0), n)
   126  	assert.Equal(t, fh.opened, false)
   127  	n, err = fh.Seek(0, io.SeekCurrent)
   128  	assert.NoError(t, err)
   129  	assert.Equal(t, int64(0), n)
   130  	assert.Equal(t, fh.opened, false)
   131  
   132  	assert.Equal(t, "0", rwReadString(t, fh, 1))
   133  
   134  	// 0 means relative to the origin of the file,
   135  	n, err = fh.Seek(5, io.SeekStart)
   136  	assert.NoError(t, err)
   137  	assert.Equal(t, int64(5), n)
   138  	assert.Equal(t, "5", rwReadString(t, fh, 1))
   139  
   140  	// 1 means relative to the current offset
   141  	n, err = fh.Seek(-3, io.SeekCurrent)
   142  	assert.NoError(t, err)
   143  	assert.Equal(t, int64(3), n)
   144  	assert.Equal(t, "3", rwReadString(t, fh, 1))
   145  
   146  	// 2 means relative to the end.
   147  	n, err = fh.Seek(-3, io.SeekEnd)
   148  	assert.NoError(t, err)
   149  	assert.Equal(t, int64(13), n)
   150  	assert.Equal(t, "d", rwReadString(t, fh, 1))
   151  
   152  	// Seek off the end
   153  	_, err = fh.Seek(100, io.SeekStart)
   154  	assert.NoError(t, err)
   155  
   156  	// Get the error on read
   157  	buf := make([]byte, 16)
   158  	l, err := fh.Read(buf)
   159  	assert.Equal(t, io.EOF, err)
   160  	assert.Equal(t, 0, l)
   161  
   162  	// Close
   163  	assert.Equal(t, nil, fh.Close())
   164  }
   165  
   166  func TestRWFileHandleReadAt(t *testing.T) {
   167  	_, _, fh := rwHandleCreateReadOnly(t)
   168  
   169  	// read from start
   170  	buf := make([]byte, 1)
   171  	n, err := fh.ReadAt(buf, 0)
   172  	require.NoError(t, err)
   173  	assert.Equal(t, 1, n)
   174  	assert.Equal(t, "0", string(buf[:n]))
   175  
   176  	// seek forwards
   177  	n, err = fh.ReadAt(buf, 5)
   178  	require.NoError(t, err)
   179  	assert.Equal(t, 1, n)
   180  	assert.Equal(t, "5", string(buf[:n]))
   181  
   182  	// seek backwards
   183  	n, err = fh.ReadAt(buf, 1)
   184  	require.NoError(t, err)
   185  	assert.Equal(t, 1, n)
   186  	assert.Equal(t, "1", string(buf[:n]))
   187  
   188  	// read exactly to the end
   189  	buf = make([]byte, 6)
   190  	n, err = fh.ReadAt(buf, 10)
   191  	require.NoError(t, err)
   192  	assert.Equal(t, 6, n)
   193  	assert.Equal(t, "abcdef", string(buf[:n]))
   194  
   195  	// read off the end
   196  	buf = make([]byte, 256)
   197  	n, err = fh.ReadAt(buf, 10)
   198  	assert.Equal(t, io.EOF, err)
   199  	assert.Equal(t, 6, n)
   200  	assert.Equal(t, "abcdef", string(buf[:n]))
   201  
   202  	// read starting off the end
   203  	n, err = fh.ReadAt(buf, 100)
   204  	assert.Equal(t, io.EOF, err)
   205  	assert.Equal(t, 0, n)
   206  
   207  	// Properly close the file
   208  	assert.NoError(t, fh.Close())
   209  
   210  	// check reading on closed file
   211  	_, err = fh.ReadAt(buf, 100)
   212  	assert.Equal(t, ECLOSED, err)
   213  }
   214  
   215  func TestRWFileHandleFlushRead(t *testing.T) {
   216  	_, _, fh := rwHandleCreateReadOnly(t)
   217  
   218  	// Check Flush does nothing if read not called
   219  	err := fh.Flush()
   220  	assert.NoError(t, err)
   221  	assert.False(t, fh.closed)
   222  
   223  	// Read data
   224  	buf := make([]byte, 256)
   225  	n, err := fh.Read(buf)
   226  	assert.True(t, err == io.EOF || err == nil)
   227  	assert.Equal(t, 16, n)
   228  
   229  	// Check Flush does nothing if read called
   230  	err = fh.Flush()
   231  	assert.NoError(t, err)
   232  	assert.False(t, fh.closed)
   233  
   234  	// Check flush does nothing if called again
   235  	err = fh.Flush()
   236  	assert.NoError(t, err)
   237  	assert.False(t, fh.closed)
   238  
   239  	// Properly close the file
   240  	assert.NoError(t, fh.Close())
   241  }
   242  
   243  func TestRWFileHandleReleaseRead(t *testing.T) {
   244  	_, _, fh := rwHandleCreateReadOnly(t)
   245  
   246  	// Read data
   247  	buf := make([]byte, 256)
   248  	n, err := fh.Read(buf)
   249  	assert.True(t, err == io.EOF || err == nil)
   250  	assert.Equal(t, 16, n)
   251  
   252  	// Check Release closes file
   253  	err = fh.Release()
   254  	assert.NoError(t, err)
   255  	assert.True(t, fh.closed)
   256  
   257  	// Check Release does nothing if called again
   258  	err = fh.Release()
   259  	assert.NoError(t, err)
   260  	assert.True(t, fh.closed)
   261  }
   262  
   263  /// ------------------------------------------------------------
   264  
   265  func TestRWFileHandleMethodsWrite(t *testing.T) {
   266  	r, vfs, fh := rwHandleCreateWriteOnly(t)
   267  
   268  	// String
   269  	assert.Equal(t, "file1 (rw)", fh.String())
   270  	assert.Equal(t, "<nil *RWFileHandle>", (*RWFileHandle)(nil).String())
   271  	assert.Equal(t, "<nil *RWFileHandle.file>", new(RWFileHandle).String())
   272  
   273  	// Node
   274  	node := fh.Node()
   275  	assert.Equal(t, "file1", node.Name())
   276  
   277  	offset := func() int64 {
   278  		n, err := fh.Seek(0, io.SeekCurrent)
   279  		require.NoError(t, err)
   280  		return n
   281  	}
   282  
   283  	// Offset #1
   284  	assert.Equal(t, int64(0), offset())
   285  	assert.Equal(t, int64(0), node.Size())
   286  
   287  	// Size #1
   288  	assert.Equal(t, int64(0), fh.Size())
   289  
   290  	// Write
   291  	n, err := fh.Write([]byte("hello"))
   292  	assert.NoError(t, err)
   293  	assert.Equal(t, 5, n)
   294  
   295  	// Offset #2
   296  	assert.Equal(t, int64(5), offset())
   297  	assert.Equal(t, int64(5), node.Size())
   298  
   299  	// Size #2
   300  	assert.Equal(t, int64(5), fh.Size())
   301  
   302  	// WriteString
   303  	n, err = fh.WriteString(" world!")
   304  	assert.NoError(t, err)
   305  	assert.Equal(t, 7, n)
   306  
   307  	// Sync
   308  	err = fh.Sync()
   309  	assert.NoError(t, err)
   310  
   311  	// Stat
   312  	var fi os.FileInfo
   313  	fi, err = fh.Stat()
   314  	assert.NoError(t, err)
   315  	assert.Equal(t, int64(12), fi.Size())
   316  	assert.Equal(t, "file1", fi.Name())
   317  
   318  	// Truncate
   319  	err = fh.Truncate(11)
   320  	assert.NoError(t, err)
   321  
   322  	// Close
   323  	assert.NoError(t, fh.Close())
   324  
   325  	// Check double close
   326  	err = fh.Close()
   327  	assert.Equal(t, ECLOSED, err)
   328  
   329  	// check vfs
   330  	root, err := vfs.Root()
   331  	require.NoError(t, err)
   332  	checkListing(t, root, []string{"file1,11,false"})
   333  
   334  	// check the underlying r.Fremote but not the modtime
   335  	file1 := fstest.NewItem("file1", "hello world", t1)
   336  	vfs.WaitForWriters(waitForWritersDelay)
   337  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported)
   338  }
   339  
   340  func TestRWFileHandleWriteAt(t *testing.T) {
   341  	r, vfs, fh := rwHandleCreateWriteOnly(t)
   342  
   343  	offset := func() int64 {
   344  		n, err := fh.Seek(0, io.SeekCurrent)
   345  		require.NoError(t, err)
   346  		return n
   347  	}
   348  
   349  	// Name
   350  	assert.Equal(t, "file1", fh.Name())
   351  
   352  	// Preconditions
   353  	assert.Equal(t, int64(0), offset())
   354  	assert.True(t, fh.opened)
   355  	assert.False(t, fh.writeCalled)
   356  
   357  	// Write the data
   358  	n, err := fh.WriteAt([]byte("hello**"), 0)
   359  	assert.NoError(t, err)
   360  	assert.Equal(t, 7, n)
   361  
   362  	// After write
   363  	assert.Equal(t, int64(0), offset())
   364  	assert.True(t, fh.writeCalled)
   365  
   366  	// Write more data
   367  	n, err = fh.WriteAt([]byte(" world"), 5)
   368  	assert.NoError(t, err)
   369  	assert.Equal(t, 6, n)
   370  
   371  	// Close
   372  	assert.NoError(t, fh.Close())
   373  
   374  	// Check can't write on closed handle
   375  	n, err = fh.WriteAt([]byte("hello"), 0)
   376  	assert.Equal(t, ECLOSED, err)
   377  	assert.Equal(t, 0, n)
   378  
   379  	// check vfs
   380  	root, err := vfs.Root()
   381  	require.NoError(t, err)
   382  	checkListing(t, root, []string{"file1,11,false"})
   383  
   384  	// check the underlying r.Fremote but not the modtime
   385  	file1 := fstest.NewItem("file1", "hello world", t1)
   386  	vfs.WaitForWriters(waitForWritersDelay)
   387  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported)
   388  }
   389  
   390  func TestRWFileHandleWriteNoWrite(t *testing.T) {
   391  	r, vfs, fh := rwHandleCreateWriteOnly(t)
   392  
   393  	// Close the file without writing to it
   394  	err := fh.Close()
   395  	if errors.Is(err, fs.ErrorCantUploadEmptyFiles) {
   396  		t.Logf("skipping test: %v", err)
   397  		return
   398  	}
   399  	assert.NoError(t, err)
   400  
   401  	// Create a different file (not in the cache)
   402  	h, err := vfs.OpenFile("file2", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
   403  	require.NoError(t, err)
   404  
   405  	// Close it with Flush and Release
   406  	err = h.Flush()
   407  	assert.NoError(t, err)
   408  	err = h.Release()
   409  	assert.NoError(t, err)
   410  
   411  	// check vfs
   412  	root, err := vfs.Root()
   413  	require.NoError(t, err)
   414  	checkListing(t, root, []string{"file1,0,false", "file2,0,false"})
   415  
   416  	// check the underlying r.Fremote but not the modtime
   417  	file1 := fstest.NewItem("file1", "", t1)
   418  	file2 := fstest.NewItem("file2", "", t1)
   419  	vfs.WaitForWriters(waitForWritersDelay)
   420  	fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file2}, []string{}, fs.ModTimeNotSupported)
   421  }
   422  
   423  func TestRWFileHandleFlushWrite(t *testing.T) {
   424  	_, _, fh := rwHandleCreateWriteOnly(t)
   425  
   426  	// Check that the file has been create and is open
   427  	assert.True(t, fh.opened)
   428  
   429  	// Write some data
   430  	n, err := fh.Write([]byte("hello"))
   431  	assert.NoError(t, err)
   432  	assert.Equal(t, 5, n)
   433  	assert.True(t, fh.opened)
   434  
   435  	// Check Flush does not close file if write called
   436  	err = fh.Flush()
   437  	assert.NoError(t, err)
   438  	assert.False(t, fh.closed)
   439  
   440  	// Check flush does nothing if called again
   441  	err = fh.Flush()
   442  	assert.NoError(t, err)
   443  	assert.False(t, fh.closed)
   444  
   445  	// Check that Close closes the file
   446  	err = fh.Close()
   447  	assert.NoError(t, err)
   448  	assert.True(t, fh.closed)
   449  }
   450  
   451  func TestRWFileHandleReleaseWrite(t *testing.T) {
   452  	_, _, fh := rwHandleCreateWriteOnly(t)
   453  
   454  	// Write some data
   455  	n, err := fh.Write([]byte("hello"))
   456  	assert.NoError(t, err)
   457  	assert.Equal(t, 5, n)
   458  
   459  	// Check Release closes file
   460  	err = fh.Release()
   461  	assert.NoError(t, err)
   462  	assert.True(t, fh.closed)
   463  
   464  	// Check Release does nothing if called again
   465  	err = fh.Release()
   466  	assert.NoError(t, err)
   467  	assert.True(t, fh.closed)
   468  }
   469  
   470  // check the size of the file through the open file (if not nil) and via stat
   471  func assertSize(t *testing.T, vfs *VFS, fh *RWFileHandle, filepath string, size int64) {
   472  	if fh != nil {
   473  		assert.Equal(t, size, fh.Size())
   474  	}
   475  	fi, err := vfs.Stat(filepath)
   476  	require.NoError(t, err)
   477  	assert.Equal(t, size, fi.Size())
   478  }
   479  
   480  func TestRWFileHandleSizeTruncateExisting(t *testing.T) {
   481  	_, vfs, fh := rwHandleCreateFlags(t, true, "dir/file1", os.O_WRONLY|os.O_TRUNC)
   482  
   483  	// check initial size after opening
   484  	assertSize(t, vfs, fh, "dir/file1", 0)
   485  
   486  	// write some bytes
   487  	n, err := fh.Write([]byte("hello"))
   488  	assert.NoError(t, err)
   489  	assert.Equal(t, 5, n)
   490  
   491  	// check size after writing
   492  	assertSize(t, vfs, fh, "dir/file1", 5)
   493  
   494  	// close
   495  	assert.NoError(t, fh.Close())
   496  
   497  	// check size after close
   498  	assertSize(t, vfs, nil, "dir/file1", 5)
   499  }
   500  
   501  func TestRWFileHandleSizeCreateExisting(t *testing.T) {
   502  	_, vfs, fh := rwHandleCreateFlags(t, true, "dir/file1", os.O_WRONLY|os.O_CREATE)
   503  
   504  	// check initial size after opening
   505  	assertSize(t, vfs, fh, "dir/file1", 16)
   506  
   507  	// write some bytes
   508  	n, err := fh.Write([]byte("hello"))
   509  	assert.NoError(t, err)
   510  	assert.Equal(t, 5, n)
   511  
   512  	// check size after writing
   513  	assertSize(t, vfs, fh, "dir/file1", 16)
   514  
   515  	// write some more bytes
   516  	n, err = fh.Write([]byte("helloHELLOhello"))
   517  	assert.NoError(t, err)
   518  	assert.Equal(t, 15, n)
   519  
   520  	// check size after writing
   521  	assertSize(t, vfs, fh, "dir/file1", 20)
   522  
   523  	// close
   524  	assert.NoError(t, fh.Close())
   525  
   526  	// check size after close
   527  	assertSize(t, vfs, nil, "dir/file1", 20)
   528  }
   529  
   530  func TestRWFileHandleSizeCreateNew(t *testing.T) {
   531  	_, vfs, fh := rwHandleCreateFlags(t, false, "file1", os.O_WRONLY|os.O_CREATE)
   532  
   533  	// check initial size after opening
   534  	assertSize(t, vfs, fh, "file1", 0)
   535  
   536  	// write some bytes
   537  	n, err := fh.Write([]byte("hello"))
   538  	assert.NoError(t, err)
   539  	assert.Equal(t, 5, n)
   540  
   541  	// check size after writing
   542  	assertSize(t, vfs, fh, "file1", 5)
   543  
   544  	// check size after writing
   545  	assertSize(t, vfs, fh, "file1", 5)
   546  
   547  	// close
   548  	assert.NoError(t, fh.Close())
   549  
   550  	// check size after close
   551  	assertSize(t, vfs, nil, "file1", 5)
   552  }
   553  
   554  func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) {
   555  	fileName := "open-test-file"
   556  
   557  	// Make sure we delete the file on failure too
   558  	defer func() {
   559  		_ = vfs.Remove(fileName)
   560  	}()
   561  
   562  	// first try with file not existing
   563  	_, err := vfs.Stat(fileName)
   564  	require.True(t, os.IsNotExist(err))
   565  
   566  	f, openNonExistentErr := vfs.OpenFile(fileName, test.flags, 0666)
   567  
   568  	var readNonExistentErr error
   569  	var writeNonExistentErr error
   570  	if openNonExistentErr == nil {
   571  		// read some bytes
   572  		buf := []byte{0, 0}
   573  		_, readNonExistentErr = f.Read(buf)
   574  
   575  		// write some bytes
   576  		_, writeNonExistentErr = f.Write([]byte("hello"))
   577  
   578  		// close
   579  		err = f.Close()
   580  		require.NoError(t, err)
   581  	}
   582  
   583  	// write the file
   584  	f, err = vfs.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0777)
   585  	require.NoError(t, err)
   586  	_, err = f.Write([]byte("hello"))
   587  	require.NoError(t, err)
   588  	err = f.Close()
   589  	require.NoError(t, err)
   590  
   591  	// then open file and try with file existing
   592  
   593  	f, openExistingErr := vfs.OpenFile(fileName, test.flags, 0666)
   594  	var readExistingErr error
   595  	var writeExistingErr error
   596  	if openExistingErr == nil {
   597  		// read some bytes
   598  		buf := []byte{0, 0}
   599  		_, readExistingErr = f.Read(buf)
   600  
   601  		// write some bytes
   602  		_, writeExistingErr = f.Write([]byte("HEL"))
   603  
   604  		// close
   605  		err = f.Close()
   606  		require.NoError(t, err)
   607  	}
   608  
   609  	// read the file
   610  	f, err = vfs.OpenFile(fileName, os.O_RDONLY, 0)
   611  	require.NoError(t, err)
   612  	buf, err := io.ReadAll(f)
   613  	require.NoError(t, err)
   614  	err = f.Close()
   615  	require.NoError(t, err)
   616  	contents := string(buf)
   617  
   618  	// remove file
   619  	node, err := vfs.Stat(fileName)
   620  	require.NoError(t, err)
   621  	err = node.Remove()
   622  	require.NoError(t, err)
   623  
   624  	// check
   625  	assert.Equal(t, test.openNonExistentErr, openNonExistentErr, "openNonExistentErr: want=%v, got=%v", test.openNonExistentErr, openNonExistentErr)
   626  	assert.Equal(t, test.readNonExistentErr, readNonExistentErr, "readNonExistentErr: want=%v, got=%v", test.readNonExistentErr, readNonExistentErr)
   627  	assert.Equal(t, test.writeNonExistentErr, writeNonExistentErr, "writeNonExistentErr: want=%v, got=%v", test.writeNonExistentErr, writeNonExistentErr)
   628  	assert.Equal(t, test.openExistingErr, openExistingErr, "openExistingErr: want=%v, got=%v", test.openExistingErr, openExistingErr)
   629  	assert.Equal(t, test.readExistingErr, readExistingErr, "readExistingErr: want=%v, got=%v", test.readExistingErr, readExistingErr)
   630  	assert.Equal(t, test.writeExistingErr, writeExistingErr, "writeExistingErr: want=%v, got=%v", test.writeExistingErr, writeExistingErr)
   631  	assert.Equal(t, test.contents, contents)
   632  }
   633  
   634  func TestRWFileHandleOpenTests(t *testing.T) {
   635  	for _, cacheMode := range []vfscommon.CacheMode{vfscommon.CacheModeWrites, vfscommon.CacheModeFull} {
   636  		t.Run(cacheMode.String(), func(t *testing.T) {
   637  			opt := vfscommon.DefaultOpt
   638  			opt.CacheMode = cacheMode
   639  			opt.WriteBack = writeBackDelay
   640  			_, vfs := newTestVFSOpt(t, &opt)
   641  
   642  			for _, test := range openTests {
   643  				t.Run(test.what, func(t *testing.T) {
   644  					testRWFileHandleOpenTest(t, vfs, &test)
   645  				})
   646  			}
   647  		})
   648  	}
   649  }
   650  
   651  // tests mod time on open files
   652  func TestRWFileModTimeWithOpenWriters(t *testing.T) {
   653  	r, vfs, fh := rwHandleCreateWriteOnly(t)
   654  	if !canSetModTime(t, r) {
   655  		t.Skip("can't set mod time")
   656  	}
   657  
   658  	mtime := time.Date(2012, time.November, 18, 17, 32, 31, 0, time.UTC)
   659  
   660  	_, err := fh.Write([]byte{104, 105})
   661  	require.NoError(t, err)
   662  
   663  	err = fh.Node().SetModTime(mtime)
   664  	require.NoError(t, err)
   665  
   666  	// Using Flush/Release to mimic mount instead of Close
   667  
   668  	err = fh.Flush()
   669  	require.NoError(t, err)
   670  
   671  	err = fh.Release()
   672  	require.NoError(t, err)
   673  
   674  	info, err := vfs.Stat("file1")
   675  	require.NoError(t, err)
   676  
   677  	if r.Fremote.Precision() != fs.ModTimeNotSupported {
   678  		// avoid errors because of timezone differences
   679  		assert.Equal(t, info.ModTime().Unix(), mtime.Unix(), fmt.Sprintf("Time mismatch: %v != %v", info.ModTime(), mtime))
   680  	}
   681  
   682  	file1 := fstest.NewItem("file1", "hi", mtime)
   683  	vfs.WaitForWriters(waitForWritersDelay)
   684  	r.CheckRemoteItems(t, file1)
   685  }
   686  
   687  func TestRWCacheRename(t *testing.T) {
   688  	opt := vfscommon.DefaultOpt
   689  	opt.CacheMode = vfscommon.CacheModeFull
   690  	opt.WriteBack = writeBackDelay
   691  	r, vfs := newTestVFSOpt(t, &opt)
   692  
   693  	if !operations.CanServerSideMove(r.Fremote) {
   694  		t.Skip("skip as can't rename files")
   695  	}
   696  
   697  	h, err := vfs.OpenFile("rename_me", os.O_WRONLY|os.O_CREATE, 0777)
   698  	require.NoError(t, err)
   699  	_, err = h.WriteString("hello")
   700  	require.NoError(t, err)
   701  	fh, ok := h.(*RWFileHandle)
   702  	require.True(t, ok)
   703  
   704  	err = fh.Sync()
   705  	require.NoError(t, err)
   706  	err = fh.Close()
   707  	require.NoError(t, err)
   708  
   709  	assert.True(t, vfs.cache.Exists("rename_me"))
   710  
   711  	err = vfs.Rename("rename_me", "i_was_renamed")
   712  	require.NoError(t, err)
   713  
   714  	assert.False(t, vfs.cache.Exists("rename_me"))
   715  	assert.True(t, vfs.cache.Exists("i_was_renamed"))
   716  }
   717  
   718  // Test the cache reading a file that is updated externally
   719  //
   720  // See: https://github.com/rclone/rclone/issues/6053
   721  func TestRWCacheUpdate(t *testing.T) {
   722  	opt := vfscommon.DefaultOpt
   723  	opt.CacheMode = vfscommon.CacheModeFull
   724  	opt.WriteBack = writeBackDelay
   725  	opt.DirCacheTime = 100 * time.Millisecond
   726  	r, vfs := newTestVFSOpt(t, &opt)
   727  
   728  	if r.Fremote.Precision() == fs.ModTimeNotSupported {
   729  		t.Skip("skip as modtime not supported")
   730  	}
   731  
   732  	const filename = "TestRWCacheUpdate"
   733  
   734  	modTime := time.Now().Add(-time.Hour)
   735  	for i := 0; i < 10; i++ {
   736  		modTime = modTime.Add(time.Minute)
   737  		// Refresh test file
   738  		contents := fmt.Sprintf("TestRWCacheUpdate%03d", i)
   739  		// Increase the size for second half of test
   740  		for j := 5; j < i; j++ {
   741  			contents += "*"
   742  		}
   743  		file1 := r.WriteObject(context.Background(), filename, contents, modTime)
   744  		r.CheckRemoteItems(t, file1)
   745  
   746  		// Wait for directory cache to expire
   747  		time.Sleep(2 * opt.DirCacheTime)
   748  
   749  		// Check the file is OK via the VFS
   750  		data, err := vfs.ReadFile(filename)
   751  		require.NoError(t, err)
   752  		require.Equal(t, contents, string(data))
   753  
   754  		// Check Stat
   755  		fi, err := vfs.Stat(filename)
   756  		require.NoError(t, err)
   757  		assert.Equal(t, int64(len(contents)), fi.Size())
   758  		fstest.AssertTimeEqualWithPrecision(t, filename, modTime, fi.ModTime(), r.Fremote.Precision())
   759  	}
   760  }