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