From a0aa0c98fa764df69d53748a9730372a20f5a08c Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sun, 6 Sep 2026 22:17:47 +0700 Subject: [PATCH] test: prove an upload recovers on retry after a real move failure --- internal/pipeline/upload_test.go | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/internal/pipeline/upload_test.go b/internal/pipeline/upload_test.go index 2b55180..498f6ec 100644 --- a/internal/pipeline/upload_test.go +++ b/internal/pipeline/upload_test.go @@ -141,3 +141,48 @@ func TestUploadMovesAndConfirms(t *testing.T) { t.Error("the staged copy survived a successful move") } } + +// The recovery the retry exists for: the first attempt fails, the condition +// clears, and the second attempt succeeds — without the file having to be +// downloaded again. +// +// The destination is made unwritable so the first move genuinely fails inside +// rclone, and the backoff hook restores it. Faking the error would only test +// the loop against itself; this exercises the real MoveFile path. +func TestUploadSucceedsOnRetryAfterTheRemoteRecovers(t *testing.T) { + u, it, dstDir, stageDir := settleFixture(t, -1, 4096) + u.confirm = true + + if err := os.Chmod(dstDir, 0o500); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = os.Chmod(dstDir, 0o700) }) + + restore := uploadBackoff + t.Cleanup(func() { uploadBackoff = restore }) + var backoffs int + uploadBackoff = func(int) time.Duration { + backoffs++ + if err := os.Chmod(dstDir, 0o700); err != nil { + t.Errorf("restore destination: %v", err) + } + return time.Millisecond + } + + if err := u.upload(t.Context(), it); err != nil { + t.Fatalf("upload did not recover on retry: %v", err) + } + if backoffs == 0 { + t.Error("the first attempt did not fail, so no retry was exercised") + } + info, err := os.Stat(filepath.Join(dstDir, settleName)) + if err != nil { + t.Fatalf("object not on the destination after the retry: %v", err) + } + if info.Size() != it.Size() { + t.Errorf("object is %d bytes, want %d", info.Size(), it.Size()) + } + if _, err := os.Stat(filepath.Join(stageDir, settleName)); !os.IsNotExist(err) { + t.Error("the staged copy survived a successful retry") + } +}