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