Skip to content

Commit 8c61f8e

Browse files
wesmclaude
andcommitted
refactor: split sync_test.go into focused test files
Split the 2,487-line sync_test.go (36 tests) into 7 focused files: - sync_test_helpers_test.go: shared helpers, legacy DDL, syncTestHelper - sync_state_test.go: sync state and worker lifecycle (6 tests) - sync_backfill_test.go: machine ID and repo identity backfill (6 tests) - sync_identity_test.go: repo identity CRUD and schema migrations (8 tests) - sync_queries_test.go: sync query functions and timestamps (5 tests) - sync_ordering_test.go: sync ordering and dependency enforcement (8 tests) - sync_remap_test.go: patch ID round-trip and job remapping (4 tests) No test logic changes. Follows the pattern set by review_test.go split (#379). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f71aafe commit 8c61f8e

File tree

8 files changed

+2532
-2487
lines changed

8 files changed

+2532
-2487
lines changed
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
package storage
2+
3+
import (
4+
"database/sql"
5+
"os/exec"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
"time"
10+
)
11+
12+
func TestBackfillSourceMachineID(t *testing.T) {
13+
h := newSyncTestHelper(t)
14+
15+
job := h.createPendingJob("abc123")
16+
17+
// Verify source_machine_id is initially NULL (simulating legacy data)
18+
var sourceMachineID *string
19+
err := h.db.QueryRow(`SELECT source_machine_id FROM review_jobs WHERE id = ?`, job.ID).Scan(&sourceMachineID)
20+
if err != nil {
21+
t.Fatalf("Query failed: %v", err)
22+
}
23+
// After migration, backfill runs automatically, so it may already have a value
24+
// Let's clear it to test the backfill
25+
h.clearSourceMachineID(job.ID)
26+
27+
// Run backfill
28+
err = h.db.BackfillSourceMachineID()
29+
if err != nil {
30+
t.Fatalf("BackfillSourceMachineID failed: %v", err)
31+
}
32+
33+
// Verify source_machine_id is now set
34+
var newSourceMachineID string
35+
err = h.db.QueryRow(`SELECT source_machine_id FROM review_jobs WHERE id = ?`, job.ID).Scan(&newSourceMachineID)
36+
if err != nil {
37+
t.Fatalf("Query after backfill failed: %v", err)
38+
}
39+
40+
machineID, _ := h.db.GetMachineID()
41+
if newSourceMachineID != machineID {
42+
t.Errorf("Expected source_machine_id %q, got %q", machineID, newSourceMachineID)
43+
}
44+
}
45+
46+
func TestBackfillRepoIdentities_LocalRepoFallback(t *testing.T) {
47+
db := openTestDB(t)
48+
defer db.Close()
49+
50+
// Create a git repo without a remote configured
51+
tempDir := t.TempDir()
52+
cmd := exec.Command("git", "init", tempDir)
53+
if err := cmd.Run(); err != nil {
54+
t.Skipf("git init failed (git not available?): %v", err)
55+
}
56+
57+
repo, err := db.GetOrCreateRepo(tempDir)
58+
if err != nil {
59+
t.Fatalf("GetOrCreateRepo failed: %v", err)
60+
}
61+
62+
// Clear identity to simulate legacy repo
63+
h := &syncTestHelper{t: t, db: db}
64+
h.clearRepoIdentity(repo.ID)
65+
66+
// Backfill should use local: prefix with repo name (git repo, no remote)
67+
count, err := db.BackfillRepoIdentities()
68+
if err != nil {
69+
t.Fatalf("BackfillRepoIdentities failed: %v", err)
70+
}
71+
if count != 1 {
72+
t.Errorf("Expected 1 repo backfilled, got %d", count)
73+
}
74+
75+
// Verify identity was set with local: prefix
76+
var identity string
77+
err = db.QueryRow(`SELECT identity FROM repos WHERE id = ?`, repo.ID).Scan(&identity)
78+
if err != nil {
79+
t.Fatalf("Query identity failed: %v", err)
80+
}
81+
82+
expectedPrefix := "local:"
83+
if !strings.HasPrefix(identity, expectedPrefix) {
84+
t.Errorf("Expected identity to start with %q, got %q", expectedPrefix, identity)
85+
}
86+
87+
// The identity should contain the repo name (last component of path)
88+
if !strings.Contains(identity, repo.Name) {
89+
t.Errorf("Expected identity to contain repo name %q, got %q", repo.Name, identity)
90+
}
91+
}
92+
93+
func TestBackfillRepoIdentities_SkipsNonGitRepos(t *testing.T) {
94+
db := openTestDB(t)
95+
defer db.Close()
96+
97+
// Create a repo pointing to a directory that is NOT a git repository
98+
tempDir := t.TempDir() // Just a plain directory, no git init
99+
repo, err := db.GetOrCreateRepo(tempDir)
100+
if err != nil {
101+
t.Fatalf("GetOrCreateRepo failed: %v", err)
102+
}
103+
104+
// Clear identity to simulate legacy repo
105+
h := &syncTestHelper{t: t, db: db}
106+
h.clearRepoIdentity(repo.ID)
107+
108+
// Backfill should set a local:// identity for non-git repos
109+
count, err := db.BackfillRepoIdentities()
110+
if err != nil {
111+
t.Fatalf("BackfillRepoIdentities failed: %v", err)
112+
}
113+
if count != 1 {
114+
t.Errorf("Expected 1 repo backfilled with local:// identity, got %d", count)
115+
}
116+
117+
// Verify identity is set to local:// prefix
118+
var identity sql.NullString
119+
err = db.QueryRow(`SELECT identity FROM repos WHERE id = ?`, repo.ID).Scan(&identity)
120+
if err != nil {
121+
t.Fatalf("Query identity failed: %v", err)
122+
}
123+
if !identity.Valid || !strings.HasPrefix(identity.String, "local://") {
124+
t.Errorf("Expected identity with local:// prefix, got %q", identity.String)
125+
}
126+
}
127+
128+
func TestBackfillRepoIdentities_SkipsReposWithIdentity(t *testing.T) {
129+
db := openTestDB(t)
130+
defer db.Close()
131+
132+
// Create a repo and set its identity
133+
tempDir := t.TempDir()
134+
repo, err := db.GetOrCreateRepo(tempDir)
135+
if err != nil {
136+
t.Fatalf("GetOrCreateRepo failed: %v", err)
137+
}
138+
err = db.SetRepoIdentity(repo.ID, "https://github.com/user/existing.git")
139+
if err != nil {
140+
t.Fatalf("SetRepoIdentity failed: %v", err)
141+
}
142+
143+
// Backfill should not change existing identity
144+
count, err := db.BackfillRepoIdentities()
145+
if err != nil {
146+
t.Fatalf("BackfillRepoIdentities failed: %v", err)
147+
}
148+
if count != 0 {
149+
t.Errorf("Expected 0 repos backfilled (already has identity), got %d", count)
150+
}
151+
152+
// Verify identity unchanged
153+
var identity string
154+
err = db.QueryRow(`SELECT identity FROM repos WHERE id = ?`, repo.ID).Scan(&identity)
155+
if err != nil {
156+
t.Fatalf("Query identity failed: %v", err)
157+
}
158+
if identity != "https://github.com/user/existing.git" {
159+
t.Errorf("Expected identity unchanged, got %q", identity)
160+
}
161+
}
162+
163+
func TestBackfillRepoIdentities_SkipsMissingPaths(t *testing.T) {
164+
db := openTestDB(t)
165+
defer db.Close()
166+
167+
// Create a repo pointing to a non-existent path (subpath of temp dir that doesn't exist)
168+
nonExistentPath := filepath.Join(t.TempDir(), "this-subdir-does-not-exist", "nested")
169+
_, err := db.Exec(`INSERT INTO repos (root_path, name, identity) VALUES (?, ?, NULL)`,
170+
nonExistentPath, "missing-repo")
171+
if err != nil {
172+
t.Fatalf("Insert repo failed: %v", err)
173+
}
174+
175+
// Get the repo ID
176+
var repoID int64
177+
err = db.QueryRow(`SELECT id FROM repos WHERE root_path = ?`, nonExistentPath).Scan(&repoID)
178+
if err != nil {
179+
t.Fatalf("Get repo ID failed: %v", err)
180+
}
181+
182+
// Backfill should still set a local:// identity for missing paths
183+
// (better to have an identity than none, even for stale entries)
184+
count, err := db.BackfillRepoIdentities()
185+
if err != nil {
186+
t.Fatalf("BackfillRepoIdentities failed: %v", err)
187+
}
188+
if count != 1 {
189+
t.Errorf("Expected 1 repo backfilled with local:// identity, got %d", count)
190+
}
191+
192+
// Verify identity is set to local:// prefix
193+
var identity sql.NullString
194+
err = db.QueryRow(`SELECT identity FROM repos WHERE id = ?`, repoID).Scan(&identity)
195+
if err != nil {
196+
t.Fatalf("Query identity failed: %v", err)
197+
}
198+
if !identity.Valid || !strings.HasPrefix(identity.String, "local://") {
199+
t.Errorf("Expected identity with local:// prefix, got %q", identity.String)
200+
}
201+
}
202+
203+
func TestUpsertPulledJob_BackfillsModel(t *testing.T) {
204+
// This test verifies that upserting a pulled job with a model value backfills
205+
// an existing job that has NULL model (COALESCE behavior in SQLite)
206+
db := openTestDB(t)
207+
defer db.Close()
208+
209+
// Create a repo
210+
repo, err := db.GetOrCreateRepo("/test/repo")
211+
if err != nil {
212+
t.Fatalf("GetOrCreateRepo failed: %v", err)
213+
}
214+
215+
// Insert a job with NULL model using EnqueueJob (which sets model to empty string by default)
216+
// We need to directly insert with NULL model to test the COALESCE behavior
217+
jobUUID := "test-uuid-backfill-" + time.Now().Format("20060102150405")
218+
_, err = db.Exec(`
219+
INSERT INTO review_jobs (uuid, repo_id, git_ref, agent, status, enqueued_at)
220+
VALUES (?, ?, 'HEAD', 'test-agent', 'done', datetime('now'))
221+
`, jobUUID, repo.ID)
222+
if err != nil {
223+
t.Fatalf("Failed to insert job with NULL model: %v", err)
224+
}
225+
226+
// Verify model is NULL
227+
var modelBefore sql.NullString
228+
err = db.QueryRow(`SELECT model FROM review_jobs WHERE uuid = ?`, jobUUID).Scan(&modelBefore)
229+
if err != nil {
230+
t.Fatalf("Failed to query model before: %v", err)
231+
}
232+
if modelBefore.Valid {
233+
t.Fatalf("Expected model to be NULL before upsert, got %q", modelBefore.String)
234+
}
235+
236+
// Upsert with a model value - should backfill
237+
pulledJob := PulledJob{
238+
UUID: jobUUID,
239+
RepoIdentity: "/test/repo",
240+
GitRef: "HEAD",
241+
Agent: "test-agent",
242+
Model: "gpt-4", // Now providing a model
243+
Status: "done",
244+
SourceMachineID: "test-machine",
245+
EnqueuedAt: time.Now(),
246+
UpdatedAt: time.Now(),
247+
}
248+
err = db.UpsertPulledJob(pulledJob, repo.ID, nil)
249+
if err != nil {
250+
t.Fatalf("UpsertPulledJob failed: %v", err)
251+
}
252+
253+
// Verify model was backfilled
254+
var modelAfter sql.NullString
255+
err = db.QueryRow(`SELECT model FROM review_jobs WHERE uuid = ?`, jobUUID).Scan(&modelAfter)
256+
if err != nil {
257+
t.Fatalf("Failed to query model after: %v", err)
258+
}
259+
if !modelAfter.Valid {
260+
t.Error("Expected model to be backfilled, but it's still NULL")
261+
} else if modelAfter.String != "gpt-4" {
262+
t.Errorf("Expected model 'gpt-4', got %q", modelAfter.String)
263+
}
264+
265+
// Also verify that upserting with empty model doesn't clear existing model
266+
pulledJob.Model = "" // Empty model
267+
err = db.UpsertPulledJob(pulledJob, repo.ID, nil)
268+
if err != nil {
269+
t.Fatalf("UpsertPulledJob (empty model) failed: %v", err)
270+
}
271+
272+
var modelPreserved sql.NullString
273+
err = db.QueryRow(`SELECT model FROM review_jobs WHERE uuid = ?`, jobUUID).Scan(&modelPreserved)
274+
if err != nil {
275+
t.Fatalf("Failed to query model preserved: %v", err)
276+
}
277+
if !modelPreserved.Valid || modelPreserved.String != "gpt-4" {
278+
t.Errorf("Expected model to be preserved as 'gpt-4' when upserting with empty model, got %v", modelPreserved)
279+
}
280+
}

0 commit comments

Comments
 (0)