github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/vfs/dir_test.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "sort" 8 "testing" 9 "time" 10 11 "github.com/rclone/rclone/fs" 12 "github.com/rclone/rclone/fstest" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func dirCreate(t *testing.T, r *fstest.Run) (*VFS, *Dir, fstest.Item) { 18 vfs := New(r.Fremote, nil) 19 20 file1 := r.WriteObject(context.Background(), "dir/file1", "file1 contents", t1) 21 fstest.CheckItems(t, r.Fremote, file1) 22 23 node, err := vfs.Stat("dir") 24 require.NoError(t, err) 25 require.True(t, node.IsDir()) 26 27 return vfs, node.(*Dir), file1 28 } 29 30 func TestDirMethods(t *testing.T) { 31 r := fstest.NewRun(t) 32 defer r.Finalise() 33 vfs, dir, _ := dirCreate(t, r) 34 35 // String 36 assert.Equal(t, "dir/", dir.String()) 37 assert.Equal(t, "<nil *Dir>", (*Dir)(nil).String()) 38 39 // IsDir 40 assert.Equal(t, true, dir.IsDir()) 41 42 // IsFile 43 assert.Equal(t, false, dir.IsFile()) 44 45 // Mode 46 assert.Equal(t, vfs.Opt.DirPerms, dir.Mode()) 47 48 // Name 49 assert.Equal(t, "dir", dir.Name()) 50 51 // Path 52 assert.Equal(t, "dir", dir.Path()) 53 54 // Sys 55 assert.Equal(t, nil, dir.Sys()) 56 57 // SetSys 58 dir.SetSys(42) 59 assert.Equal(t, 42, dir.Sys()) 60 61 // Inode 62 assert.NotEqual(t, uint64(0), dir.Inode()) 63 64 // Node 65 assert.Equal(t, dir, dir.Node()) 66 67 // ModTime 68 assert.WithinDuration(t, t1, dir.ModTime(), 100*365*24*60*60*time.Second) 69 70 // Size 71 assert.Equal(t, int64(0), dir.Size()) 72 73 // Sync 74 assert.NoError(t, dir.Sync()) 75 76 // DirEntry 77 assert.Equal(t, dir.entry, dir.DirEntry()) 78 79 // VFS 80 assert.Equal(t, vfs, dir.VFS()) 81 } 82 83 func TestDirForgetAll(t *testing.T) { 84 r := fstest.NewRun(t) 85 defer r.Finalise() 86 vfs, dir, file1 := dirCreate(t, r) 87 88 // Make sure / and dir are in cache 89 _, err := vfs.Stat(file1.Path) 90 require.NoError(t, err) 91 92 root, err := vfs.Root() 93 require.NoError(t, err) 94 95 assert.Equal(t, 1, len(root.items)) 96 assert.Equal(t, 1, len(dir.items)) 97 assert.False(t, root.read.IsZero()) 98 assert.False(t, dir.read.IsZero()) 99 100 dir.ForgetAll() 101 assert.Equal(t, 1, len(root.items)) 102 assert.Equal(t, 0, len(dir.items)) 103 assert.False(t, root.read.IsZero()) 104 assert.True(t, dir.read.IsZero()) 105 106 root.ForgetAll() 107 assert.Equal(t, 0, len(root.items)) 108 assert.Equal(t, 0, len(dir.items)) 109 assert.True(t, root.read.IsZero()) 110 } 111 112 func TestDirForgetPath(t *testing.T) { 113 r := fstest.NewRun(t) 114 defer r.Finalise() 115 vfs, dir, file1 := dirCreate(t, r) 116 117 // Make sure / and dir are in cache 118 _, err := vfs.Stat(file1.Path) 119 require.NoError(t, err) 120 121 root, err := vfs.Root() 122 require.NoError(t, err) 123 124 assert.Equal(t, 1, len(root.items)) 125 assert.Equal(t, 1, len(dir.items)) 126 assert.False(t, root.read.IsZero()) 127 assert.False(t, dir.read.IsZero()) 128 129 root.ForgetPath("dir/notfound", fs.EntryObject) 130 assert.Equal(t, 1, len(root.items)) 131 assert.Equal(t, 1, len(dir.items)) 132 assert.False(t, root.read.IsZero()) 133 assert.True(t, dir.read.IsZero()) 134 135 root.ForgetPath("dir", fs.EntryDirectory) 136 assert.Equal(t, 1, len(root.items)) 137 assert.Equal(t, 0, len(dir.items)) 138 assert.True(t, root.read.IsZero()) 139 140 root.ForgetPath("not/in/cache", fs.EntryDirectory) 141 assert.Equal(t, 1, len(root.items)) 142 assert.Equal(t, 0, len(dir.items)) 143 } 144 145 func TestDirWalk(t *testing.T) { 146 r := fstest.NewRun(t) 147 defer r.Finalise() 148 vfs, _, file1 := dirCreate(t, r) 149 150 file2 := r.WriteObject(context.Background(), "fil/a/b/c", "super long file", t1) 151 fstest.CheckItems(t, r.Fremote, file1, file2) 152 153 root, err := vfs.Root() 154 require.NoError(t, err) 155 156 // Forget the cache since we put another object in 157 root.ForgetAll() 158 159 // Read the directories in 160 _, err = vfs.Stat("dir") 161 require.NoError(t, err) 162 _, err = vfs.Stat("fil/a/b") 163 require.NoError(t, err) 164 fil, err := vfs.Stat("fil") 165 require.NoError(t, err) 166 167 var result []string 168 fn := func(d *Dir) { 169 result = append(result, d.path) 170 } 171 172 result = nil 173 root.walk(fn) 174 sort.Strings(result) // sort as there is a map traversal involved 175 assert.Equal(t, []string{"", "dir", "fil", "fil/a", "fil/a/b"}, result) 176 177 assert.Nil(t, root.cachedDir("not found")) 178 if dir := root.cachedDir("dir"); assert.NotNil(t, dir) { 179 result = nil 180 dir.walk(fn) 181 assert.Equal(t, []string{"dir"}, result) 182 } 183 if dir := root.cachedDir("fil"); assert.NotNil(t, dir) { 184 result = nil 185 dir.walk(fn) 186 assert.Equal(t, []string{"fil/a/b", "fil/a", "fil"}, result) 187 } 188 if dir := fil.(*Dir); assert.NotNil(t, dir) { 189 result = nil 190 dir.walk(fn) 191 assert.Equal(t, []string{"fil/a/b", "fil/a", "fil"}, result) 192 } 193 if dir := root.cachedDir("fil/a"); assert.NotNil(t, dir) { 194 result = nil 195 dir.walk(fn) 196 assert.Equal(t, []string{"fil/a/b", "fil/a"}, result) 197 } 198 if dir := fil.(*Dir).cachedDir("a"); assert.NotNil(t, dir) { 199 result = nil 200 dir.walk(fn) 201 assert.Equal(t, []string{"fil/a/b", "fil/a"}, result) 202 } 203 if dir := root.cachedDir("fil/a"); assert.NotNil(t, dir) { 204 result = nil 205 dir.walk(fn) 206 assert.Equal(t, []string{"fil/a/b", "fil/a"}, result) 207 } 208 if dir := root.cachedDir("fil/a/b"); assert.NotNil(t, dir) { 209 result = nil 210 dir.walk(fn) 211 assert.Equal(t, []string{"fil/a/b"}, result) 212 } 213 } 214 215 func TestDirSetModTime(t *testing.T) { 216 r := fstest.NewRun(t) 217 defer r.Finalise() 218 vfs, dir, _ := dirCreate(t, r) 219 220 err := dir.SetModTime(t1) 221 require.NoError(t, err) 222 assert.WithinDuration(t, t1, dir.ModTime(), time.Second) 223 224 err = dir.SetModTime(t2) 225 require.NoError(t, err) 226 assert.WithinDuration(t, t2, dir.ModTime(), time.Second) 227 228 vfs.Opt.ReadOnly = true 229 err = dir.SetModTime(t2) 230 assert.Equal(t, EROFS, err) 231 } 232 233 func TestDirStat(t *testing.T) { 234 r := fstest.NewRun(t) 235 defer r.Finalise() 236 _, dir, _ := dirCreate(t, r) 237 238 node, err := dir.Stat("file1") 239 require.NoError(t, err) 240 _, ok := node.(*File) 241 assert.True(t, ok) 242 assert.Equal(t, int64(14), node.Size()) 243 assert.Equal(t, "file1", node.Name()) 244 245 _, err = dir.Stat("not found") 246 assert.Equal(t, ENOENT, err) 247 } 248 249 // This lists dir and checks the listing is as expected 250 func checkListing(t *testing.T, dir *Dir, want []string) { 251 var got []string 252 nodes, err := dir.ReadDirAll() 253 require.NoError(t, err) 254 for _, node := range nodes { 255 got = append(got, fmt.Sprintf("%s,%d,%v", node.Name(), node.Size(), node.IsDir())) 256 } 257 assert.Equal(t, want, got) 258 } 259 260 func TestDirReadDirAll(t *testing.T) { 261 r := fstest.NewRun(t) 262 defer r.Finalise() 263 vfs := New(r.Fremote, nil) 264 265 file1 := r.WriteObject(context.Background(), "dir/file1", "file1 contents", t1) 266 file2 := r.WriteObject(context.Background(), "dir/file2", "file2- contents", t2) 267 file3 := r.WriteObject(context.Background(), "dir/subdir/file3", "file3-- contents", t3) 268 fstest.CheckItems(t, r.Fremote, file1, file2, file3) 269 270 node, err := vfs.Stat("dir") 271 require.NoError(t, err) 272 dir := node.(*Dir) 273 274 checkListing(t, dir, []string{"file1,14,false", "file2,15,false", "subdir,0,true"}) 275 276 node, err = vfs.Stat("") 277 require.NoError(t, err) 278 dir = node.(*Dir) 279 280 checkListing(t, dir, []string{"dir,0,true"}) 281 282 node, err = vfs.Stat("dir/subdir") 283 require.NoError(t, err) 284 dir = node.(*Dir) 285 286 checkListing(t, dir, []string{"file3,16,false"}) 287 } 288 289 func TestDirOpen(t *testing.T) { 290 r := fstest.NewRun(t) 291 defer r.Finalise() 292 _, dir, _ := dirCreate(t, r) 293 294 fd, err := dir.Open(os.O_RDONLY) 295 require.NoError(t, err) 296 _, ok := fd.(*DirHandle) 297 assert.True(t, ok) 298 require.NoError(t, fd.Close()) 299 300 _, err = dir.Open(os.O_WRONLY) 301 assert.Equal(t, EPERM, err) 302 } 303 304 func TestDirCreate(t *testing.T) { 305 r := fstest.NewRun(t) 306 defer r.Finalise() 307 vfs, dir, _ := dirCreate(t, r) 308 309 file, err := dir.Create("potato", os.O_WRONLY|os.O_CREATE) 310 require.NoError(t, err) 311 assert.Equal(t, int64(0), file.Size()) 312 313 fd, err := file.Open(os.O_WRONLY | os.O_CREATE) 314 require.NoError(t, err) 315 316 // FIXME Note that this fails with the current implementation 317 // until the file has been opened. 318 319 // file2, err := vfs.Stat("dir/potato") 320 // require.NoError(t, err) 321 // assert.Equal(t, file, file2) 322 323 n, err := fd.Write([]byte("hello")) 324 require.NoError(t, err) 325 assert.Equal(t, 5, n) 326 327 require.NoError(t, fd.Close()) 328 329 file2, err := vfs.Stat("dir/potato") 330 require.NoError(t, err) 331 assert.Equal(t, int64(5), file2.Size()) 332 333 vfs.Opt.ReadOnly = true 334 _, err = dir.Create("sausage", os.O_WRONLY|os.O_CREATE) 335 assert.Equal(t, EROFS, err) 336 } 337 338 func TestDirMkdir(t *testing.T) { 339 r := fstest.NewRun(t) 340 defer r.Finalise() 341 vfs, dir, file1 := dirCreate(t, r) 342 343 _, err := dir.Mkdir("file1") 344 assert.Error(t, err) 345 346 sub, err := dir.Mkdir("sub") 347 assert.NoError(t, err) 348 349 // check the vfs 350 checkListing(t, dir, []string{"file1,14,false", "sub,0,true"}) 351 checkListing(t, sub, []string(nil)) 352 353 // check the underlying r.Fremote 354 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir", "dir/sub"}, r.Fremote.Precision()) 355 356 vfs.Opt.ReadOnly = true 357 _, err = dir.Mkdir("sausage") 358 assert.Equal(t, EROFS, err) 359 } 360 361 func TestDirMkdirSub(t *testing.T) { 362 r := fstest.NewRun(t) 363 defer r.Finalise() 364 vfs, dir, file1 := dirCreate(t, r) 365 366 _, err := dir.Mkdir("file1") 367 assert.Error(t, err) 368 369 sub, err := dir.Mkdir("sub") 370 assert.NoError(t, err) 371 372 subsub, err := sub.Mkdir("subsub") 373 assert.NoError(t, err) 374 375 // check the vfs 376 checkListing(t, dir, []string{"file1,14,false", "sub,0,true"}) 377 checkListing(t, sub, []string{"subsub,0,true"}) 378 checkListing(t, subsub, []string(nil)) 379 380 // check the underlying r.Fremote 381 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir", "dir/sub", "dir/sub/subsub"}, r.Fremote.Precision()) 382 383 vfs.Opt.ReadOnly = true 384 _, err = dir.Mkdir("sausage") 385 assert.Equal(t, EROFS, err) 386 } 387 388 func TestDirRemove(t *testing.T) { 389 r := fstest.NewRun(t) 390 defer r.Finalise() 391 vfs, dir, _ := dirCreate(t, r) 392 393 // check directory is there 394 node, err := vfs.Stat("dir") 395 require.NoError(t, err) 396 assert.True(t, node.IsDir()) 397 398 err = dir.Remove() 399 assert.Equal(t, ENOTEMPTY, err) 400 401 // Delete the sub file 402 node, err = vfs.Stat("dir/file1") 403 require.NoError(t, err) 404 err = node.Remove() 405 require.NoError(t, err) 406 407 // Remove the now empty directory 408 err = dir.Remove() 409 require.NoError(t, err) 410 411 // check directory is not there 412 _, err = vfs.Stat("dir") 413 assert.Equal(t, ENOENT, err) 414 415 // check the vfs 416 root, err := vfs.Root() 417 require.NoError(t, err) 418 checkListing(t, root, []string(nil)) 419 420 // check the underlying r.Fremote 421 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, r.Fremote.Precision()) 422 423 // read only check 424 vfs.Opt.ReadOnly = true 425 err = dir.Remove() 426 assert.Equal(t, EROFS, err) 427 } 428 429 func TestDirRemoveAll(t *testing.T) { 430 r := fstest.NewRun(t) 431 defer r.Finalise() 432 vfs, dir, _ := dirCreate(t, r) 433 434 // Remove the directory and contents 435 err := dir.RemoveAll() 436 require.NoError(t, err) 437 438 // check the vfs 439 root, err := vfs.Root() 440 require.NoError(t, err) 441 checkListing(t, root, []string(nil)) 442 443 // check the underlying r.Fremote 444 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{}, r.Fremote.Precision()) 445 446 // read only check 447 vfs.Opt.ReadOnly = true 448 err = dir.RemoveAll() 449 assert.Equal(t, EROFS, err) 450 } 451 452 func TestDirRemoveName(t *testing.T) { 453 r := fstest.NewRun(t) 454 defer r.Finalise() 455 vfs, dir, _ := dirCreate(t, r) 456 457 err := dir.RemoveName("file1") 458 require.NoError(t, err) 459 checkListing(t, dir, []string(nil)) 460 root, err := vfs.Root() 461 require.NoError(t, err) 462 checkListing(t, root, []string{"dir,0,true"}) 463 464 // check the underlying r.Fremote 465 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{}, []string{"dir"}, r.Fremote.Precision()) 466 467 // read only check 468 vfs.Opt.ReadOnly = true 469 err = dir.RemoveName("potato") 470 assert.Equal(t, EROFS, err) 471 } 472 473 func TestDirRename(t *testing.T) { 474 r := fstest.NewRun(t) 475 defer r.Finalise() 476 477 features := r.Fremote.Features() 478 if features.DirMove == nil && features.Move == nil && features.Copy == nil { 479 return // skip as can't rename directories 480 } 481 482 vfs, dir, file1 := dirCreate(t, r) 483 file3 := r.WriteObject(context.Background(), "dir/file3", "file3 contents!", t1) 484 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file3}, []string{"dir"}, r.Fremote.Precision()) 485 486 root, err := vfs.Root() 487 require.NoError(t, err) 488 489 err = dir.Rename("not found", "tuba", dir) 490 assert.Equal(t, ENOENT, err) 491 492 // Rename a directory 493 err = root.Rename("dir", "dir2", root) 494 assert.NoError(t, err) 495 checkListing(t, root, []string{"dir2,0,true"}) 496 checkListing(t, dir, []string{"file1,14,false", "file3,15,false"}) 497 498 // check the underlying r.Fremote 499 file1.Path = "dir2/file1" 500 file3.Path = "dir2/file3" 501 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file3}, []string{"dir2"}, r.Fremote.Precision()) 502 503 // refetch dir 504 node, err := vfs.Stat("dir2") 505 assert.NoError(t, err) 506 dir = node.(*Dir) 507 508 // Rename a file 509 err = dir.Rename("file1", "file2", root) 510 assert.NoError(t, err) 511 checkListing(t, root, []string{"dir2,0,true", "file2,14,false"}) 512 checkListing(t, dir, []string{"file3,15,false"}) 513 514 // check the underlying r.Fremote 515 file1.Path = "file2" 516 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file3}, []string{"dir2"}, r.Fremote.Precision()) 517 518 // Rename a file on top of another file 519 err = root.Rename("file2", "file3", dir) 520 assert.NoError(t, err) 521 checkListing(t, root, []string{"dir2,0,true"}) 522 checkListing(t, dir, []string{"file3,14,false"}) 523 524 // check the underlying r.Fremote 525 file1.Path = "dir2/file3" 526 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir2"}, r.Fremote.Precision()) 527 528 // rename an empty directory 529 _, err = root.Mkdir("empty directory") 530 assert.NoError(t, err) 531 checkListing(t, root, []string{ 532 "dir2,0,true", 533 "empty directory,0,true", 534 }) 535 err = root.Rename("empty directory", "renamed empty directory", root) 536 assert.NoError(t, err) 537 checkListing(t, root, []string{ 538 "dir2,0,true", 539 "renamed empty directory,0,true", 540 }) 541 // ...we don't check the underlying f.Fremote because on 542 // bucket based remotes the directory won't be there 543 544 // read only check 545 vfs.Opt.ReadOnly = true 546 err = dir.Rename("potato", "tuba", dir) 547 assert.Equal(t, EROFS, err) 548 }