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 }