From ff988d6c7630a94fbcf92e15c6ec7b25348f0b80 Mon Sep 17 00:00:00 2001 From: Khaliq Date: Tue, 4 Aug 2026 19:54:33 +0200 Subject: [PATCH] test(mountsync): cover write-only to mirror mode-flip backfill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the missing regression for a write-only mount later flipped to mirror mode: performs a real write-only cycle, recreates the syncer in mirror mode against the same state dir, and proves pre-existing remote history is tree-listed/read/materialized instead of being skipped by the restart fast-path. The underlying runtime fix (persist SyncMode and reset BootstrapComplete/bootstrap checkpoints in loadState on write-only to mirror transition) already exists on main — verified this test passes against a clean origin/main checkout with no production code changes. Closes #262. Verified independently: - go test ./internal/mountsync/... -run TestSyncOnceWriteOnlyToMirrorBackfillsExistingRemoteFiles -v -count=1 - go test ./internal/mountsync/... -count=1 --- internal/mountsync/syncer_test.go | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/internal/mountsync/syncer_test.go b/internal/mountsync/syncer_test.go index 35307ff6..edae6b5b 100644 --- a/internal/mountsync/syncer_test.go +++ b/internal/mountsync/syncer_test.go @@ -608,6 +608,79 @@ func TestSyncOnceWriteOnlySkipsRemotePullButPushesLocalFiles(t *testing.T) { } } +func TestSyncOnceWriteOnlyToMirrorBackfillsExistingRemoteFiles(t *testing.T) { + client := &fakeClient{ + files: map[string]RemoteFile{ + "/slack/channels/C123/messages/history.json": { + Path: "/slack/channels/C123/messages/history.json", + Revision: "rev_1", + ContentType: "application/json", + Content: `{"text":"history predating the mount"}`, + }, + }, + revisionCounter: 1, + } + localDir := t.TempDir() + + writeOnly, err := NewSyncer(client, SyncerOptions{ + WorkspaceID: "ws_write_only_to_mirror", + RemoteRoot: "/slack/channels/C123/messages", + LocalRoot: localDir, + SyncMode: "write-only", + }) + if err != nil { + t.Fatalf("new write-only syncer failed: %v", err) + } + if err := os.WriteFile(filepath.Join(localDir, "wb-pear-ack.json"), []byte(`{"text":"ack"}`), 0o644); err != nil { + t.Fatalf("write local draft failed: %v", err) + } + if err := writeOnly.SyncOnce(context.Background()); err != nil { + t.Fatalf("write-only sync failed: %v", err) + } + if !writeOnly.state.BootstrapComplete { + t.Fatal("write-only sync did not persist the legacy BootstrapComplete state needed to reproduce the mode-flip bug") + } + if writeOnly.state.SyncMode != "write-only" { + t.Fatalf("persisted sync mode = %q, want write-only", writeOnly.state.SyncMode) + } + if len(writeOnly.state.Files) == 0 { + t.Fatal("write-only sync did not track its uploaded file, so the restart fast-path would not be eligible") + } + if _, err := os.Stat(filepath.Join(localDir, "history.json")); !errors.Is(err, os.ErrNotExist) { + t.Fatalf("write-only sync unexpectedly mirrored provider history, stat err=%v", err) + } + + // Recreate the daemon against the same local/state directory, but in + // mirror mode. Before the fix, loadState trusted BootstrapComplete=true, + // seeded the events cursor to the writeback event at the feed tip, and + // returned without ever listing or reading the pre-existing history file. + mirror, err := NewSyncer(client, SyncerOptions{ + WorkspaceID: "ws_write_only_to_mirror", + RemoteRoot: "/slack/channels/C123/messages", + LocalRoot: localDir, + }) + if err != nil { + t.Fatalf("new mirror syncer failed: %v", err) + } + if err := mirror.SyncOnce(context.Background()); err != nil { + t.Fatalf("first mirror sync after mode flip failed: %v", err) + } + + if client.listTreeCalls == 0 { + t.Fatal("write-only to mirror flip skipped the full bootstrap tree listing") + } + if client.readFileCalls == 0 { + t.Fatal("write-only to mirror flip skipped reading pre-existing remote content") + } + assertLocalFileContent(t, filepath.Join(localDir, "history.json"), `{"text":"history predating the mount"}`) + if !mirror.state.BootstrapComplete { + t.Fatal("successful mirror backfill did not mark bootstrap complete") + } + if mirror.state.SyncMode != "mirror" { + t.Fatalf("persisted sync mode after backfill = %q, want mirror", mirror.state.SyncMode) + } +} + func TestHandleLocalChangeIgnoresAlreadyTrackedContent(t *testing.T) { client := &fakeClient{ files: map[string]RemoteFile{