| @@ -2,25 +2,24 @@ package gitannex · 1 unmodified line |
| 2 | | 2 | |
| 3 | import ( | 3 | import ( |
| 4 | "bufio" | 4 | "bufio" |
| 5 | "crypto/sha256" | 5 | "context" |
| 6 | "fmt" | 6 | "fmt" |
| 7 | "io" | 7 | "io" |
| 8 | "os" | 8 | "os" |
| 9 | "path/filepath" | 9 | "path/filepath" |
| 10 | "regexp" | 10 | "regexp" |
| | 11 | "runtime" |
| 11 | "strings" | 12 | "strings" |
| 12 | "sync" | 13 | "sync" |
| 13 | "testing" | 14 | "testing" |
| | 15 | "time" |
| 14 | | 16 | |
| 15 | // Without this import, the local filesystem backend would be unavailable. | 17 | // Without this import, the various backends would be unavailable. It looks |
| 16 | // It looks unused, but the act of importing it runs its `init()` function. | 18 | // unused, but the act of importing runs the package's `init()` function. |
| 17 | _ "github.com/rclone/rclone/backend/local" | 19 | _ "github.com/rclone/rclone/backend/all" |
| 18 | | 20 | |
| 19 | "github.com/rclone/rclone/fs" | 21 | "github.com/rclone/rclone/fs/fspath" |
| 20 | "github.com/rclone/rclone/fs/cache" | 22 | "github.com/rclone/rclone/fstest" |
| 21 | "github.com/rclone/rclone/fs/config" | | |
| 22 | "github.com/rclone/rclone/fs/config/configfile" | | |
| 23 | "github.com/rclone/rclone/fstest/mockfs" | | |
| 24 | | 23 | |
| 25 | "github.com/stretchr/testify/assert" | 24 | "github.com/stretchr/testify/assert" |
| 26 | "github.com/stretchr/testify/require" | 25 | "github.com/stretchr/testify/require" |
| @@ -256,9 +255,9 @@ type testState struct { · 229 unmodified lines |
| 256 | mockStdinW *io.PipeWriter | 255 | mockStdinW *io.PipeWriter |
| 257 | mockStdoutReader *bufio.Reader | 256 | mockStdoutReader *bufio.Reader |
| 258 | | 257 | |
| 259 | localFsDir string | 258 | fstestRun *fstest.Run |
| 260 | configPath string | 259 | remoteName string |
| 261 | remoteName string | 260 | remotePrefix string |
| 262 | } | 261 | } |
| 263 | | 262 | |
| 264 | func makeTestState(t *testing.T) testState { | 263 | func makeTestState(t *testing.T) testState { |
| @@ -276,6 +275,10 @@ func makeTestState(t *testing.T) testState { · 11 unmodified lines |
| 276 | } | 275 | } |
| 277 | } | 276 | } |
| 278 | | 277 | |
| | 278 | func (h *testState) requireRemoteIsEmpty() { |
| | 279 | h.fstestRun.CheckRemoteItems(h.t) |
| | 280 | } |
| | 281 | |
| 279 | func (h *testState) requireReadLineExact(line string) { | 282 | func (h *testState) requireReadLineExact(line string) { |
| 280 | receivedLine, err := h.mockStdoutReader.ReadString('\n') | 283 | receivedLine, err := h.mockStdoutReader.ReadString('\n') |
| 281 | require.NoError(h.t, err) | 284 | require.NoError(h.t, err) |
| @@ -296,21 +299,106 @@ func (h *testState) requireWriteLine(line string) { · 14 unmodified lines |
| 296 | // Preconfigure the handle. This enables the calling test to skip the PREPARE | 299 | // Preconfigure the handle. This enables the calling test to skip the PREPARE |
| 297 | // handshake. | 300 | // handshake. |
| 298 | func (h *testState) preconfigureServer() { | 301 | func (h *testState) preconfigureServer() { |
| 299 | h.server.configPrefix = h.localFsDir | | |
| 300 | h.server.configRcloneRemoteName = h.remoteName | 302 | h.server.configRcloneRemoteName = h.remoteName |
| | 303 | h.server.configPrefix = h.remotePrefix |
| 301 | h.server.configRcloneLayout = string(layoutModeNodir) | 304 | h.server.configRcloneLayout = string(layoutModeNodir) |
| 302 | h.server.configsDone = true | 305 | h.server.configsDone = true |
| 303 | } | 306 | } |
| 304 | | 307 | |
| 305 | // getUniqueRemoteName returns a valid remote name derived from the given test's | 308 | // Drop-in replacement for `filepath.Rel()` that works around a Windows-specific |
| 306 | // name. This is necessary because when a test registers a second remote with | 309 | // quirk when one of the paths begins with `\\?\` or `//?/`. It seems that |
| 307 | // the same name, the original remote appears to take precedence. This function | 310 | // fstest gives us paths with this prefix on Windows, which throws a wrench in |
| 308 | // is injective, so each test gets a unique remote name. Returned strings | 311 | // the gitannex tests that need to construct relative paths from absolute paths. |
| 309 | // contain no spaces. | 312 | // For a demonstration, see `TestWindowsFilepathRelQuirk` below. |
| 310 | func getUniqueRemoteName(t *testing.T) string { | 313 | // |
| 311 | // Using sha256 as a hack to ensure injectivity without adding a global | 314 | // The `\\?\` prefix tells Windows APIs to pass strings unmodified to the |
| 312 | // variable. | 315 | // filesystem without additional parsing [1]. Our workaround is roughly to add |
| 313 | return fmt.Sprintf("remote-%x", sha256.Sum256([]byte(t.Name()))) | 316 | // the prefix to whichever parameter doesn't have it (when the OS is Windows). |
| | 317 | // I'm not sure this generalizes, but it works for the the kinds of inputs we're |
| | 318 | // throwing at it. |
| | 319 | // |
| | 320 | // [1]: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#win32-file-namespaces |
| | 321 | func relativeFilepathWorkaround(basepath, targpath string) (string, error) { |
| | 322 | if runtime.GOOS != "windows" { |
| | 323 | return filepath.Rel(basepath, targpath) |
| | 324 | } |
| | 325 | // Canonicalize paths to use backslashes. |
| | 326 | basepath = filepath.Clean(basepath) |
| | 327 | targpath = filepath.Clean(targpath) |
| | 328 | |
| | 329 | const winFilePrefixDisableStringParsing = `\\?\` |
| | 330 | baseHasPrefix := strings.HasPrefix(basepath, winFilePrefixDisableStringParsing) |
| | 331 | targHasPrefix := strings.HasPrefix(targpath, winFilePrefixDisableStringParsing) |
| | 332 | |
| | 333 | if baseHasPrefix && !targHasPrefix { |
| | 334 | targpath = winFilePrefixDisableStringParsing + targpath |
| | 335 | } |
| | 336 | if !baseHasPrefix && targHasPrefix { |
| | 337 | basepath = winFilePrefixDisableStringParsing + basepath |
| | 338 | } |
| | 339 | return filepath.Rel(basepath, targpath) |
| | 340 | } |
| | 341 | |
| | 342 | func TestWindowsFilepathRelQuirk(t *testing.T) { |
| | 343 | if runtime.GOOS != "windows" { |
| | 344 | t.Skip() |
| | 345 | } |
| | 346 | |
| | 347 | t.Run("filepathRelQuirk", func(t *testing.T) { |
| | 348 | var err error |
| | 349 | |
| | 350 | _, err = filepath.Rel(`C:\foo`, `\\?\C:\foo\bar`) |
| | 351 | require.Error(t, err) |
| | 352 | |
| | 353 | _, err = filepath.Rel(`C:/foo`, `//?/C:/foo/bar`) |
| | 354 | require.Error(t, err) |
| | 355 | |
| | 356 | _, err = filepath.Rel(`\\?\C:\foo`, `C:\foo\bar`) |
| | 357 | require.Error(t, err) |
| | 358 | |
| | 359 | _, err = filepath.Rel(`//?/C:/foo`, `C:/foo/bar`) |
| | 360 | require.Error(t, err) |
| | 361 | |
| | 362 | path, err := filepath.Rel(`\\?\C:\foo`, `\\?\C:\foo\bar`) |
| | 363 | require.NoError(t, err) |
| | 364 | require.Equal(t, path, `bar`) |
| | 365 | |
| | 366 | path, err = filepath.Rel(`//?/C:/foo`, `//?/C:/foo/bar`) |
| | 367 | require.NoError(t, err) |
| | 368 | require.Equal(t, path, `bar`) |
| | 369 | }) |
| | 370 | |
| | 371 | t.Run("fstestAndTempDirHaveDifferentPrefixes", func(t *testing.T) { |
| | 372 | r := fstest.NewRun(t) |
| | 373 | p := r.Flocal.Root() |
| | 374 | require.True(t, strings.HasPrefix(p, `//?/`)) |
| | 375 | |
| | 376 | tempDir := t.TempDir() |
| | 377 | require.False(t, strings.HasPrefix(tempDir, `//?/`)) |
| | 378 | require.False(t, strings.HasPrefix(tempDir, `\\?\`)) |
| | 379 | }) |
| | 380 | |
| | 381 | t.Run("workaroundWorks", func(t *testing.T) { |
| | 382 | path, err := relativeFilepathWorkaround(`C:\foo`, `\\?\C:\foo\bar`) |
| | 383 | require.NoError(t, err) |
| | 384 | require.Equal(t, path, "bar") |
| | 385 | |
| | 386 | path, err = relativeFilepathWorkaround(`C:/foo`, `//?/C:/foo/bar`) |
| | 387 | require.NoError(t, err) |
| | 388 | require.Equal(t, path, "bar") |
| | 389 | |
| | 390 | path, err = relativeFilepathWorkaround(`\\?\C:\foo`, `C:\foo\bar`) |
| | 391 | require.NoError(t, err) |
| | 392 | require.Equal(t, path, `bar`) |
| | 393 | |
| | 394 | path, err = relativeFilepathWorkaround(`//?/C:/foo`, `C:/foo/bar`) |
| | 395 | require.NoError(t, err) |
| | 396 | require.Equal(t, path, `bar`) |
| | 397 | |
| | 398 | path, err = relativeFilepathWorkaround(`\\?\C:\foo`, `\\?\C:\foo\bar`) |
| | 399 | require.NoError(t, err) |
| | 400 | require.Equal(t, path, `bar`) |
| | 401 | }) |
| 314 | } | 402 | } |
| 315 | | 403 | |
| 316 | type testCase struct { | 404 | type testCase struct { |
| @@ -319,8 +407,8 @@ type testCase struct { · 2 unmodified lines |
| 319 | expectedError string | 407 | expectedError string |
| 320 | } | 408 | } |
| 321 | | 409 | |
| 322 | // These test cases run against the "local" backend. | 410 | // These test cases run against a backend selected by the `-remote` flag. |
| 323 | var localBackendTestCases = []testCase{ | 411 | var fstestTestCases = []testCase{ |
| 324 | { | 412 | { |
| 325 | label: "HandlesInit", | 413 | label: "HandlesInit", |
| 326 | testProtocolFunc: func(t *testing.T, h *testState) { | 414 | testProtocolFunc: func(t *testing.T, h *testState) { |
| @@ -377,17 +465,85 @@ var localBackendTestCases = []testCase{ · 50 unmodified lines |
| 377 | h.requireReadLineExact("GETCONFIG rcloneremotename") | 465 | h.requireReadLineExact("GETCONFIG rcloneremotename") |
| 378 | h.requireWriteLine("VALUE " + h.remoteName) | 466 | h.requireWriteLine("VALUE " + h.remoteName) |
| 379 | h.requireReadLineExact("GETCONFIG rcloneprefix") | 467 | h.requireReadLineExact("GETCONFIG rcloneprefix") |
| 380 | h.requireWriteLine("VALUE " + h.localFsDir) | 468 | h.requireWriteLine("VALUE " + h.remotePrefix) |
| 381 | h.requireReadLineExact("GETCONFIG rclonelayout") | 469 | h.requireReadLineExact("GETCONFIG rclonelayout") |
| 382 | h.requireWriteLine("VALUE foo") | 470 | h.requireWriteLine("VALUE foo") |
| 383 | h.requireReadLineExact("PREPARE-SUCCESS") | 471 | h.requireReadLineExact("PREPARE-SUCCESS") |
| 384 | | 472 | |
| 385 | require.Equal(t, h.server.configRcloneRemoteName, h.remoteName) | 473 | require.Equal(t, h.server.configRcloneRemoteName, h.remoteName) |
| 386 | require.Equal(t, h.server.configPrefix, h.localFsDir) | 474 | require.Equal(t, h.server.configPrefix, h.remotePrefix) |
| | 475 | require.True(t, h.server.configsDone) |
| | 476 | |
| | 477 | require.NoError(t, h.mockStdinW.Close()) |
| | 478 | }, |
| | 479 | }, |
| | 480 | { |
| | 481 | label: "HandlesPrepareWithNonexistentRemote", |
| | 482 | testProtocolFunc: func(t *testing.T, h *testState) { |
| | 483 | h.requireReadLineExact("VERSION 1") |
| | 484 | h.requireWriteLine("EXTENSIONS INFO") // Advertise that we support the INFO extension |
| | 485 | h.requireReadLineExact("EXTENSIONS") |
| | 486 | |
| | 487 | if !h.server.extensionInfo { |
| | 488 | t.Errorf("expected INFO extension to be enabled") |
| | 489 | return |
| | 490 | } |
| | 491 | |
| | 492 | h.requireWriteLine("PREPARE") |
| | 493 | h.requireReadLineExact("GETCONFIG rcloneremotename") |
| | 494 | h.requireWriteLine("VALUE thisRemoteDoesNotExist") |
| | 495 | h.requireReadLineExact("GETCONFIG rcloneprefix") |
| | 496 | h.requireWriteLine("VALUE " + h.remotePrefix) |
| | 497 | h.requireReadLineExact("GETCONFIG rclonelayout") |
| | 498 | h.requireWriteLine("VALUE foo") |
| | 499 | h.requireReadLineExact("PREPARE-SUCCESS") |
| | 500 | |
| | 501 | require.Equal(t, h.server.configRcloneRemoteName, "thisRemoteDoesNotExist") |
| | 502 | require.Equal(t, h.server.configPrefix, h.remotePrefix) |
| | 503 | require.True(t, h.server.configsDone) |
| | 504 | |
| | 505 | h.requireWriteLine("INITREMOTE") |
| | 506 | h.requireReadLineExact("INITREMOTE-FAILURE remote does not exist: thisRemoteDoesNotExist") |
| | 507 | |
| | 508 | require.NoError(t, h.mockStdinW.Close()) |
| | 509 | }, |
| | 510 | expectedError: "remote does not exist: thisRemoteDoesNotExist", |
| | 511 | }, |
| | 512 | { |
| | 513 | label: "HandlesPrepareWithPathAsRemote", |
| | 514 | testProtocolFunc: func(t *testing.T, h *testState) { |
| | 515 | h.requireReadLineExact("VERSION 1") |
| | 516 | h.requireWriteLine("EXTENSIONS INFO") // Advertise that we support the INFO extension |
| | 517 | h.requireReadLineExact("EXTENSIONS") |
| | 518 | |
| | 519 | if !h.server.extensionInfo { |
| | 520 | t.Errorf("expected INFO extension to be enabled") |
| | 521 | return |
| | 522 | } |
| | 523 | |
| | 524 | h.requireWriteLine("PREPARE") |
| | 525 | h.requireReadLineExact("GETCONFIG rcloneremotename") |
| | 526 | h.requireWriteLine("VALUE " + h.remotePrefix) |
| | 527 | h.requireReadLineExact("GETCONFIG rcloneprefix") |
| | 528 | h.requireWriteLine("VALUE /foo") |
| | 529 | h.requireReadLineExact("GETCONFIG rclonelayout") |
| | 530 | h.requireWriteLine("VALUE foo") |
| | 531 | h.requireReadLineExact("PREPARE-SUCCESS") |
| | 532 | |
| | 533 | require.Equal(t, h.server.configRcloneRemoteName, h.remotePrefix) |
| | 534 | require.Equal(t, h.server.configPrefix, "/foo") |
| 387 | require.True(t, h.server.configsDone) | 535 | require.True(t, h.server.configsDone) |
| 388 | | 536 | |
| | 537 | h.requireWriteLine("INITREMOTE") |
| | 538 | |
| | 539 | require.Regexp(t, |
| | 540 | regexp.MustCompile("^INITREMOTE-FAILURE remote does not exist: "), |
| | 541 | h.requireReadLine(), |
| | 542 | ) |
| | 543 | |
| 389 | require.NoError(t, h.mockStdinW.Close()) | 544 | require.NoError(t, h.mockStdinW.Close()) |
| 390 | }, | 545 | }, |
| | 546 | expectedError: "remote does not exist:", |
| 391 | }, | 547 | }, |
| 392 | { | 548 | { |
| 393 | label: "HandlesPrepareWithSynonyms", | 549 | label: "HandlesPrepareWithSynonyms", |
| @@ -409,13 +565,13 @@ var localBackendTestCases = []testCase{ · 15 unmodified lines |
| 409 | h.requireWriteLine("VALUE " + h.remoteName) | 565 | h.requireWriteLine("VALUE " + h.remoteName) |
| 410 | | 566 | |
| 411 | h.requireReadLineExact("GETCONFIG rcloneprefix") | 567 | h.requireReadLineExact("GETCONFIG rcloneprefix") |
| 412 | h.requireWriteLine("VALUE " + h.localFsDir) | 568 | h.requireWriteLine("VALUE " + h.remotePrefix) |
| 413 | h.requireReadLineExact("GETCONFIG rclonelayout") | 569 | h.requireReadLineExact("GETCONFIG rclonelayout") |
| 414 | h.requireWriteLine("VALUE foo") | 570 | h.requireWriteLine("VALUE foo") |
| 415 | h.requireReadLineExact("PREPARE-SUCCESS") | 571 | h.requireReadLineExact("PREPARE-SUCCESS") |
| 416 | | 572 | |
| 417 | require.Equal(t, h.server.configRcloneRemoteName, h.remoteName) | 573 | require.Equal(t, h.server.configRcloneRemoteName, h.remoteName) |
| 418 | require.Equal(t, h.server.configPrefix, h.localFsDir) | 574 | require.Equal(t, h.server.configPrefix, h.remotePrefix) |
| 419 | require.True(t, h.server.configsDone) | 575 | require.True(t, h.server.configsDone) |
| 420 | | 576 | |
| 421 | require.NoError(t, h.mockStdinW.Close()) | 577 | require.NoError(t, h.mockStdinW.Close()) |
| @@ -437,12 +593,12 @@ var localBackendTestCases = []testCase{ · 15 unmodified lines |
| 437 | h.requireReadLineExact("GETCONFIG rcloneremotename") | 593 | h.requireReadLineExact("GETCONFIG rcloneremotename") |
| 438 | | 594 | |
| 439 | remoteNameWithSpaces := fmt.Sprintf(" %s ", h.remoteName) | 595 | remoteNameWithSpaces := fmt.Sprintf(" %s ", h.remoteName) |
| 440 | localFsDirWithSpaces := fmt.Sprintf(" %s\t", h.localFsDir) | 596 | prefixWithWhitespace := fmt.Sprintf(" %s\t", h.remotePrefix) |
| 441 | | 597 | |
| 442 | h.requireWriteLine(fmt.Sprintf("VALUE %s", remoteNameWithSpaces)) | 598 | h.requireWriteLine(fmt.Sprintf("VALUE %s", remoteNameWithSpaces)) |
| 443 | | 599 | |
| 444 | h.requireReadLineExact("GETCONFIG rcloneprefix") | 600 | h.requireReadLineExact("GETCONFIG rcloneprefix") |
| 445 | h.requireWriteLine(fmt.Sprintf("VALUE %s", localFsDirWithSpaces)) | 601 | h.requireWriteLine(fmt.Sprintf("VALUE %s", prefixWithWhitespace)) |
| 446 | | 602 | |
| 447 | h.requireReadLineExact("GETCONFIG rclonelayout") | 603 | h.requireReadLineExact("GETCONFIG rclonelayout") |
| 448 | h.requireWriteLine("VALUE") | 604 | h.requireWriteLine("VALUE") |
| @@ -452,7 +608,7 @@ var localBackendTestCases = []testCase{ · 3 unmodified lines |
| 452 | h.requireReadLineExact("PREPARE-SUCCESS") | 608 | h.requireReadLineExact("PREPARE-SUCCESS") |
| 453 | | 609 | |
| 454 | require.Equal(t, h.server.configRcloneRemoteName, remoteNameWithSpaces) | 610 | require.Equal(t, h.server.configRcloneRemoteName, remoteNameWithSpaces) |
| 455 | require.Equal(t, h.server.configPrefix, localFsDirWithSpaces) | 611 | require.Equal(t, h.server.configPrefix, prefixWithWhitespace) |
| 456 | require.True(t, h.server.configsDone) | 612 | require.True(t, h.server.configsDone) |
| 457 | | 613 | |
| 458 | require.NoError(t, h.mockStdinW.Close()) | 614 | require.NoError(t, h.mockStdinW.Close()) |
| @@ -639,20 +795,25 @@ var localBackendTestCases = []testCase{ · 180 unmodified lines |
| 639 | h.requireReadLineExact("INITREMOTE-SUCCESS") | 795 | h.requireReadLineExact("INITREMOTE-SUCCESS") |
| 640 | | 796 | |
| 641 | // Create temp file for transfer with an absolute path. | 797 | // Create temp file for transfer with an absolute path. |
| 642 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | 798 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 643 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 799 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| 644 | require.FileExists(t, fileToTransfer) | 800 | require.True(t, filepath.IsAbs(absPath)) |
| 645 | require.True(t, filepath.IsAbs(fileToTransfer)) | | |
| 646 | | 801 | |
| 647 | // Specify an absolute path to transfer. | 802 | // Specify an absolute path to transfer. |
| 648 | h.requireWriteLine("TRANSFER STORE KeyAbsolute " + fileToTransfer) | 803 | h.requireWriteLine("TRANSFER STORE KeyAbsolute " + absPath) |
| 649 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyAbsolute") | 804 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyAbsolute") |
| 650 | require.FileExists(t, filepath.Join(h.localFsDir, "KeyAbsolute")) | 805 | |
| | 806 | // Check that the file was transferred. |
| | 807 | remoteItem := fstest.NewItem("KeyAbsolute", "HELLO", item.ModTime) |
| | 808 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 651 | | 809 | |
| 652 | // Transfer the same absolute path a second time, but with a different key. | 810 | // Transfer the same absolute path a second time, but with a different key. |
| 653 | h.requireWriteLine("TRANSFER STORE KeyAbsolute2 " + fileToTransfer) | 811 | h.requireWriteLine("TRANSFER STORE KeyAbsolute2 " + absPath) |
| 654 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyAbsolute2") | 812 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyAbsolute2") |
| 655 | require.FileExists(t, filepath.Join(h.localFsDir, "KeyAbsolute2")) | 813 | |
| | 814 | // Check that the same file was transferred to a new name. |
| | 815 | remoteItem2 := fstest.NewItem("KeyAbsolute2", "HELLO", item.ModTime) |
| | 816 | h.fstestRun.CheckRemoteItems(t, remoteItem, remoteItem2) |
| 656 | | 817 | |
| 657 | h.requireWriteLine("CHECKPRESENT KeyAbsolute2") | 818 | h.requireWriteLine("CHECKPRESENT KeyAbsolute2") |
| 658 | h.requireReadLineExact("CHECKPRESENT-SUCCESS KeyAbsolute2") | 819 | h.requireReadLineExact("CHECKPRESENT-SUCCESS KeyAbsolute2") |
| @@ -668,30 +829,36 @@ var localBackendTestCases = []testCase{ · 9 unmodified lines |
| 668 | { | 829 | { |
| 669 | label: "TransferStoreRelative", | 830 | label: "TransferStoreRelative", |
| 670 | testProtocolFunc: func(t *testing.T, h *testState) { | 831 | testProtocolFunc: func(t *testing.T, h *testState) { |
| 671 | h.preconfigureServer() | | |
| 672 | | | |
| 673 | // Save the current working directory so we can restore it when this | 832 | // Save the current working directory so we can restore it when this |
| 674 | // test ends. | 833 | // test ends. |
| 675 | cwd, err := os.Getwd() | 834 | cwd, err := os.Getwd() |
| 676 | require.NoError(t, err) | 835 | require.NoError(t, err) |
| 677 | | 836 | |
| 678 | require.NoError(t, os.Chdir(t.TempDir())) | 837 | tempDir := t.TempDir() |
| | 838 | |
| | 839 | require.NoError(t, os.Chdir(tempDir)) |
| 679 | t.Cleanup(func() { require.NoError(t, os.Chdir(cwd)) }) | 840 | t.Cleanup(func() { require.NoError(t, os.Chdir(cwd)) }) |
| 680 | | 841 | |
| | 842 | h.preconfigureServer() |
| | 843 | |
| 681 | h.requireReadLineExact("VERSION 1") | 844 | h.requireReadLineExact("VERSION 1") |
| 682 | h.requireWriteLine("INITREMOTE") | 845 | h.requireWriteLine("INITREMOTE") |
| 683 | h.requireReadLineExact("INITREMOTE-SUCCESS") | 846 | h.requireReadLineExact("INITREMOTE-SUCCESS") |
| 684 | | 847 | |
| 685 | // Create temp file for transfer with a relative path. | 848 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 686 | fileToTransfer := "file.txt" | 849 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| 687 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 850 | |
| 688 | require.FileExists(t, fileToTransfer) | 851 | relativePath, err := relativeFilepathWorkaround(tempDir, absPath) |
| 689 | require.False(t, filepath.IsAbs(fileToTransfer)) | 852 | require.NoError(t, err) |
| | 853 | require.False(t, filepath.IsAbs(relativePath)) |
| | 854 | require.FileExists(t, relativePath) |
| 690 | | 855 | |
| 691 | // Specify a relative path to transfer. | 856 | // Specify a relative path to transfer. |
| 692 | h.requireWriteLine("TRANSFER STORE KeyRelative " + fileToTransfer) | 857 | h.requireWriteLine("TRANSFER STORE KeyRelative " + relativePath) |
| 693 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyRelative") | 858 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyRelative") |
| 694 | require.FileExists(t, filepath.Join(h.localFsDir, "KeyRelative")) | 859 | |
| | 860 | remoteItem := fstest.NewItem("KeyRelative", "HELLO", item.ModTime) |
| | 861 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 695 | | 862 | |
| 696 | h.requireWriteLine("CHECKPRESENT KeyRelative") | 863 | h.requireWriteLine("CHECKPRESENT KeyRelative") |
| 697 | h.requireReadLineExact("CHECKPRESENT-SUCCESS KeyRelative") | 864 | h.requireReadLineExact("CHECKPRESENT-SUCCESS KeyRelative") |
| @@ -710,7 +877,8 @@ var localBackendTestCases = []testCase{ · 12 unmodified lines |
| 710 | cwd, err := os.Getwd() | 877 | cwd, err := os.Getwd() |
| 711 | require.NoError(t, err) | 878 | require.NoError(t, err) |
| 712 | | 879 | |
| 713 | require.NoError(t, os.Chdir(t.TempDir())) | 880 | tempDir := t.TempDir() |
| | 881 | require.NoError(t, os.Chdir(tempDir)) |
| 714 | t.Cleanup(func() { require.NoError(t, os.Chdir(cwd)) }) | 882 | t.Cleanup(func() { require.NoError(t, os.Chdir(cwd)) }) |
| 715 | | 883 | |
| 716 | h.preconfigureServer() | 884 | h.preconfigureServer() |
| @@ -720,15 +888,19 @@ var localBackendTestCases = []testCase{ · 3 unmodified lines |
| 720 | h.requireReadLineExact("INITREMOTE-SUCCESS") | 888 | h.requireReadLineExact("INITREMOTE-SUCCESS") |
| 721 | | 889 | |
| 722 | // Create temp file for transfer. | 890 | // Create temp file for transfer. |
| 723 | fileToTransfer := "filename with spaces.txt" | 891 | item := h.fstestRun.WriteFile("filename with spaces.txt", "HELLO", time.Now()) |
| 724 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 892 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| 725 | require.FileExists(t, fileToTransfer) | 893 | relativePath, err := relativeFilepathWorkaround(tempDir, absPath) |
| 726 | require.False(t, filepath.IsAbs(fileToTransfer)) | 894 | require.NoError(t, err) |
| | 895 | require.False(t, filepath.IsAbs(relativePath)) |
| | 896 | require.FileExists(t, relativePath) |
| 727 | | 897 | |
| 728 | // Specify a relative path to transfer. | 898 | // Specify a relative path to transfer. |
| 729 | h.requireWriteLine("TRANSFER STORE KeyRelative " + fileToTransfer) | 899 | h.requireWriteLine("TRANSFER STORE KeyRelative " + relativePath) |
| 730 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyRelative") | 900 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyRelative") |
| 731 | require.FileExists(t, filepath.Join(h.localFsDir, "KeyRelative")) | 901 | |
| | 902 | remoteItem := fstest.NewItem("KeyRelative", "HELLO", item.ModTime) |
| | 903 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 732 | | 904 | |
| 733 | h.requireWriteLine("CHECKPRESENT KeyRelative") | 905 | h.requireWriteLine("CHECKPRESENT KeyRelative") |
| 734 | h.requireReadLineExact("CHECKPRESENT-SUCCESS KeyRelative") | 906 | h.requireReadLineExact("CHECKPRESENT-SUCCESS KeyRelative") |
| @@ -745,8 +917,9 @@ var localBackendTestCases = []testCase{ · 10 unmodified lines |
| 745 | h.preconfigureServer() | 917 | h.preconfigureServer() |
| 746 | | 918 | |
| 747 | // Create temp file for transfer. | 919 | // Create temp file for transfer. |
| 748 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | 920 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 749 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 921 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| | 922 | require.True(t, filepath.IsAbs(absPath)) |
| 750 | | 923 | |
| 751 | h.requireReadLineExact("VERSION 1") | 924 | h.requireReadLineExact("VERSION 1") |
| 752 | h.requireWriteLine("INITREMOTE") | 925 | h.requireWriteLine("INITREMOTE") |
| @@ -756,10 +929,11 @@ var localBackendTestCases = []testCase{ · 3 unmodified lines |
| 756 | h.requireReadLineExact("CHECKPRESENT-FAILURE KeyThatDoesNotExist") | 929 | h.requireReadLineExact("CHECKPRESENT-FAILURE KeyThatDoesNotExist") |
| 757 | | 930 | |
| 758 | // Specify an absolute path to transfer. | 931 | // Specify an absolute path to transfer. |
| 759 | require.True(t, filepath.IsAbs(fileToTransfer)) | 932 | h.requireWriteLine("TRANSFER STORE KeyAbsolute " + absPath) |
| 760 | h.requireWriteLine("TRANSFER STORE KeyAbsolute " + fileToTransfer) | | |
| 761 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyAbsolute") | 933 | h.requireReadLineExact("TRANSFER-SUCCESS STORE KeyAbsolute") |
| 762 | require.FileExists(t, filepath.Join(h.localFsDir, "KeyAbsolute")) | 934 | |
| | 935 | remoteItem := fstest.NewItem("KeyAbsolute", "HELLO", item.ModTime) |
| | 936 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 763 | | 937 | |
| 764 | require.NoError(t, h.mockStdinW.Close()) | 938 | require.NoError(t, h.mockStdinW.Close()) |
| 765 | }, | 939 | }, |
| @@ -781,8 +955,9 @@ var localBackendTestCases = []testCase{ · 15 unmodified lines |
| 781 | h.preconfigureServer() | 955 | h.preconfigureServer() |
| 782 | | 956 | |
| 783 | // Create temp file for transfer. | 957 | // Create temp file for transfer. |
| 784 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | 958 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 785 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 959 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| | 960 | require.True(t, filepath.IsAbs(absPath)) |
| 786 | | 961 | |
| 787 | h.requireReadLineExact("VERSION 1") | 962 | h.requireReadLineExact("VERSION 1") |
| 788 | h.requireWriteLine("INITREMOTE") | 963 | h.requireWriteLine("INITREMOTE") |
| @@ -791,9 +966,11 @@ var localBackendTestCases = []testCase{ · 2 unmodified lines |
| 791 | h.requireWriteLine("CHECKPRESENT foo") | 966 | h.requireWriteLine("CHECKPRESENT foo") |
| 792 | h.requireReadLineExact("CHECKPRESENT-FAILURE foo") | 967 | h.requireReadLineExact("CHECKPRESENT-FAILURE foo") |
| 793 | | 968 | |
| 794 | h.requireWriteLine("TRANSFER STORE foo " + fileToTransfer) | 969 | h.requireWriteLine("TRANSFER STORE foo " + absPath) |
| 795 | h.requireReadLineExact("TRANSFER-SUCCESS STORE foo") | 970 | h.requireReadLineExact("TRANSFER-SUCCESS STORE foo") |
| 796 | require.FileExists(t, filepath.Join(h.localFsDir, "foo")) | 971 | |
| | 972 | remoteItem := fstest.NewItem("foo", "HELLO", item.ModTime) |
| | 973 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 797 | | 974 | |
| 798 | h.requireWriteLine("CHECKPRESENT foo") | 975 | h.requireWriteLine("CHECKPRESENT foo") |
| 799 | h.requireReadLineExact("CHECKPRESENT-SUCCESS foo") | 976 | h.requireReadLineExact("CHECKPRESENT-SUCCESS foo") |
| @@ -807,8 +984,9 @@ var localBackendTestCases = []testCase{ · 7 unmodified lines |
| 807 | h.preconfigureServer() | 984 | h.preconfigureServer() |
| 808 | | 985 | |
| 809 | // Create temp file for transfer. | 986 | // Create temp file for transfer. |
| 810 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | 987 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 811 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 988 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| | 989 | require.True(t, filepath.IsAbs(absPath)) |
| 812 | | 990 | |
| 813 | h.requireReadLineExact("VERSION 1") | 991 | h.requireReadLineExact("VERSION 1") |
| 814 | h.requireWriteLine("INITREMOTE") | 992 | h.requireWriteLine("INITREMOTE") |
| @@ -817,10 +995,11 @@ var localBackendTestCases = []testCase{ · 2 unmodified lines |
| 817 | realisticKey := "SHA256E-s1048576--7ba87e06b9b7903cfbaf4a38736766c161e3e7b42f06fe57f040aa410a8f0701.this-is-a-test-key" | 995 | realisticKey := "SHA256E-s1048576--7ba87e06b9b7903cfbaf4a38736766c161e3e7b42f06fe57f040aa410a8f0701.this-is-a-test-key" |
| 818 | | 996 | |
| 819 | // Specify an absolute path to transfer. | 997 | // Specify an absolute path to transfer. |
| 820 | require.True(t, filepath.IsAbs(fileToTransfer)) | 998 | h.requireWriteLine(fmt.Sprintf("TRANSFER STORE %s %s", realisticKey, absPath)) |
| 821 | h.requireWriteLine(fmt.Sprintf("TRANSFER STORE %s %s", realisticKey, fileToTransfer)) | | |
| 822 | h.requireReadLineExact("TRANSFER-SUCCESS STORE " + realisticKey) | 999 | h.requireReadLineExact("TRANSFER-SUCCESS STORE " + realisticKey) |
| 823 | require.FileExists(t, filepath.Join(h.localFsDir, realisticKey)) | 1000 | |
| | 1001 | remoteItem := fstest.NewItem(realisticKey, "HELLO", item.ModTime) |
| | 1002 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 824 | | 1003 | |
| 825 | h.requireWriteLine("CHECKPRESENT " + realisticKey) | 1004 | h.requireWriteLine("CHECKPRESENT " + realisticKey) |
| 826 | h.requireReadLineExact("CHECKPRESENT-SUCCESS " + realisticKey) | 1005 | h.requireReadLineExact("CHECKPRESENT-SUCCESS " + realisticKey) |
| @@ -849,27 +1028,36 @@ var localBackendTestCases = []testCase{ · 22 unmodified lines |
| 849 | h.preconfigureServer() | 1028 | h.preconfigureServer() |
| 850 | | 1029 | |
| 851 | // Create temp file for transfer. | 1030 | // Create temp file for transfer. |
| 852 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | 1031 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 853 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 1032 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| | 1033 | require.True(t, filepath.IsAbs(absPath)) |
| 854 | | 1034 | |
| 855 | h.requireReadLineExact("VERSION 1") | 1035 | h.requireReadLineExact("VERSION 1") |
| 856 | h.requireWriteLine("INITREMOTE") | 1036 | h.requireWriteLine("INITREMOTE") |
| 857 | h.requireReadLineExact("INITREMOTE-SUCCESS") | 1037 | h.requireReadLineExact("INITREMOTE-SUCCESS") |
| 858 | | 1038 | |
| 859 | // Specify an absolute path to transfer. | 1039 | // Specify an absolute path to transfer. |
| 860 | require.True(t, filepath.IsAbs(fileToTransfer)) | 1040 | h.requireWriteLine("TRANSFER STORE SomeKey " + absPath) |
| 861 | h.requireWriteLine("TRANSFER STORE SomeKey " + fileToTransfer) | | |
| 862 | h.requireReadLineExact("TRANSFER-SUCCESS STORE SomeKey") | 1041 | h.requireReadLineExact("TRANSFER-SUCCESS STORE SomeKey") |
| 863 | require.FileExists(t, filepath.Join(h.localFsDir, "SomeKey")) | 1042 | |
| | 1043 | remoteItem := fstest.NewItem("SomeKey", "HELLO", item.ModTime) |
| | 1044 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 864 | | 1045 | |
| 865 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1046 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 866 | h.requireReadLineExact("CHECKPRESENT-SUCCESS SomeKey") | 1047 | h.requireReadLineExact("CHECKPRESENT-SUCCESS SomeKey") |
| 867 | | 1048 | |
| 868 | retrievedFilePath := fileToTransfer + ".retrieved" | 1049 | h.fstestRun.CheckLocalItems(t, |
| 869 | require.NoFileExists(t, retrievedFilePath) | 1050 | fstest.NewItem("file.txt", "HELLO", item.ModTime), |
| | 1051 | ) |
| | 1052 | |
| | 1053 | retrievedFilePath := absPath + ".retrieved" |
| 870 | h.requireWriteLine("TRANSFER RETRIEVE SomeKey " + retrievedFilePath) | 1054 | h.requireWriteLine("TRANSFER RETRIEVE SomeKey " + retrievedFilePath) |
| 871 | h.requireReadLineExact("TRANSFER-SUCCESS RETRIEVE SomeKey") | 1055 | h.requireReadLineExact("TRANSFER-SUCCESS RETRIEVE SomeKey") |
| 872 | require.FileExists(t, retrievedFilePath) | 1056 | |
| | 1057 | h.fstestRun.CheckLocalItems(t, |
| | 1058 | fstest.NewItem("file.txt", "HELLO", item.ModTime), |
| | 1059 | fstest.NewItem("file.txt.retrieved", "HELLO", item.ModTime), |
| | 1060 | ) |
| 873 | | 1061 | |
| 874 | require.NoError(t, h.mockStdinW.Close()) | 1062 | require.NoError(t, h.mockStdinW.Close()) |
| 875 | }, | 1063 | }, |
| @@ -879,11 +1067,13 @@ var localBackendTestCases = []testCase{ · 3 unmodified lines |
| 879 | testProtocolFunc: func(t *testing.T, h *testState) { | 1067 | testProtocolFunc: func(t *testing.T, h *testState) { |
| 880 | h.preconfigureServer() | 1068 | h.preconfigureServer() |
| 881 | | 1069 | |
| | 1070 | ctx := context.WithoutCancel(context.Background()) |
| | 1071 | |
| 882 | // Write a file into the remote without using the git-annex | 1072 | // Write a file into the remote without using the git-annex |
| 883 | // protocol. | 1073 | // protocol. |
| 884 | remoteFilePath := filepath.Join(h.localFsDir, "SomeKey") | 1074 | remoteItem := h.fstestRun.WriteObject(ctx, "SomeKey", "HELLO", time.Now()) |
| 885 | require.NoError(t, os.WriteFile(remoteFilePath, []byte("HELLO"), 0600)) | 1075 | |
| 886 | require.FileExists(t, remoteFilePath) | 1076 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 887 | | 1077 | |
| 888 | h.requireReadLineExact("VERSION 1") | 1078 | h.requireReadLineExact("VERSION 1") |
| 889 | h.requireWriteLine("INITREMOTE") | 1079 | h.requireWriteLine("INITREMOTE") |
| @@ -891,15 +1081,18 @@ var localBackendTestCases = []testCase{ · 1 unmodified line |
| 891 | | 1081 | |
| 892 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1082 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 893 | h.requireReadLineExact("CHECKPRESENT-SUCCESS SomeKey") | 1083 | h.requireReadLineExact("CHECKPRESENT-SUCCESS SomeKey") |
| 894 | require.FileExists(t, remoteFilePath) | 1084 | |
| | 1085 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 895 | | 1086 | |
| 896 | h.requireWriteLine("REMOVE SomeKey") | 1087 | h.requireWriteLine("REMOVE SomeKey") |
| 897 | h.requireReadLineExact("REMOVE-SUCCESS SomeKey") | 1088 | h.requireReadLineExact("REMOVE-SUCCESS SomeKey") |
| 898 | require.NoFileExists(t, remoteFilePath) | 1089 | |
| | 1090 | h.requireRemoteIsEmpty() |
| 899 | | 1091 | |
| 900 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1092 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 901 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") | 1093 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") |
| 902 | require.NoFileExists(t, remoteFilePath) | 1094 | |
| | 1095 | h.requireRemoteIsEmpty() |
| 903 | | 1096 | |
| 904 | require.NoError(t, h.mockStdinW.Close()) | 1097 | require.NoError(t, h.mockStdinW.Close()) |
| 905 | }, | 1098 | }, |
| @@ -910,8 +1103,9 @@ var localBackendTestCases = []testCase{ · 4 unmodified lines |
| 910 | h.preconfigureServer() | 1103 | h.preconfigureServer() |
| 911 | | 1104 | |
| 912 | // Create temp file for transfer. | 1105 | // Create temp file for transfer. |
| 913 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | 1106 | item := h.fstestRun.WriteFile("file.txt", "HELLO", time.Now()) |
| 914 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | 1107 | absPath := filepath.Join(h.fstestRun.Flocal.Root(), item.Path) |
| | 1108 | require.True(t, filepath.IsAbs(absPath)) |
| 915 | | 1109 | |
| 916 | h.requireReadLineExact("VERSION 1") | 1110 | h.requireReadLineExact("VERSION 1") |
| 917 | h.requireWriteLine("INITREMOTE") | 1111 | h.requireWriteLine("INITREMOTE") |
| @@ -921,17 +1115,19 @@ var localBackendTestCases = []testCase{ · 3 unmodified lines |
| 921 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") | 1115 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") |
| 922 | | 1116 | |
| 923 | // Specify an absolute path to transfer. | 1117 | // Specify an absolute path to transfer. |
| 924 | require.True(t, filepath.IsAbs(fileToTransfer)) | 1118 | h.requireWriteLine("TRANSFER STORE SomeKey " + absPath) |
| 925 | h.requireWriteLine("TRANSFER STORE SomeKey " + fileToTransfer) | | |
| 926 | h.requireReadLineExact("TRANSFER-SUCCESS STORE SomeKey") | 1119 | h.requireReadLineExact("TRANSFER-SUCCESS STORE SomeKey") |
| 927 | require.FileExists(t, filepath.Join(h.localFsDir, "SomeKey")) | 1120 | |
| | 1121 | remoteItem := fstest.NewItem("SomeKey", "HELLO", item.ModTime) |
| | 1122 | h.fstestRun.CheckRemoteItems(t, remoteItem) |
| 928 | | 1123 | |
| 929 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1124 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 930 | h.requireReadLineExact("CHECKPRESENT-SUCCESS SomeKey") | 1125 | h.requireReadLineExact("CHECKPRESENT-SUCCESS SomeKey") |
| 931 | | 1126 | |
| 932 | h.requireWriteLine("REMOVE SomeKey") | 1127 | h.requireWriteLine("REMOVE SomeKey") |
| 933 | h.requireReadLineExact("REMOVE-SUCCESS SomeKey") | 1128 | h.requireReadLineExact("REMOVE-SUCCESS SomeKey") |
| 934 | require.NoFileExists(t, filepath.Join(h.localFsDir, "SomeKey")) | 1129 | |
| | 1130 | h.requireRemoteIsEmpty() |
| 935 | | 1131 | |
| 936 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1132 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 937 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") | 1133 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") |
| @@ -944,10 +1140,6 @@ var localBackendTestCases = []testCase{ · 6 unmodified lines |
| 944 | testProtocolFunc: func(t *testing.T, h *testState) { | 1140 | testProtocolFunc: func(t *testing.T, h *testState) { |
| 945 | h.preconfigureServer() | 1141 | h.preconfigureServer() |
| 946 | | 1142 | |
| 947 | // Create temp file for transfer. | | |
| 948 | fileToTransfer := filepath.Join(t.TempDir(), "file.txt") | | |
| 949 | require.NoError(t, os.WriteFile(fileToTransfer, []byte("HELLO"), 0600)) | | |
| 950 | | | |
| 951 | h.requireReadLineExact("VERSION 1") | 1143 | h.requireReadLineExact("VERSION 1") |
| 952 | h.requireWriteLine("INITREMOTE") | 1144 | h.requireWriteLine("INITREMOTE") |
| 953 | h.requireReadLineExact("INITREMOTE-SUCCESS") | 1145 | h.requireReadLineExact("INITREMOTE-SUCCESS") |
| @@ -955,10 +1147,12 @@ var localBackendTestCases = []testCase{ · 1 unmodified line |
| 955 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1147 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 956 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") | 1148 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") |
| 957 | | 1149 | |
| 958 | require.NoFileExists(t, filepath.Join(h.localFsDir, "SomeKey")) | 1150 | h.requireRemoteIsEmpty() |
| | 1151 | |
| 959 | h.requireWriteLine("REMOVE SomeKey") | 1152 | h.requireWriteLine("REMOVE SomeKey") |
| 960 | h.requireReadLineExact("REMOVE-SUCCESS SomeKey") | 1153 | h.requireReadLineExact("REMOVE-SUCCESS SomeKey") |
| 961 | require.NoFileExists(t, filepath.Join(h.localFsDir, "SomeKey")) | 1154 | |
| | 1155 | h.requireRemoteIsEmpty() |
| 962 | | 1156 | |
| 963 | h.requireWriteLine("CHECKPRESENT SomeKey") | 1157 | h.requireWriteLine("CHECKPRESENT SomeKey") |
| 964 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") | 1158 | h.requireReadLineExact("CHECKPRESENT-FAILURE SomeKey") |
| @@ -983,44 +1177,40 @@ var localBackendTestCases = []testCase{ · 18 unmodified lines |
| 983 | }, | 1177 | }, |
| 984 | } | 1178 | } |
| 985 | | 1179 | |
| 986 | func TestGitAnnexLocalBackendCases(t *testing.T) { | 1180 | // TestMain drives the tests |
| 987 | for _, testCase := range localBackendTestCases { | 1181 | func TestMain(m *testing.M) { |
| 988 | // Clear global state left behind by tests that chdir to a temp directory. | 1182 | fstest.TestMain(m) |
| 989 | cache.Clear() | 1183 | } |
| | 1184 | |
| | 1185 | // Run fstest-compatible test cases with backend selected by `-remote`. |
| | 1186 | func TestGitAnnexFstestBackendCases(t *testing.T) { |
| 990 | | 1187 | |
| | 1188 | for _, testCase := range fstestTestCases { |
| 991 | // TODO: Remove this when rclone requires a Go version >= 1.22. Future | 1189 | // TODO: Remove this when rclone requires a Go version >= 1.22. Future |
| 992 | // versions of Go fix the semantics of capturing a range variable. | 1190 | // versions of Go fix the semantics of capturing a range variable. |
| 993 | // https://go.dev/blog/loopvar-preview | 1191 | // https://go.dev/blog/loopvar-preview |
| 994 | testCase := testCase | 1192 | testCase := testCase |
| 995 | | 1193 | |
| 996 | t.Run(testCase.label, func(t *testing.T) { | 1194 | t.Run(testCase.label, func(t *testing.T) { |
| 997 | tempDir := t.TempDir() | 1195 | r := fstest.NewRun(t) |
| | 1196 | t.Cleanup(func() { r.Finalise() }) |
| 998 | | 1197 | |
| 999 | // Create temp dir for an rclone remote pointing at local filesystem. | 1198 | // Parse the fstest-provided remote string. It might have a path! |
| 1000 | localFsDir := filepath.Join(tempDir, "remoteTarget") | 1199 | remoteName, remotePath, err := fspath.SplitFs(r.FremoteName) |
| 1001 | require.NoError(t, os.Mkdir(localFsDir, 0700)) | 1200 | require.NoError(t, err) |
| 1002 | | 1201 | |
| 1003 | // Create temp config | 1202 | // The gitannex command requires the `rcloneremotename` is the name |
| 1004 | remoteName := getUniqueRemoteName(t) | 1203 | // of a remote or exactly ":local", so the empty string will not |
| 1005 | configLines := []string{ | 1204 | // suffice. |
| 1006 | fmt.Sprintf("[%s]", remoteName), | 1205 | if remoteName == "" { |
| 1007 | "type = local", | 1206 | require.True(t, r.Fremote.Features().IsLocal) |
| 1008 | fmt.Sprintf("remote = %s", localFsDir), | 1207 | remoteName = ":local" |
| 1009 | } | 1208 | } |
| 1010 | configContents := strings.Join(configLines, "\n") | | |
| 1011 | | | |
| 1012 | configPath := filepath.Join(tempDir, "rclone.conf") | | |
| 1013 | require.NoError(t, os.WriteFile(configPath, []byte(configContents), 0600)) | | |
| 1014 | require.NoError(t, config.SetConfigPath(configPath)) | | |
| 1015 | | | |
| 1016 | // The custom config file will be ignored unless we install the | | |
| 1017 | // global config file handler. | | |
| 1018 | configfile.Install() | | |
| 1019 | | 1209 | |
| 1020 | handle := makeTestState(t) | 1210 | handle := makeTestState(t) |
| 1021 | handle.localFsDir = localFsDir | 1211 | handle.fstestRun = r |
| 1022 | handle.configPath = configPath | | |
| 1023 | handle.remoteName = remoteName | 1212 | handle.remoteName = remoteName |
| | 1213 | handle.remotePrefix = remotePath |
| 1024 | | 1214 | |
| 1025 | var wg sync.WaitGroup | 1215 | var wg sync.WaitGroup |
| 1026 | wg.Add(1) | 1216 | wg.Add(1) |
| @@ -1042,54 +1232,3 @@ func TestGitAnnexLocalBackendCases(t *testing.T) { · 15 unmodified lines |
| 1042 | }) | 1232 | }) |
| 1043 | } | 1233 | } |
| 1044 | } | 1234 | } |
| 1045 | | | |
| 1046 | // Configure the git-annex client with a mockfs backend and send it the | | |
| 1047 | // "INITREMOTE" command over mocked stdin. This should fail because mockfs does | | |
| 1048 | // not support empty directories. | | |
| 1049 | func TestGitAnnexHandleInitRemoteBackendDoesNotSupportEmptyDirectories(t *testing.T) { | | |
| 1050 | tempDir := t.TempDir() | | |
| 1051 | | | |
| 1052 | // Temporarily override the filesystem registry. | | |
| 1053 | oldRegistry := fs.Registry | | |
| 1054 | mockfs.Register() | | |
| 1055 | defer func() { fs.Registry = oldRegistry }() | | |
| 1056 | | | |
| 1057 | // Create temp dir for an rclone remote pointing at local filesystem. | | |
| 1058 | localFsDir := filepath.Join(tempDir, "remoteTarget") | | |
| 1059 | require.NoError(t, os.Mkdir(localFsDir, 0700)) | | |
| 1060 | | | |
| 1061 | // Create temp config | | |
| 1062 | remoteName := getUniqueRemoteName(t) | | |
| 1063 | configLines := []string{ | | |
| 1064 | fmt.Sprintf("[%s]", remoteName), | | |
| 1065 | "type = mockfs", | | |
| 1066 | fmt.Sprintf("remote = %s", localFsDir), | | |
| 1067 | } | | |
| 1068 | configContents := strings.Join(configLines, "\n") | | |
| 1069 | | | |
| 1070 | configPath := filepath.Join(tempDir, "rclone.conf") | | |
| 1071 | require.NoError(t, os.WriteFile(configPath, []byte(configContents), 0600)) | | |
| 1072 | | | |
| 1073 | // The custom config file will be ignored unless we install the global | | |
| 1074 | // config file handler. | | |
| 1075 | configfile.Install() | | |
| 1076 | require.NoError(t, config.SetConfigPath(configPath)) | | |
| 1077 | | | |
| 1078 | handle := makeTestState(t) | | |
| 1079 | handle.server.configPrefix = localFsDir | | |
| 1080 | handle.server.configRcloneRemoteName = remoteName | | |
| 1081 | handle.server.configsDone = true | | |
| 1082 | | | |
| 1083 | var wg sync.WaitGroup | | |
| 1084 | wg.Add(1) | | |
| 1085 | | | |
| 1086 | go func() { | | |
| 1087 | require.NotNil(t, handle.server.run()) | | |
| 1088 | wg.Done() | | |
| 1089 | }() | | |
| 1090 | defer wg.Wait() | | |
| 1091 | | | |
| 1092 | handle.requireReadLineExact("VERSION 1") | | |
| 1093 | handle.requireWriteLine("INITREMOTE") | | |
| 1094 | handle.requireReadLineExact("INITREMOTE-FAILURE this rclone remote does not support empty directories") | | |
| 1095 | } | | |