test(e2e): add worktree-remote and unreachable-remote scenarios (G2, G3) · Entire
test(e2e): add worktree-remote and unreachable-remote scenarios (G2, G3)
7093889·
Soph·1w ago·2 files·+163 added/-0 removed
- G2: an agent session runs inside a linked
git worktree, the user commits and pushes the worktree's branch with a plaingit push(the real pre-push hook syncs checkpoints — no explicit PushCheckpointRefs), and a fresh cloneentire resumes the session. Exercises the worktree shadow-branch namespace and the shared common-dir push queue end to end. - G3:
entire doctoron a repo whose origin points at an unreachable (hermetic, missing local path) target completes without hanging or crashing and still reports its local session-health scan — pinning the degrade-to-local behavior.
Both are vogon-only (deterministic, free, part of the CI canary matrix). G2 reuses the resume-from-clone prompt phrasing verbatim so vogon's regex prompt parser needs no changes. Adds entire.DoctorCtx, a context-bounded doctor runner that returns output+error instead of failing the test, so G3 can surface a hang as a deadline.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
Sessions
8f2fa44f0ab7View transcript
[?
Comprehensive Checkpoint Testing CoverageCodex·GPT-5.5·2 steps](/content/gh/entireio/cli/session/019f22a2-95f4-7d71-8140-4d86b0d40aa5#timeline-8f2fa44f0ab7/index.html)
Changes
2
e2e
entire
Mentire.go+12
tests
Aworktree_remote_test.go+151
52 unmodified lines
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
52 unmodified lines
return run(t, dir, "doctor", "--force")
}
// DoctorCtx runs `entire doctor --force` under the given context and returns the
// combined output and any error WITHOUT failing the test. Use it to pin doctor's
// behavior against a degraded/unreachable remote: pass a context.WithTimeout so a
// hang surfaces as context.DeadlineExceeded rather than blocking the suite.
func DoctorCtx(ctx context.Context, dir string) (string, error) {
cmd := execx.NonInteractive(ctx, BinPath(), "doctor", "--force")
cmd.Dir = dir
cmd.Env = os.Environ()
out, err := cmd.CombinedOutput()
return strings.TrimSpace(string(out)), err
}
// CleanDryRun runs `entire clean --dry-run` and returns the output.
func CleanDryRun(t *testing.T, dir string) string {
t.Helper()
Me2e/entire/entire.go+12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//go:build e2e
package tests
import (
"context"
"errors"
"os"
"path/filepath"
"testing"
"time"
"github.com/entireio/cli/e2e/entire"
"github.com/entireio/cli/e2e/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestResumeFromWorktreeSession is G2: an agent session runs inside a linked
// `git worktree`, the user commits and pushes the worktree's branch with a plain
// `git push` (the real pre-push hook syncs checkpoints — no explicit
// PushCheckpointRefs), and a fresh clone elsewhere can `entire resume` the
// session. This exercises the worktree shadow-branch namespace and the shared
// (common-dir) push queue end to end.
//
// vogon-only: deterministic and free, matching the doctor canary. The prompt
// phrasing is copied verbatim from the resume-from-clone test so vogon's
// regex-based prompt parser needs no changes.
func TestResumeFromWorktreeSession(t *testing.T) {
testutil.ForEachNamedAgent(t, 3*time.Minute, []string{"vogon"}, func(t *testing.T, s *testutil.RepoState, ctx context.Context) {
bareDir := testutil.SetupBareRemote(t, s)
// Commit the `entire enable` files on the default branch and push, so the
// bare remote has a base the clone can start from.
s.Git(t, "add", ".")
s.Git(t, "commit", "-m", "Enable entire")
s.Git(t, "push")
// Create a linked worktree on a feature branch. It shares the main repo's
// git common dir (objects, refs, hooks, and the checkpoint push queue).
worktreeDir := filepath.Join(t.TempDir(), "worktree")
if resolved, symErr := filepath.EvalSymlinks(filepath.Dir(worktreeDir)); symErr == nil {
worktreeDir = filepath.Join(resolved, "worktree")
}
s.Git(t, "worktree", "add", worktreeDir, "-b", "feature")
// .entire/ is gitignored, so the worktree's working tree has none — enable
// Entire in the worktree to give it its own settings (hooks live in the
// shared common dir and are already installed).
entire.Enable(t, worktreeDir, s.Agent.EntireAgent())
testutil.PatchSettings(t, worktreeDir, map[string]any{"log_level": "debug", "commit_linking": "always"})
// Run the agent IN the worktree (its cwd is the worktree, so the session
// transcript and shadow branch are scoped to it).
out, err := s.Agent.RunPrompt(ctx, worktreeDir,
"create a file at docs/hello.md with a paragraph about greetings. Do not ask for confirmation, just make the change.")
s.ConsoleLog.WriteString("> [worktree] " + out.Command + "\nstdout:\n" + out.Stdout + "\nstderr:\n" + out.Stderr + "\n")
require.NoError(t, err, "agent failed in worktree")
testutil.Git(t, worktreeDir, "add", ".")
testutil.Git(t, worktreeDir, "commit", "-m", "Add hello doc")
// Checkpoint refs live in the shared common dir, visible from s.Dir.
testutil.WaitForCheckpoint(t, s, 30*time.Second)
checkpointID := testutil.AssertHasCheckpointTrailer(t, worktreeDir, "HEAD")
require.NotEmpty(t, checkpointID, "worktree commit should carry a checkpoint trailer")
sessionMeta := testutil.WaitForSessionMetadata(t, s.Dir, checkpointID, 0, 30*time.Second)
// Plain push of the worktree's branch through the real hook drains the
// shared push queue / syncs the v1 branch — no explicit PushCheckpointRefs.
testutil.Git(t, worktreeDir, "push", "-u", "origin", "feature")
testutil.AssertCheckpointsOnRemote(t, s, bareDir)
// Clone elsewhere (a teammate) and resume the worktree's session.
cloneDir := t.TempDir()
if resolved, symErr := filepath.EvalSymlinks(cloneDir); symErr == nil {
cloneDir = resolved
}
require.NoError(t, os.RemoveAll(cloneDir))
testutil.Git(t, "", "clone", bareDir, cloneDir)
testutil.Git(t, cloneDir, "config", "user.name", "E2E Clone")
testutil.Git(t, cloneDir, "config", "user.email", "e2e-clone@test.local")
require.False(t, testutil.CheckpointsPresent(cloneDir),
"checkpoint metadata should not exist locally in the clone before resume")
// Materialize the feature branch locally, then return to the default branch
// so resume can switch to it.
mainClone := testutil.GitOutput(t, cloneDir, "branch", "--show-current")
testutil.Git(t, cloneDir, "checkout", "feature")
testutil.Git(t, cloneDir, "checkout", mainClone)
entire.Enable(t, cloneDir, s.Agent.EntireAgent())
testutil.CommitIfDirty(t, cloneDir, "Enable entire in clone")
resumeOut, err := entire.Resume(cloneDir, "feature")
require.NoError(t, err, "entire resume failed in clone: %s", resumeOut)
current := testutil.GitOutput(t, cloneDir, "branch", "--show-current")
assert.Equal(t, "feature", current, "should be on the feature branch after resume")
assert.Contains(t, resumeOut, "To continue", "resume output should show resume instructions")
assert.True(t, testutil.CheckpointsPresent(cloneDir),
"checkpoint metadata should exist locally after resuming the worktree session")
if restoredTranscript, ok := testutil.RestoredSessionTranscriptPath(t, cloneDir, sessionMeta); ok {
_, statErr := os.Stat(restoredTranscript)
assert.NoError(t, statErr, "restored session transcript should exist at %s after resume", restoredTranscript)
}
})
}
// TestDoctorUnreachableRemote is G3: `entire doctor` on a repo whose origin
// points at an unreachable target reports the situation and exits without
// hanging or crashing. It pins the current behavior: doctor degrades to
// local-only checks rather than blocking on the dead remote.
func TestDoctorUnreachableRemote(t *testing.T) {
testutil.ForEachNamedAgent(t, 3*time.Minute, []string{"vogon"}, func(t *testing.T, s *testutil.RepoState, ctx context.Context) {
// A committed checkpoint so doctor has real metadata/session state to scan.
s.Git(t, "add", ".")
s.Git(t, "commit", "-m", "Enable entire")
_, err := s.RunPrompt(t, ctx,
"create a file at docs/doctor.md with a short paragraph about checkpoint health. Do not ask for confirmation or approval, just make the change.")
require.NoError(t, err, "agent failed")
s.Git(t, "add", ".")
s.Git(t, "commit", "-m", "Add doctor coverage doc")
testutil.WaitForCheckpoint(t, s, 30*time.Second)
// Point origin at a local path that does not exist — unreachable but fully
// hermetic (no network) and fails fast.
deadRemote := filepath.Join(t.TempDir(), "nonexistent-bare.git")
s.Git(t, "remote", "add", "origin", deadRemote)
// Bound the run so a hang surfaces as a deadline rather than blocking.
dctx, cancel := context.WithTimeout(ctx, 90*time.Second)
defer cancel()
out, doctorErr := entire.DoctorCtx(dctx, s.Dir)
t.Logf("doctor (unreachable remote) exit=%v\n%s", doctorErr, out)
require.False(t, errors.Is(dctx.Err(), context.DeadlineExceeded),
"doctor must not hang on an unreachable remote")
require.NotContains(t, out, "panic:", "doctor must not crash on an unreachable remote")
// Pin: doctor still completes its local scan and reports session health
// despite the dead remote (it degrades rather than aborting the scan).
assert.Contains(t, out, "stuck sessions",
"doctor should still report the session-health scan even with an unreachable remote")
})
}