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 }