Skip to content

Commit 6eba81b

Browse files
committed
test(integration): cover reftable repos under the git-refs default backend
Add TestReftableRepository_GitRefsBackend and its linked-worktree variant, which drive the full capture flow on a reftable repo using the shipped default (git-refs) backend and assert per-checkpoint refs under refs/entire/checkpoints are written/read through the reftable storer, with no v1 branch. Extract bootstrapReftableRepo/readWorktreeFile helpers and drop runCLIIn's unused return. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Paulo Gomes <paulo@entire.io> Entire-Checkpoint: 01KYMC8VEJVCRC9TM5J9ESR6XA
1 parent 7a344d9 commit 6eba81b

1 file changed

Lines changed: 145 additions & 2 deletions

File tree

cmd/entire/cli/integration_test/reftable_repo_test.go

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package integration
44

55
import (
66
"context"
7+
"os"
78
"os/exec"
89
"path/filepath"
910
"strings"
@@ -170,11 +171,154 @@ func TestReftableRepository_LinkedWorktree(t *testing.T) {
170171
}
171172
}
172173

174+
// TestReftableRepository_GitRefsBackend exercises the full capture flow against a
175+
// reftable repository using the shipped default checkpoint backend (git-refs),
176+
// where each checkpoint is condensed to its own ref under refs/entire/checkpoints
177+
// rather than to the entire/checkpoints/v1 branch. Every ref write and read goes
178+
// through gitrepo.reftableStorer, so this proves the reftable backend works with
179+
// the default per-checkpoint ref layout, not just the git-branch flow. It runs
180+
// WITHOUT --checkpoint-backend and without an ENTIRE_CHECKPOINTS_PRIMARY override
181+
// so it pins the actual shipped default.
182+
func TestReftableRepository_GitRefsBackend(t *testing.T) {
183+
t.Parallel()
184+
requireGitReftableSupport(t)
185+
186+
env := NewTestEnv(t)
187+
bootstrapReftableRepo(t, env)
188+
189+
// No --checkpoint-backend flag: exercise the shipped first-run default, which
190+
// must write the git-refs primary into settings.json.
191+
env.RunCLI("enable", "--no-github", "--agent", "claude-code", "--telemetry=false")
192+
if s := env.ReadFile(".entire/settings.json"); !strings.Contains(s, `"git-refs"`) {
193+
t.Fatalf("first-run enable on a reftable repo should default to the git-refs backend, settings.json:\n%s", s)
194+
}
195+
196+
initialHead := gitOutput(t, env.RepoDir, "rev-parse", "HEAD")
197+
198+
sess := env.NewSession()
199+
prompt := "Create a file in the reftable repo"
200+
if err := env.SimulateUserPromptSubmitWithPromptAndTranscriptPath(sess.ID, prompt, sess.TranscriptPath); err != nil {
201+
t.Fatalf("user-prompt-submit failed: %v", err)
202+
}
203+
204+
const mainContent = "package main\n\nfunc main() {}\n"
205+
env.WriteFile("main.go", mainContent)
206+
sess.CreateTranscript(prompt, []FileChange{{Path: "main.go", Content: mainContent}})
207+
if err := env.SimulateStop(sess.ID, sess.TranscriptPath); err != nil {
208+
t.Fatalf("stop hook failed creating first checkpoint: %v", err)
209+
}
210+
211+
state, err := env.GetSessionState(sess.ID)
212+
if err != nil {
213+
t.Fatalf("GetSessionState failed: %v", err)
214+
}
215+
if state == nil || state.StepCount != 1 {
216+
t.Fatalf("session StepCount after first checkpoint = %#v, want 1", state)
217+
}
218+
219+
// The shadow branch is created and advanced via reftable ref writes.
220+
shadowBranch := env.GetShadowBranchNameForCommit(initialHead)
221+
if got := gitOutput(t, env.RepoDir, "rev-parse", shadowBranch); got == "" {
222+
t.Fatalf("expected shadow branch %s to resolve", shadowBranch)
223+
}
224+
225+
env.GitCommitWithShadowHooks("Add reftable main", "main.go")
226+
if userHead := gitOutput(t, env.RepoDir, "rev-parse", "HEAD"); userHead == initialHead {
227+
t.Fatal("expected user commit to advance HEAD")
228+
}
229+
230+
// git-refs artifact: the condensed checkpoint lands on a per-checkpoint ref
231+
// under refs/entire/checkpoints (written through the reftable storer), and the
232+
// v1 branch is never created under this backend.
233+
if refs := gitOutput(t, env.RepoDir, "for-each-ref", checkpointRefPrefix); refs == "" {
234+
t.Fatalf("expected a per-checkpoint ref under %s for the git-refs default", checkpointRefPrefix)
235+
}
236+
if env.BranchExists(paths.MetadataBranchName) {
237+
t.Fatalf("git-refs default must not create the %s branch", paths.MetadataBranchName)
238+
}
239+
240+
// The checkpoint's exact ref resolves through the reftable read path, and its
241+
// ID is recoverable from the code commit's Entire-Checkpoint trailer.
242+
checkpointID := env.GetLatestCheckpointIDFromHistory()
243+
if !refExists(t, env.RepoDir, checkpointRefName(checkpointID)) {
244+
t.Fatalf("expected checkpoint ref %s to resolve", checkpointRefName(checkpointID))
245+
}
246+
247+
// checkpoint list must work against the reftable repo (read path).
248+
if listOut := env.RunCLI("checkpoint", "list"); !strings.Contains(listOut, checkpointID) {
249+
t.Fatalf("checkpoint list missing checkpoint %s:\n%s", checkpointID, listOut)
250+
}
251+
}
252+
253+
// TestReftableRepository_GitRefsBackend_LinkedWorktree verifies that first-run
254+
// enable with the default git-refs backend succeeds inside a linked worktree of a
255+
// reftable repository (shared reftable stack under the common git dir) and that
256+
// the reftable read paths work from the worktree. The git-branch variant is
257+
// covered by TestReftableRepository_LinkedWorktree.
258+
func TestReftableRepository_GitRefsBackend_LinkedWorktree(t *testing.T) {
259+
t.Parallel()
260+
requireGitReftableSupport(t)
261+
262+
env := NewTestEnv(t)
263+
bootstrapReftableRepo(t, env)
264+
265+
worktreePath := filepath.Join(t.TempDir(), "wt")
266+
gitOutput(t, env.RepoDir, "worktree", "add", "-b", "feature/wt", worktreePath)
267+
268+
// Default backend (git-refs): no --checkpoint-backend flag.
269+
runCLIIn(t, env, worktreePath, "enable", "--no-github", "--agent", "claude-code", "--telemetry=false")
270+
271+
if s := readWorktreeFile(t, worktreePath, ".entire/settings.json"); !strings.Contains(s, `"git-refs"`) {
272+
t.Fatalf("enable in a reftable worktree should default to git-refs, settings.json:\n%s", s)
273+
}
274+
if got := gitOutput(t, worktreePath, "rev-parse", "--show-ref-format"); got != refFormatReftable {
275+
t.Fatalf("worktree ref format = %q, want reftable", got)
276+
}
277+
278+
// A ref read against the worktree (HEAD resolution through the reftable storer,
279+
// whose HEAD stub go-git cannot read) must return the real branch.
280+
if branch := gitOutput(t, worktreePath, "rev-parse", "--abbrev-ref", "HEAD"); branch != "feature/wt" {
281+
t.Fatalf("worktree branch = %q, want feature/wt", branch)
282+
}
283+
284+
// The git-refs default must not bootstrap the v1 branch.
285+
if got := gitOutput(t, worktreePath, "for-each-ref", checkpointRefPrefix); got != "" {
286+
t.Fatalf("no checkpoint should exist yet, got refs:\n%s", got)
287+
}
288+
}
289+
290+
// bootstrapReftableRepo initializes env.RepoDir as a reftable repository with an
291+
// initial commit via the git CLI. Integration tests deliberately avoid the enable
292+
// bootstrap path and drive hooks through getTestBinary(), so the repo is created
293+
// directly here.
294+
func bootstrapReftableRepo(t *testing.T, env *TestEnv) {
295+
t.Helper()
296+
gitOutput(t, "", "init", "--ref-format=reftable", env.RepoDir)
297+
gitOutput(t, env.RepoDir, "config", "user.name", "Test User")
298+
gitOutput(t, env.RepoDir, "config", "user.email", "test@example.com")
299+
gitOutput(t, env.RepoDir, "config", "commit.gpgsign", "false")
300+
env.WriteFile("README.md", "# reftable repo\n")
301+
gitOutput(t, env.RepoDir, "add", "README.md")
302+
gitOutput(t, env.RepoDir, "commit", "-m", "Initial reftable commit")
303+
}
304+
305+
// readWorktreeFile reads a file relative to a linked worktree root. env.ReadFile
306+
// is scoped to env.RepoDir, so worktree-local files (e.g. a per-worktree
307+
// .entire/settings.json) need a direct read.
308+
func readWorktreeFile(t *testing.T, worktreePath, rel string) string {
309+
t.Helper()
310+
data, err := os.ReadFile(filepath.Join(worktreePath, rel))
311+
if err != nil {
312+
t.Fatalf("read %s in worktree: %v", rel, err)
313+
}
314+
return string(data)
315+
}
316+
173317
// runCLIIn runs the built entire binary in an arbitrary directory (e.g. a linked
174318
// worktree) with the same isolated environment RunCLI uses, detached from any
175319
// controlling TTY (matching TestEnv.RunCLIWithError) so an interactive prompt
176320
// path can't hang the test.
177-
func runCLIIn(t *testing.T, env *TestEnv, dir string, args ...string) string {
321+
func runCLIIn(t *testing.T, env *TestEnv, dir string, args ...string) {
178322
t.Helper()
179323
cmd := execx.NonInteractive(context.Background(), getTestBinary(), args...)
180324
cmd.Dir = dir
@@ -183,7 +327,6 @@ func runCLIIn(t *testing.T, env *TestEnv, dir string, args ...string) string {
183327
if err != nil {
184328
t.Fatalf("entire %s (in %s) failed: %v\n%s", strings.Join(args, " "), dir, err, out)
185329
}
186-
return string(out)
187330
}
188331

189332
func requireGitReftableSupport(t *testing.T) {

0 commit comments

Comments
 (0)