github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/fs/operations/operations_test.go (about) 1 // Integration tests - test rclone by doing real transactions to a 2 // storage provider to and from the local disk. 3 // 4 // By default it will use a local fs, however you can provide a 5 // -remote option to use a different remote. The test_all.go script 6 // is a wrapper to call this for all the test remotes. 7 // 8 // FIXME not safe for concurrent running of tests until fs.Config is 9 // no longer a global 10 // 11 // NB When writing tests 12 // 13 // Make sure every series of writes to the remote has a 14 // fstest.CheckItems() before use. This make sure the directory 15 // listing is now consistent and stops cascading errors. 16 // 17 // Call accounting.GlobalStats().ResetCounters() before every fs.Sync() as it 18 // uses the error count internally. 19 20 package operations_test 21 22 import ( 23 "bytes" 24 "context" 25 "errors" 26 "fmt" 27 "io" 28 "log" 29 "net/http" 30 "net/http/httptest" 31 "os" 32 "regexp" 33 "strings" 34 "testing" 35 "time" 36 37 _ "github.com/rclone/rclone/backend/all" // import all backends 38 "github.com/rclone/rclone/fs" 39 "github.com/rclone/rclone/fs/accounting" 40 "github.com/rclone/rclone/fs/filter" 41 "github.com/rclone/rclone/fs/fshttp" 42 "github.com/rclone/rclone/fs/hash" 43 "github.com/rclone/rclone/fs/operations" 44 "github.com/rclone/rclone/fstest" 45 "github.com/stretchr/testify/assert" 46 "github.com/stretchr/testify/require" 47 ) 48 49 // Some times used in the tests 50 var ( 51 t1 = fstest.Time("2001-02-03T04:05:06.499999999Z") 52 t2 = fstest.Time("2011-12-25T12:59:59.123456789Z") 53 t3 = fstest.Time("2011-12-30T12:59:59.000000000Z") 54 ) 55 56 // TestMain drives the tests 57 func TestMain(m *testing.M) { 58 fstest.TestMain(m) 59 } 60 61 func TestMkdir(t *testing.T) { 62 r := fstest.NewRun(t) 63 defer r.Finalise() 64 65 err := operations.Mkdir(context.Background(), r.Fremote, "") 66 require.NoError(t, err) 67 fstest.CheckListing(t, r.Fremote, []fstest.Item{}) 68 69 err = operations.Mkdir(context.Background(), r.Fremote, "") 70 require.NoError(t, err) 71 } 72 73 func TestLsd(t *testing.T) { 74 r := fstest.NewRun(t) 75 defer r.Finalise() 76 file1 := r.WriteObject(context.Background(), "sub dir/hello world", "hello world", t1) 77 78 fstest.CheckItems(t, r.Fremote, file1) 79 80 var buf bytes.Buffer 81 err := operations.ListDir(context.Background(), r.Fremote, &buf) 82 require.NoError(t, err) 83 res := buf.String() 84 assert.Contains(t, res, "sub dir\n") 85 } 86 87 func TestLs(t *testing.T) { 88 r := fstest.NewRun(t) 89 defer r.Finalise() 90 file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1) 91 file2 := r.WriteBoth(context.Background(), "empty space", "-", t2) 92 93 fstest.CheckItems(t, r.Fremote, file1, file2) 94 95 var buf bytes.Buffer 96 err := operations.List(context.Background(), r.Fremote, &buf) 97 require.NoError(t, err) 98 res := buf.String() 99 assert.Contains(t, res, " 1 empty space\n") 100 assert.Contains(t, res, " 60 potato2\n") 101 } 102 103 func TestLsWithFilesFrom(t *testing.T) { 104 r := fstest.NewRun(t) 105 defer r.Finalise() 106 file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1) 107 file2 := r.WriteBoth(context.Background(), "empty space", "-", t2) 108 109 fstest.CheckItems(t, r.Fremote, file1, file2) 110 111 // Set the --files-from equivalent 112 f, err := filter.NewFilter(nil) 113 require.NoError(t, err) 114 require.NoError(t, f.AddFile("potato2")) 115 require.NoError(t, f.AddFile("notfound")) 116 117 // Monkey patch the active filter 118 oldFilter := filter.Active 119 filter.Active = f 120 defer func() { 121 filter.Active = oldFilter 122 }() 123 124 var buf bytes.Buffer 125 err = operations.List(context.Background(), r.Fremote, &buf) 126 require.NoError(t, err) 127 assert.Equal(t, " 60 potato2\n", buf.String()) 128 129 // Now try with --no-traverse 130 oldNoTraverse := fs.Config.NoTraverse 131 fs.Config.NoTraverse = true 132 defer func() { 133 fs.Config.NoTraverse = oldNoTraverse 134 }() 135 136 buf.Reset() 137 err = operations.List(context.Background(), r.Fremote, &buf) 138 require.NoError(t, err) 139 assert.Equal(t, " 60 potato2\n", buf.String()) 140 } 141 142 func TestLsLong(t *testing.T) { 143 r := fstest.NewRun(t) 144 defer r.Finalise() 145 file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1) 146 file2 := r.WriteBoth(context.Background(), "empty space", "-", t2) 147 148 fstest.CheckItems(t, r.Fremote, file1, file2) 149 150 var buf bytes.Buffer 151 err := operations.ListLong(context.Background(), r.Fremote, &buf) 152 require.NoError(t, err) 153 res := buf.String() 154 lines := strings.Split(strings.Trim(res, "\n"), "\n") 155 assert.Equal(t, 2, len(lines)) 156 157 timeFormat := "2006-01-02 15:04:05.000000000" 158 precision := r.Fremote.Precision() 159 location := time.Now().Location() 160 checkTime := func(m, filename string, expected time.Time) { 161 modTime, err := time.ParseInLocation(timeFormat, m, location) // parse as localtime 162 if err != nil { 163 t.Errorf("Error parsing %q: %v", m, err) 164 } else { 165 dt, ok := fstest.CheckTimeEqualWithPrecision(expected, modTime, precision) 166 if !ok { 167 t.Errorf("%s: Modification time difference too big |%s| > %s (%s vs %s) (precision %s)", filename, dt, precision, modTime, expected, precision) 168 } 169 } 170 } 171 172 m1 := regexp.MustCompile(`(?m)^ 1 (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{9}) empty space$`) 173 if ms := m1.FindStringSubmatch(res); ms == nil { 174 t.Errorf("empty space missing: %q", res) 175 } else { 176 checkTime(ms[1], "empty space", t2.Local()) 177 } 178 179 m2 := regexp.MustCompile(`(?m)^ 60 (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{9}) potato2$`) 180 if ms := m2.FindStringSubmatch(res); ms == nil { 181 t.Errorf("potato2 missing: %q", res) 182 } else { 183 checkTime(ms[1], "potato2", t1.Local()) 184 } 185 } 186 187 func TestHashSums(t *testing.T) { 188 r := fstest.NewRun(t) 189 defer r.Finalise() 190 file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1) 191 file2 := r.WriteBoth(context.Background(), "empty space", "-", t2) 192 193 fstest.CheckItems(t, r.Fremote, file1, file2) 194 195 // MD5 Sum 196 197 var buf bytes.Buffer 198 err := operations.Md5sum(context.Background(), r.Fremote, &buf) 199 require.NoError(t, err) 200 res := buf.String() 201 if !strings.Contains(res, "336d5ebc5436534e61d16e63ddfca327 empty space\n") && 202 !strings.Contains(res, " UNSUPPORTED empty space\n") && 203 !strings.Contains(res, " empty space\n") { 204 t.Errorf("empty space missing: %q", res) 205 } 206 if !strings.Contains(res, "d6548b156ea68a4e003e786df99eee76 potato2\n") && 207 !strings.Contains(res, " UNSUPPORTED potato2\n") && 208 !strings.Contains(res, " potato2\n") { 209 t.Errorf("potato2 missing: %q", res) 210 } 211 212 // SHA1 Sum 213 214 buf.Reset() 215 err = operations.Sha1sum(context.Background(), r.Fremote, &buf) 216 require.NoError(t, err) 217 res = buf.String() 218 if !strings.Contains(res, "3bc15c8aae3e4124dd409035f32ea2fd6835efc9 empty space\n") && 219 !strings.Contains(res, " UNSUPPORTED empty space\n") && 220 !strings.Contains(res, " empty space\n") { 221 t.Errorf("empty space missing: %q", res) 222 } 223 if !strings.Contains(res, "9dc7f7d3279715991a22853f5981df582b7f9f6d potato2\n") && 224 !strings.Contains(res, " UNSUPPORTED potato2\n") && 225 !strings.Contains(res, " potato2\n") { 226 t.Errorf("potato2 missing: %q", res) 227 } 228 229 // QuickXorHash Sum 230 231 buf.Reset() 232 var ht hash.Type 233 err = ht.Set("QuickXorHash") 234 require.NoError(t, err) 235 err = operations.HashLister(context.Background(), ht, r.Fremote, &buf) 236 require.NoError(t, err) 237 res = buf.String() 238 if !strings.Contains(res, "2d00000000000000000000000100000000000000 empty space\n") && 239 !strings.Contains(res, " UNSUPPORTED empty space\n") && 240 !strings.Contains(res, " empty space\n") { 241 t.Errorf("empty space missing: %q", res) 242 } 243 if !strings.Contains(res, "4001dad296b6b4a52d6d694b67dad296b6b4a52d potato2\n") && 244 !strings.Contains(res, " UNSUPPORTED potato2\n") && 245 !strings.Contains(res, " potato2\n") { 246 t.Errorf("potato2 missing: %q", res) 247 } 248 249 // QuickXorHash Sum with Base64 Encoded 250 251 buf.Reset() 252 err = operations.HashListerBase64(context.Background(), ht, r.Fremote, &buf) 253 require.NoError(t, err) 254 res = buf.String() 255 if !strings.Contains(res, "LQAAAAAAAAAAAAAAAQAAAAAAAAA= empty space\n") && 256 !strings.Contains(res, " UNSUPPORTED empty space\n") && 257 !strings.Contains(res, " empty space\n") { 258 t.Errorf("empty space missing: %q", res) 259 } 260 if !strings.Contains(res, "QAHa0pa2tKUtbWlLZ9rSlra0pS0= potato2\n") && 261 !strings.Contains(res, " UNSUPPORTED potato2\n") && 262 !strings.Contains(res, " potato2\n") { 263 t.Errorf("potato2 missing: %q", res) 264 } 265 } 266 267 func TestSuffixName(t *testing.T) { 268 origSuffix, origKeepExt := fs.Config.Suffix, fs.Config.SuffixKeepExtension 269 defer func() { 270 fs.Config.Suffix, fs.Config.SuffixKeepExtension = origSuffix, origKeepExt 271 }() 272 for _, test := range []struct { 273 remote string 274 suffix string 275 keepExt bool 276 want string 277 }{ 278 {"test.txt", "", false, "test.txt"}, 279 {"test.txt", "", true, "test.txt"}, 280 {"test.txt", "-suffix", false, "test.txt-suffix"}, 281 {"test.txt", "-suffix", true, "test-suffix.txt"}, 282 {"test.txt.csv", "-suffix", false, "test.txt.csv-suffix"}, 283 {"test.txt.csv", "-suffix", true, "test.txt-suffix.csv"}, 284 {"test", "-suffix", false, "test-suffix"}, 285 {"test", "-suffix", true, "test-suffix"}, 286 } { 287 fs.Config.Suffix = test.suffix 288 fs.Config.SuffixKeepExtension = test.keepExt 289 got := operations.SuffixName(test.remote) 290 assert.Equal(t, test.want, got, fmt.Sprintf("%+v", test)) 291 } 292 } 293 294 func TestCount(t *testing.T) { 295 r := fstest.NewRun(t) 296 defer r.Finalise() 297 file1 := r.WriteBoth(context.Background(), "potato2", "------------------------------------------------------------", t1) 298 file2 := r.WriteBoth(context.Background(), "empty space", "-", t2) 299 file3 := r.WriteBoth(context.Background(), "sub dir/potato3", "hello", t2) 300 301 fstest.CheckItems(t, r.Fremote, file1, file2, file3) 302 303 // Check the MaxDepth too 304 fs.Config.MaxDepth = 1 305 defer func() { fs.Config.MaxDepth = -1 }() 306 307 objects, size, err := operations.Count(context.Background(), r.Fremote) 308 require.NoError(t, err) 309 assert.Equal(t, int64(2), objects) 310 assert.Equal(t, int64(61), size) 311 } 312 313 func TestDelete(t *testing.T) { 314 r := fstest.NewRun(t) 315 defer r.Finalise() 316 file1 := r.WriteObject(context.Background(), "small", "1234567890", t2) // 10 bytes 317 file2 := r.WriteObject(context.Background(), "medium", "------------------------------------------------------------", t1) // 60 bytes 318 file3 := r.WriteObject(context.Background(), "large", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", t1) // 100 bytes 319 fstest.CheckItems(t, r.Fremote, file1, file2, file3) 320 321 filter.Active.Opt.MaxSize = 60 322 defer func() { 323 filter.Active.Opt.MaxSize = -1 324 }() 325 326 err := operations.Delete(context.Background(), r.Fremote) 327 require.NoError(t, err) 328 fstest.CheckItems(t, r.Fremote, file3) 329 } 330 331 func testCheck(t *testing.T, checkFunction func(ctx context.Context, fdst, fsrc fs.Fs, oneway bool) error) { 332 r := fstest.NewRun(t) 333 defer r.Finalise() 334 335 check := func(i int, wantErrors int64, wantChecks int64, oneway bool) { 336 fs.Debugf(r.Fremote, "%d: Starting check test", i) 337 accounting.GlobalStats().ResetCounters() 338 var buf bytes.Buffer 339 log.SetOutput(&buf) 340 defer func() { 341 log.SetOutput(os.Stderr) 342 }() 343 err := checkFunction(context.Background(), r.Fremote, r.Flocal, oneway) 344 gotErrors := accounting.GlobalStats().GetErrors() 345 gotChecks := accounting.GlobalStats().GetChecks() 346 if wantErrors == 0 && err != nil { 347 t.Errorf("%d: Got error when not expecting one: %v", i, err) 348 } 349 if wantErrors != 0 && err == nil { 350 t.Errorf("%d: No error when expecting one", i) 351 } 352 if wantErrors != gotErrors { 353 t.Errorf("%d: Expecting %d errors but got %d", i, wantErrors, gotErrors) 354 } 355 if gotChecks > 0 && !strings.Contains(buf.String(), "matching files") { 356 t.Errorf("%d: Total files matching line missing", i) 357 } 358 if wantChecks != gotChecks { 359 t.Errorf("%d: Expecting %d total matching files but got %d", i, wantChecks, gotChecks) 360 } 361 fs.Debugf(r.Fremote, "%d: Ending check test", i) 362 } 363 364 file1 := r.WriteBoth(context.Background(), "rutabaga", "is tasty", t3) 365 fstest.CheckItems(t, r.Fremote, file1) 366 fstest.CheckItems(t, r.Flocal, file1) 367 check(1, 0, 1, false) 368 369 file2 := r.WriteFile("potato2", "------------------------------------------------------------", t1) 370 fstest.CheckItems(t, r.Flocal, file1, file2) 371 check(2, 1, 1, false) 372 373 file3 := r.WriteObject(context.Background(), "empty space", "-", t2) 374 fstest.CheckItems(t, r.Fremote, file1, file3) 375 check(3, 2, 1, false) 376 377 file2r := file2 378 if fs.Config.SizeOnly { 379 file2r = r.WriteObject(context.Background(), "potato2", "--Some-Differences-But-Size-Only-Is-Enabled-----------------", t1) 380 } else { 381 r.WriteObject(context.Background(), "potato2", "------------------------------------------------------------", t1) 382 } 383 fstest.CheckItems(t, r.Fremote, file1, file2r, file3) 384 check(4, 1, 2, false) 385 386 r.WriteFile("empty space", "-", t2) 387 fstest.CheckItems(t, r.Flocal, file1, file2, file3) 388 check(5, 0, 3, false) 389 390 file4 := r.WriteObject(context.Background(), "remotepotato", "------------------------------------------------------------", t1) 391 fstest.CheckItems(t, r.Fremote, file1, file2r, file3, file4) 392 check(6, 1, 3, false) 393 check(7, 0, 3, true) 394 } 395 396 func TestCheck(t *testing.T) { 397 testCheck(t, operations.Check) 398 } 399 400 func TestCheckFsError(t *testing.T) { 401 dstFs, err := fs.NewFs("non-existent") 402 if err != nil { 403 t.Fatal(err) 404 } 405 srcFs, err := fs.NewFs("non-existent") 406 if err != nil { 407 t.Fatal(err) 408 } 409 err = operations.Check(context.Background(), dstFs, srcFs, false) 410 require.Error(t, err) 411 } 412 413 func TestCheckDownload(t *testing.T) { 414 testCheck(t, operations.CheckDownload) 415 } 416 417 func TestCheckSizeOnly(t *testing.T) { 418 fs.Config.SizeOnly = true 419 defer func() { fs.Config.SizeOnly = false }() 420 TestCheck(t) 421 } 422 423 func TestCat(t *testing.T) { 424 r := fstest.NewRun(t) 425 defer r.Finalise() 426 file1 := r.WriteBoth(context.Background(), "file1", "ABCDEFGHIJ", t1) 427 file2 := r.WriteBoth(context.Background(), "file2", "012345678", t2) 428 429 fstest.CheckItems(t, r.Fremote, file1, file2) 430 431 for _, test := range []struct { 432 offset int64 433 count int64 434 a string 435 b string 436 }{ 437 {0, -1, "ABCDEFGHIJ", "012345678"}, 438 {0, 5, "ABCDE", "01234"}, 439 {-3, -1, "HIJ", "678"}, 440 {1, 3, "BCD", "123"}, 441 } { 442 var buf bytes.Buffer 443 err := operations.Cat(context.Background(), r.Fremote, &buf, test.offset, test.count) 444 require.NoError(t, err) 445 res := buf.String() 446 447 if res != test.a+test.b && res != test.b+test.a { 448 t.Errorf("Incorrect output from Cat(%d,%d): %q", test.offset, test.count, res) 449 } 450 } 451 } 452 453 func TestPurge(t *testing.T) { 454 r := fstest.NewRunIndividual(t) // make new container (azureblob has delayed mkdir after rmdir) 455 defer r.Finalise() 456 r.Mkdir(context.Background(), r.Fremote) 457 458 // Make some files and dirs 459 r.ForceMkdir(context.Background(), r.Fremote) 460 file1 := r.WriteObject(context.Background(), "A1/B1/C1/one", "aaa", t1) 461 //..and dirs we expect to delete 462 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A2")) 463 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2")) 464 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2/C2")) 465 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C3")) 466 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3")) 467 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3")) 468 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3/C4")) 469 //..and one more file at the end 470 file2 := r.WriteObject(context.Background(), "A1/two", "bbb", t2) 471 472 fstest.CheckListingWithPrecision( 473 t, 474 r.Fremote, 475 []fstest.Item{ 476 file1, file2, 477 }, 478 []string{ 479 "A1", 480 "A1/B1", 481 "A1/B1/C1", 482 "A2", 483 "A1/B2", 484 "A1/B2/C2", 485 "A1/B1/C3", 486 "A3", 487 "A3/B3", 488 "A3/B3/C4", 489 }, 490 fs.GetModifyWindow(r.Fremote), 491 ) 492 493 require.NoError(t, operations.Purge(context.Background(), r.Fremote, "A1/B1")) 494 495 fstest.CheckListingWithPrecision( 496 t, 497 r.Fremote, 498 []fstest.Item{ 499 file2, 500 }, 501 []string{ 502 "A1", 503 "A2", 504 "A1/B2", 505 "A1/B2/C2", 506 "A3", 507 "A3/B3", 508 "A3/B3/C4", 509 }, 510 fs.GetModifyWindow(r.Fremote), 511 ) 512 513 require.NoError(t, operations.Purge(context.Background(), r.Fremote, "")) 514 515 fstest.CheckListingWithPrecision( 516 t, 517 r.Fremote, 518 []fstest.Item{}, 519 []string{}, 520 fs.GetModifyWindow(r.Fremote), 521 ) 522 523 } 524 525 func TestRmdirsNoLeaveRoot(t *testing.T) { 526 r := fstest.NewRun(t) 527 defer r.Finalise() 528 r.Mkdir(context.Background(), r.Fremote) 529 530 // Make some files and dirs we expect to keep 531 r.ForceMkdir(context.Background(), r.Fremote) 532 file1 := r.WriteObject(context.Background(), "A1/B1/C1/one", "aaa", t1) 533 //..and dirs we expect to delete 534 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A2")) 535 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2")) 536 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2/C2")) 537 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C3")) 538 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3")) 539 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3")) 540 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A3/B3/C4")) 541 //..and one more file at the end 542 file2 := r.WriteObject(context.Background(), "A1/two", "bbb", t2) 543 544 fstest.CheckListingWithPrecision( 545 t, 546 r.Fremote, 547 []fstest.Item{ 548 file1, file2, 549 }, 550 []string{ 551 "A1", 552 "A1/B1", 553 "A1/B1/C1", 554 "A2", 555 "A1/B2", 556 "A1/B2/C2", 557 "A1/B1/C3", 558 "A3", 559 "A3/B3", 560 "A3/B3/C4", 561 }, 562 fs.GetModifyWindow(r.Fremote), 563 ) 564 565 require.NoError(t, operations.Rmdirs(context.Background(), r.Fremote, "A3/B3/C4", false)) 566 567 fstest.CheckListingWithPrecision( 568 t, 569 r.Fremote, 570 []fstest.Item{ 571 file1, file2, 572 }, 573 []string{ 574 "A1", 575 "A1/B1", 576 "A1/B1/C1", 577 "A2", 578 "A1/B2", 579 "A1/B2/C2", 580 "A1/B1/C3", 581 "A3", 582 "A3/B3", 583 }, 584 fs.GetModifyWindow(r.Fremote), 585 ) 586 587 require.NoError(t, operations.Rmdirs(context.Background(), r.Fremote, "", false)) 588 589 fstest.CheckListingWithPrecision( 590 t, 591 r.Fremote, 592 []fstest.Item{ 593 file1, file2, 594 }, 595 []string{ 596 "A1", 597 "A1/B1", 598 "A1/B1/C1", 599 }, 600 fs.GetModifyWindow(r.Fremote), 601 ) 602 603 } 604 605 func TestRmdirsLeaveRoot(t *testing.T) { 606 r := fstest.NewRun(t) 607 defer r.Finalise() 608 r.Mkdir(context.Background(), r.Fremote) 609 610 r.ForceMkdir(context.Background(), r.Fremote) 611 612 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1")) 613 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1")) 614 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C1")) 615 616 fstest.CheckListingWithPrecision( 617 t, 618 r.Fremote, 619 []fstest.Item{}, 620 []string{ 621 "A1", 622 "A1/B1", 623 "A1/B1/C1", 624 }, 625 fs.GetModifyWindow(r.Fremote), 626 ) 627 628 require.NoError(t, operations.Rmdirs(context.Background(), r.Fremote, "A1", true)) 629 630 fstest.CheckListingWithPrecision( 631 t, 632 r.Fremote, 633 []fstest.Item{}, 634 []string{ 635 "A1", 636 }, 637 fs.GetModifyWindow(r.Fremote), 638 ) 639 } 640 641 func TestCopyURL(t *testing.T) { 642 r := fstest.NewRun(t) 643 defer r.Finalise() 644 645 contents := "file contents\n" 646 file1 := r.WriteFile("file1", contents, t1) 647 file2 := r.WriteFile("file2", contents, t1) 648 r.Mkdir(context.Background(), r.Fremote) 649 fstest.CheckItems(t, r.Fremote) 650 651 // check when reading from regular HTTP server 652 status := 0 653 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 654 if status != 0 { 655 http.Error(w, "an error ocurred", status) 656 } 657 _, err := w.Write([]byte(contents)) 658 assert.NoError(t, err) 659 }) 660 ts := httptest.NewServer(handler) 661 defer ts.Close() 662 663 o, err := operations.CopyURL(context.Background(), r.Fremote, "file1", ts.URL, false) 664 require.NoError(t, err) 665 assert.Equal(t, int64(len(contents)), o.Size()) 666 667 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, nil, fs.ModTimeNotSupported) 668 669 // Check auto file naming 670 status = 0 671 urlFileName := "filename.txt" 672 o, err = operations.CopyURL(context.Background(), r.Fremote, "", ts.URL+"/"+urlFileName, true) 673 require.NoError(t, err) 674 assert.Equal(t, int64(len(contents)), o.Size()) 675 assert.Equal(t, urlFileName, o.Remote()) 676 677 // Check auto file naming when url without file name 678 o, err = operations.CopyURL(context.Background(), r.Fremote, "file1", ts.URL, true) 679 require.Error(t, err) 680 681 // Check an error is returned for a 404 682 status = http.StatusNotFound 683 o, err = operations.CopyURL(context.Background(), r.Fremote, "file1", ts.URL, false) 684 require.Error(t, err) 685 assert.Contains(t, err.Error(), "Not Found") 686 assert.Nil(t, o) 687 status = 0 688 689 // check when reading from unverified HTTPS server 690 fs.Config.InsecureSkipVerify = true 691 fshttp.ResetTransport() 692 defer func() { 693 fs.Config.InsecureSkipVerify = false 694 fshttp.ResetTransport() 695 }() 696 tss := httptest.NewTLSServer(handler) 697 defer tss.Close() 698 699 o, err = operations.CopyURL(context.Background(), r.Fremote, "file2", tss.URL, false) 700 require.NoError(t, err) 701 assert.Equal(t, int64(len(contents)), o.Size()) 702 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file2, fstest.NewItem(urlFileName, contents, t1)}, nil, fs.ModTimeNotSupported) 703 } 704 705 func TestCopyURLToWriter(t *testing.T) { 706 contents := "file contents\n" 707 708 // check when reading from regular HTTP server 709 status := 0 710 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 711 if status != 0 { 712 http.Error(w, "an error ocurred", status) 713 return 714 } 715 _, err := w.Write([]byte(contents)) 716 assert.NoError(t, err) 717 }) 718 ts := httptest.NewServer(handler) 719 defer ts.Close() 720 721 // test normal fetch 722 var buf bytes.Buffer 723 err := operations.CopyURLToWriter(context.Background(), ts.URL, &buf) 724 require.NoError(t, err) 725 assert.Equal(t, contents, buf.String()) 726 727 // test fetch with error 728 status = http.StatusNotFound 729 buf.Reset() 730 err = operations.CopyURLToWriter(context.Background(), ts.URL, &buf) 731 require.Error(t, err) 732 assert.Contains(t, err.Error(), "Not Found") 733 assert.Equal(t, 0, len(buf.String())) 734 } 735 736 func TestMoveFile(t *testing.T) { 737 r := fstest.NewRun(t) 738 defer r.Finalise() 739 740 file1 := r.WriteFile("file1", "file1 contents", t1) 741 fstest.CheckItems(t, r.Flocal, file1) 742 743 file2 := file1 744 file2.Path = "sub/file2" 745 746 err := operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path) 747 require.NoError(t, err) 748 fstest.CheckItems(t, r.Flocal) 749 fstest.CheckItems(t, r.Fremote, file2) 750 751 r.WriteFile("file1", "file1 contents", t1) 752 fstest.CheckItems(t, r.Flocal, file1) 753 754 err = operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path) 755 require.NoError(t, err) 756 fstest.CheckItems(t, r.Flocal) 757 fstest.CheckItems(t, r.Fremote, file2) 758 759 err = operations.MoveFile(context.Background(), r.Fremote, r.Fremote, file2.Path, file2.Path) 760 require.NoError(t, err) 761 fstest.CheckItems(t, r.Flocal) 762 fstest.CheckItems(t, r.Fremote, file2) 763 } 764 765 func TestCaseInsensitiveMoveFile(t *testing.T) { 766 r := fstest.NewRun(t) 767 defer r.Finalise() 768 if !r.Fremote.Features().CaseInsensitive { 769 return 770 } 771 772 file1 := r.WriteFile("file1", "file1 contents", t1) 773 fstest.CheckItems(t, r.Flocal, file1) 774 775 file2 := file1 776 file2.Path = "sub/file2" 777 778 err := operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path) 779 require.NoError(t, err) 780 fstest.CheckItems(t, r.Flocal) 781 fstest.CheckItems(t, r.Fremote, file2) 782 783 r.WriteFile("file1", "file1 contents", t1) 784 fstest.CheckItems(t, r.Flocal, file1) 785 786 err = operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path) 787 require.NoError(t, err) 788 fstest.CheckItems(t, r.Flocal) 789 fstest.CheckItems(t, r.Fremote, file2) 790 791 file2Capitalized := file2 792 file2Capitalized.Path = "sub/File2" 793 794 err = operations.MoveFile(context.Background(), r.Fremote, r.Fremote, file2Capitalized.Path, file2.Path) 795 require.NoError(t, err) 796 fstest.CheckItems(t, r.Flocal) 797 fstest.CheckItems(t, r.Fremote, file2Capitalized) 798 } 799 800 func TestMoveFileBackupDir(t *testing.T) { 801 r := fstest.NewRun(t) 802 defer r.Finalise() 803 if !operations.CanServerSideMove(r.Fremote) { 804 t.Skip("Skipping test as remote does not support server side move or copy") 805 } 806 807 oldBackupDir := fs.Config.BackupDir 808 fs.Config.BackupDir = r.FremoteName + "/backup" 809 defer func() { 810 fs.Config.BackupDir = oldBackupDir 811 }() 812 813 file1 := r.WriteFile("dst/file1", "file1 contents", t1) 814 fstest.CheckItems(t, r.Flocal, file1) 815 816 file1old := r.WriteObject(context.Background(), "dst/file1", "file1 contents old", t1) 817 fstest.CheckItems(t, r.Fremote, file1old) 818 819 err := operations.MoveFile(context.Background(), r.Fremote, r.Flocal, file1.Path, file1.Path) 820 require.NoError(t, err) 821 fstest.CheckItems(t, r.Flocal) 822 file1old.Path = "backup/dst/file1" 823 fstest.CheckItems(t, r.Fremote, file1old, file1) 824 } 825 826 func TestCopyFile(t *testing.T) { 827 r := fstest.NewRun(t) 828 defer r.Finalise() 829 830 file1 := r.WriteFile("file1", "file1 contents", t1) 831 fstest.CheckItems(t, r.Flocal, file1) 832 833 file2 := file1 834 file2.Path = "sub/file2" 835 836 err := operations.CopyFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path) 837 require.NoError(t, err) 838 fstest.CheckItems(t, r.Flocal, file1) 839 fstest.CheckItems(t, r.Fremote, file2) 840 841 err = operations.CopyFile(context.Background(), r.Fremote, r.Flocal, file2.Path, file1.Path) 842 require.NoError(t, err) 843 fstest.CheckItems(t, r.Flocal, file1) 844 fstest.CheckItems(t, r.Fremote, file2) 845 846 err = operations.CopyFile(context.Background(), r.Fremote, r.Fremote, file2.Path, file2.Path) 847 require.NoError(t, err) 848 fstest.CheckItems(t, r.Flocal, file1) 849 fstest.CheckItems(t, r.Fremote, file2) 850 } 851 852 func TestCopyFileBackupDir(t *testing.T) { 853 r := fstest.NewRun(t) 854 defer r.Finalise() 855 if !operations.CanServerSideMove(r.Fremote) { 856 t.Skip("Skipping test as remote does not support server side move or copy") 857 } 858 859 oldBackupDir := fs.Config.BackupDir 860 fs.Config.BackupDir = r.FremoteName + "/backup" 861 defer func() { 862 fs.Config.BackupDir = oldBackupDir 863 }() 864 865 file1 := r.WriteFile("dst/file1", "file1 contents", t1) 866 fstest.CheckItems(t, r.Flocal, file1) 867 868 file1old := r.WriteObject(context.Background(), "dst/file1", "file1 contents old", t1) 869 fstest.CheckItems(t, r.Fremote, file1old) 870 871 err := operations.CopyFile(context.Background(), r.Fremote, r.Flocal, file1.Path, file1.Path) 872 require.NoError(t, err) 873 fstest.CheckItems(t, r.Flocal, file1) 874 file1old.Path = "backup/dst/file1" 875 fstest.CheckItems(t, r.Fremote, file1old, file1) 876 } 877 878 // Test with CompareDest set 879 func TestCopyFileCompareDest(t *testing.T) { 880 r := fstest.NewRun(t) 881 defer r.Finalise() 882 883 fs.Config.CompareDest = r.FremoteName + "/CompareDest" 884 defer func() { 885 fs.Config.CompareDest = "" 886 }() 887 fdst, err := fs.NewFs(r.FremoteName + "/dst") 888 require.NoError(t, err) 889 890 // check empty dest, empty compare 891 file1 := r.WriteFile("one", "one", t1) 892 fstest.CheckItems(t, r.Flocal, file1) 893 894 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1.Path, file1.Path) 895 require.NoError(t, err) 896 897 file1dst := file1 898 file1dst.Path = "dst/one" 899 900 fstest.CheckItems(t, r.Fremote, file1dst) 901 902 // check old dest, empty compare 903 file1b := r.WriteFile("one", "onet2", t2) 904 fstest.CheckItems(t, r.Fremote, file1dst) 905 fstest.CheckItems(t, r.Flocal, file1b) 906 907 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1b.Path, file1b.Path) 908 require.NoError(t, err) 909 910 file1bdst := file1b 911 file1bdst.Path = "dst/one" 912 913 fstest.CheckItems(t, r.Fremote, file1bdst) 914 915 // check old dest, new compare 916 file3 := r.WriteObject(context.Background(), "dst/one", "one", t1) 917 file2 := r.WriteObject(context.Background(), "CompareDest/one", "onet2", t2) 918 file1c := r.WriteFile("one", "onet2", t2) 919 fstest.CheckItems(t, r.Fremote, file2, file3) 920 fstest.CheckItems(t, r.Flocal, file1c) 921 922 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1c.Path, file1c.Path) 923 require.NoError(t, err) 924 925 fstest.CheckItems(t, r.Fremote, file2, file3) 926 927 // check empty dest, new compare 928 file4 := r.WriteObject(context.Background(), "CompareDest/two", "two", t2) 929 file5 := r.WriteFile("two", "two", t2) 930 fstest.CheckItems(t, r.Fremote, file2, file3, file4) 931 fstest.CheckItems(t, r.Flocal, file1c, file5) 932 933 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path) 934 require.NoError(t, err) 935 936 fstest.CheckItems(t, r.Fremote, file2, file3, file4) 937 938 // check new dest, new compare 939 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path) 940 require.NoError(t, err) 941 942 fstest.CheckItems(t, r.Fremote, file2, file3, file4) 943 944 // check empty dest, old compare 945 file5b := r.WriteFile("two", "twot3", t3) 946 fstest.CheckItems(t, r.Fremote, file2, file3, file4) 947 fstest.CheckItems(t, r.Flocal, file1c, file5b) 948 949 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5b.Path, file5b.Path) 950 require.NoError(t, err) 951 952 file5bdst := file5b 953 file5bdst.Path = "dst/two" 954 955 fstest.CheckItems(t, r.Fremote, file2, file3, file4, file5bdst) 956 } 957 958 // Test with CopyDest set 959 func TestCopyFileCopyDest(t *testing.T) { 960 r := fstest.NewRun(t) 961 defer r.Finalise() 962 963 if r.Fremote.Features().Copy == nil { 964 t.Skip("Skipping test as remote does not support server side copy") 965 } 966 967 fs.Config.CopyDest = r.FremoteName + "/CopyDest" 968 defer func() { 969 fs.Config.CopyDest = "" 970 }() 971 972 fdst, err := fs.NewFs(r.FremoteName + "/dst") 973 require.NoError(t, err) 974 975 // check empty dest, empty copy 976 file1 := r.WriteFile("one", "one", t1) 977 fstest.CheckItems(t, r.Flocal, file1) 978 979 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1.Path, file1.Path) 980 require.NoError(t, err) 981 982 file1dst := file1 983 file1dst.Path = "dst/one" 984 985 fstest.CheckItems(t, r.Fremote, file1dst) 986 987 // check old dest, empty copy 988 file1b := r.WriteFile("one", "onet2", t2) 989 fstest.CheckItems(t, r.Fremote, file1dst) 990 fstest.CheckItems(t, r.Flocal, file1b) 991 992 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1b.Path, file1b.Path) 993 require.NoError(t, err) 994 995 file1bdst := file1b 996 file1bdst.Path = "dst/one" 997 998 fstest.CheckItems(t, r.Fremote, file1bdst) 999 1000 // check old dest, new copy, backup-dir 1001 1002 fs.Config.BackupDir = r.FremoteName + "/BackupDir" 1003 1004 file3 := r.WriteObject(context.Background(), "dst/one", "one", t1) 1005 file2 := r.WriteObject(context.Background(), "CopyDest/one", "onet2", t2) 1006 file1c := r.WriteFile("one", "onet2", t2) 1007 fstest.CheckItems(t, r.Fremote, file2, file3) 1008 fstest.CheckItems(t, r.Flocal, file1c) 1009 1010 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file1c.Path, file1c.Path) 1011 require.NoError(t, err) 1012 1013 file2dst := file2 1014 file2dst.Path = "dst/one" 1015 file3.Path = "BackupDir/one" 1016 1017 fstest.CheckItems(t, r.Fremote, file2, file2dst, file3) 1018 fs.Config.BackupDir = "" 1019 1020 // check empty dest, new copy 1021 file4 := r.WriteObject(context.Background(), "CopyDest/two", "two", t2) 1022 file5 := r.WriteFile("two", "two", t2) 1023 fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4) 1024 fstest.CheckItems(t, r.Flocal, file1c, file5) 1025 1026 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path) 1027 require.NoError(t, err) 1028 1029 file4dst := file4 1030 file4dst.Path = "dst/two" 1031 1032 fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst) 1033 1034 // check new dest, new copy 1035 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file5.Path, file5.Path) 1036 require.NoError(t, err) 1037 1038 fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst) 1039 1040 // check empty dest, old copy 1041 file6 := r.WriteObject(context.Background(), "CopyDest/three", "three", t2) 1042 file7 := r.WriteFile("three", "threet3", t3) 1043 fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst, file6) 1044 fstest.CheckItems(t, r.Flocal, file1c, file5, file7) 1045 1046 err = operations.CopyFile(context.Background(), fdst, r.Flocal, file7.Path, file7.Path) 1047 require.NoError(t, err) 1048 1049 file7dst := file7 1050 file7dst.Path = "dst/three" 1051 1052 fstest.CheckItems(t, r.Fremote, file2, file2dst, file3, file4, file4dst, file6, file7dst) 1053 } 1054 1055 // testFsInfo is for unit testing fs.Info 1056 type testFsInfo struct { 1057 name string 1058 root string 1059 stringVal string 1060 precision time.Duration 1061 hashes hash.Set 1062 features fs.Features 1063 } 1064 1065 // Name of the remote (as passed into NewFs) 1066 func (i *testFsInfo) Name() string { return i.name } 1067 1068 // Root of the remote (as passed into NewFs) 1069 func (i *testFsInfo) Root() string { return i.root } 1070 1071 // String returns a description of the FS 1072 func (i *testFsInfo) String() string { return i.stringVal } 1073 1074 // Precision of the ModTimes in this Fs 1075 func (i *testFsInfo) Precision() time.Duration { return i.precision } 1076 1077 // Returns the supported hash types of the filesystem 1078 func (i *testFsInfo) Hashes() hash.Set { return i.hashes } 1079 1080 // Returns the supported hash types of the filesystem 1081 func (i *testFsInfo) Features() *fs.Features { return &i.features } 1082 1083 func TestSameConfig(t *testing.T) { 1084 a := &testFsInfo{name: "name", root: "root"} 1085 for _, test := range []struct { 1086 name string 1087 root string 1088 expected bool 1089 }{ 1090 {"name", "root", true}, 1091 {"name", "rooty", true}, 1092 {"namey", "root", false}, 1093 {"namey", "roott", false}, 1094 } { 1095 b := &testFsInfo{name: test.name, root: test.root} 1096 actual := operations.SameConfig(a, b) 1097 assert.Equal(t, test.expected, actual) 1098 actual = operations.SameConfig(b, a) 1099 assert.Equal(t, test.expected, actual) 1100 } 1101 } 1102 1103 func TestSame(t *testing.T) { 1104 a := &testFsInfo{name: "name", root: "root"} 1105 for _, test := range []struct { 1106 name string 1107 root string 1108 expected bool 1109 }{ 1110 {"name", "root", true}, 1111 {"name", "rooty", false}, 1112 {"namey", "root", false}, 1113 {"namey", "roott", false}, 1114 } { 1115 b := &testFsInfo{name: test.name, root: test.root} 1116 actual := operations.Same(a, b) 1117 assert.Equal(t, test.expected, actual) 1118 actual = operations.Same(b, a) 1119 assert.Equal(t, test.expected, actual) 1120 } 1121 } 1122 1123 func TestOverlapping(t *testing.T) { 1124 a := &testFsInfo{name: "name", root: "root"} 1125 slash := string(os.PathSeparator) // native path separator 1126 for _, test := range []struct { 1127 name string 1128 root string 1129 expected bool 1130 }{ 1131 {"name", "root", true}, 1132 {"namey", "root", false}, 1133 {"name", "rooty", false}, 1134 {"namey", "rooty", false}, 1135 {"name", "roo", false}, 1136 {"name", "root/toot", true}, 1137 {"name", "root/toot/", true}, 1138 {"name", "root" + slash + "toot", true}, 1139 {"name", "root" + slash + "toot" + slash, true}, 1140 {"name", "", true}, 1141 {"name", "/", true}, 1142 } { 1143 b := &testFsInfo{name: test.name, root: test.root} 1144 what := fmt.Sprintf("(%q,%q) vs (%q,%q)", a.name, a.root, b.name, b.root) 1145 actual := operations.Overlapping(a, b) 1146 assert.Equal(t, test.expected, actual, what) 1147 actual = operations.Overlapping(b, a) 1148 assert.Equal(t, test.expected, actual, what) 1149 } 1150 } 1151 1152 type errorReader struct { 1153 err error 1154 } 1155 1156 func (er errorReader) Read(p []byte) (n int, err error) { 1157 return 0, er.err 1158 } 1159 1160 func TestCheckEqualReaders(t *testing.T) { 1161 b65a := make([]byte, 65*1024) 1162 b65b := make([]byte, 65*1024) 1163 b65b[len(b65b)-1] = 1 1164 b66 := make([]byte, 66*1024) 1165 1166 differ, err := operations.CheckEqualReaders(bytes.NewBuffer(b65a), bytes.NewBuffer(b65a)) 1167 assert.NoError(t, err) 1168 assert.Equal(t, differ, false) 1169 1170 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), bytes.NewBuffer(b65b)) 1171 assert.NoError(t, err) 1172 assert.Equal(t, differ, true) 1173 1174 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), bytes.NewBuffer(b66)) 1175 assert.NoError(t, err) 1176 assert.Equal(t, differ, true) 1177 1178 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b66), bytes.NewBuffer(b65a)) 1179 assert.NoError(t, err) 1180 assert.Equal(t, differ, true) 1181 1182 myErr := errors.New("sentinel") 1183 wrap := func(b []byte) io.Reader { 1184 r := bytes.NewBuffer(b) 1185 e := errorReader{myErr} 1186 return io.MultiReader(r, e) 1187 } 1188 1189 differ, err = operations.CheckEqualReaders(wrap(b65a), bytes.NewBuffer(b65a)) 1190 assert.Equal(t, myErr, err) 1191 assert.Equal(t, differ, true) 1192 1193 differ, err = operations.CheckEqualReaders(wrap(b65a), bytes.NewBuffer(b65b)) 1194 assert.Equal(t, myErr, err) 1195 assert.Equal(t, differ, true) 1196 1197 differ, err = operations.CheckEqualReaders(wrap(b65a), bytes.NewBuffer(b66)) 1198 assert.Equal(t, myErr, err) 1199 assert.Equal(t, differ, true) 1200 1201 differ, err = operations.CheckEqualReaders(wrap(b66), bytes.NewBuffer(b65a)) 1202 assert.Equal(t, myErr, err) 1203 assert.Equal(t, differ, true) 1204 1205 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), wrap(b65a)) 1206 assert.Equal(t, myErr, err) 1207 assert.Equal(t, differ, true) 1208 1209 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), wrap(b65b)) 1210 assert.Equal(t, myErr, err) 1211 assert.Equal(t, differ, true) 1212 1213 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b65a), wrap(b66)) 1214 assert.Equal(t, myErr, err) 1215 assert.Equal(t, differ, true) 1216 1217 differ, err = operations.CheckEqualReaders(bytes.NewBuffer(b66), wrap(b65a)) 1218 assert.Equal(t, myErr, err) 1219 assert.Equal(t, differ, true) 1220 } 1221 1222 func TestListFormat(t *testing.T) { 1223 item0 := &operations.ListJSONItem{ 1224 Path: "a", 1225 Name: "a", 1226 Encrypted: "encryptedFileName", 1227 Size: 1, 1228 MimeType: "application/octet-stream", 1229 ModTime: operations.Timestamp{ 1230 When: t1, 1231 Format: "2006-01-02T15:04:05.000000000Z07:00"}, 1232 IsDir: false, 1233 Hashes: map[string]string{ 1234 "MD5": "0cc175b9c0f1b6a831c399e269772661", 1235 "SHA-1": "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", 1236 "DropboxHash": "bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8", 1237 "QuickXorHash": "6100000000000000000000000100000000000000"}, 1238 ID: "fileID", 1239 OrigID: "fileOrigID", 1240 } 1241 1242 item1 := &operations.ListJSONItem{ 1243 Path: "subdir", 1244 Name: "subdir", 1245 Encrypted: "encryptedDirName", 1246 Size: -1, 1247 MimeType: "inode/directory", 1248 ModTime: operations.Timestamp{ 1249 When: t2, 1250 Format: "2006-01-02T15:04:05.000000000Z07:00"}, 1251 IsDir: true, 1252 Hashes: map[string]string(nil), 1253 ID: "dirID", 1254 OrigID: "dirOrigID", 1255 } 1256 1257 var list operations.ListFormat 1258 list.AddPath() 1259 list.SetDirSlash(false) 1260 assert.Equal(t, "subdir", list.Format(item1)) 1261 1262 list.SetDirSlash(true) 1263 assert.Equal(t, "subdir/", list.Format(item1)) 1264 1265 list.SetOutput(nil) 1266 assert.Equal(t, "", list.Format(item1)) 1267 1268 list.AppendOutput(func(item *operations.ListJSONItem) string { return "a" }) 1269 list.AppendOutput(func(item *operations.ListJSONItem) string { return "b" }) 1270 assert.Equal(t, "ab", list.Format(item1)) 1271 list.SetSeparator(":::") 1272 assert.Equal(t, "a:::b", list.Format(item1)) 1273 1274 list.SetOutput(nil) 1275 list.AddModTime() 1276 assert.Equal(t, t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0)) 1277 1278 list.SetOutput(nil) 1279 list.SetSeparator("|") 1280 list.AddID() 1281 list.AddOrigID() 1282 assert.Equal(t, "fileID|fileOrigID", list.Format(item0)) 1283 assert.Equal(t, "dirID|dirOrigID", list.Format(item1)) 1284 1285 list.SetOutput(nil) 1286 list.AddMimeType() 1287 assert.Contains(t, list.Format(item0), "/") 1288 assert.Equal(t, "inode/directory", list.Format(item1)) 1289 1290 list.SetOutput(nil) 1291 list.AddPath() 1292 list.SetAbsolute(true) 1293 assert.Equal(t, "/a", list.Format(item0)) 1294 list.SetAbsolute(false) 1295 assert.Equal(t, "a", list.Format(item0)) 1296 1297 list.SetOutput(nil) 1298 list.AddSize() 1299 assert.Equal(t, "1", list.Format(item0)) 1300 1301 list.AddPath() 1302 list.AddModTime() 1303 list.SetDirSlash(true) 1304 list.SetSeparator("__SEP__") 1305 assert.Equal(t, "1__SEP__a__SEP__"+t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0)) 1306 assert.Equal(t, "-1__SEP__subdir/__SEP__"+t2.Local().Format("2006-01-02 15:04:05"), list.Format(item1)) 1307 1308 for _, test := range []struct { 1309 ht hash.Type 1310 want string 1311 }{ 1312 {hash.MD5, "0cc175b9c0f1b6a831c399e269772661"}, 1313 {hash.SHA1, "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"}, 1314 } { 1315 list.SetOutput(nil) 1316 list.AddHash(test.ht) 1317 assert.Equal(t, test.want, list.Format(item0)) 1318 } 1319 1320 list.SetOutput(nil) 1321 list.SetSeparator("|") 1322 list.SetCSV(true) 1323 list.AddSize() 1324 list.AddPath() 1325 list.AddModTime() 1326 list.SetDirSlash(true) 1327 assert.Equal(t, "1|a|"+t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0)) 1328 assert.Equal(t, "-1|subdir/|"+t2.Local().Format("2006-01-02 15:04:05"), list.Format(item1)) 1329 1330 list.SetOutput(nil) 1331 list.SetSeparator("|") 1332 list.AddPath() 1333 list.AddEncrypted() 1334 assert.Equal(t, "a|encryptedFileName", list.Format(item0)) 1335 assert.Equal(t, "subdir/|encryptedDirName/", list.Format(item1)) 1336 1337 } 1338 1339 func TestDirMove(t *testing.T) { 1340 r := fstest.NewRun(t) 1341 defer r.Finalise() 1342 1343 r.Mkdir(context.Background(), r.Fremote) 1344 1345 // Make some files and dirs 1346 r.ForceMkdir(context.Background(), r.Fremote) 1347 files := []fstest.Item{ 1348 r.WriteObject(context.Background(), "A1/one", "one", t1), 1349 r.WriteObject(context.Background(), "A1/two", "two", t2), 1350 r.WriteObject(context.Background(), "A1/B1/three", "three", t3), 1351 r.WriteObject(context.Background(), "A1/B1/C1/four", "four", t1), 1352 r.WriteObject(context.Background(), "A1/B1/C2/five", "five", t2), 1353 } 1354 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B2")) 1355 require.NoError(t, operations.Mkdir(context.Background(), r.Fremote, "A1/B1/C3")) 1356 1357 fstest.CheckListingWithPrecision( 1358 t, 1359 r.Fremote, 1360 files, 1361 []string{ 1362 "A1", 1363 "A1/B1", 1364 "A1/B2", 1365 "A1/B1/C1", 1366 "A1/B1/C2", 1367 "A1/B1/C3", 1368 }, 1369 fs.GetModifyWindow(r.Fremote), 1370 ) 1371 1372 require.NoError(t, operations.DirMove(context.Background(), r.Fremote, "A1", "A2")) 1373 1374 for i := range files { 1375 files[i].Path = strings.Replace(files[i].Path, "A1/", "A2/", -1) 1376 } 1377 1378 fstest.CheckListingWithPrecision( 1379 t, 1380 r.Fremote, 1381 files, 1382 []string{ 1383 "A2", 1384 "A2/B1", 1385 "A2/B2", 1386 "A2/B1/C1", 1387 "A2/B1/C2", 1388 "A2/B1/C3", 1389 }, 1390 fs.GetModifyWindow(r.Fremote), 1391 ) 1392 1393 // Disable DirMove 1394 features := r.Fremote.Features() 1395 oldDirMove := features.DirMove 1396 features.DirMove = nil 1397 defer func() { 1398 features.DirMove = oldDirMove 1399 }() 1400 1401 require.NoError(t, operations.DirMove(context.Background(), r.Fremote, "A2", "A3")) 1402 1403 for i := range files { 1404 files[i].Path = strings.Replace(files[i].Path, "A2/", "A3/", -1) 1405 } 1406 1407 fstest.CheckListingWithPrecision( 1408 t, 1409 r.Fremote, 1410 files, 1411 []string{ 1412 "A3", 1413 "A3/B1", 1414 "A3/B2", 1415 "A3/B1/C1", 1416 "A3/B1/C2", 1417 "A3/B1/C3", 1418 }, 1419 fs.GetModifyWindow(r.Fremote), 1420 ) 1421 1422 } 1423 1424 func TestGetFsInfo(t *testing.T) { 1425 r := fstest.NewRun(t) 1426 defer r.Finalise() 1427 1428 f := r.Fremote 1429 info := operations.GetFsInfo(f) 1430 assert.Equal(t, f.Name(), info.Name) 1431 assert.Equal(t, f.Root(), info.Root) 1432 assert.Equal(t, f.String(), info.String) 1433 assert.Equal(t, f.Precision(), info.Precision) 1434 hashSet := hash.NewHashSet() 1435 for _, hashName := range info.Hashes { 1436 var ht hash.Type 1437 require.NoError(t, ht.Set(hashName)) 1438 hashSet.Add(ht) 1439 } 1440 assert.Equal(t, f.Hashes(), hashSet) 1441 assert.Equal(t, f.Features().Enabled(), info.Features) 1442 }