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