test(integration): add checkpoint-backend matrix (I-1) · Entire
test(integration): add checkpoint-backend matrix (I-1)
d57ee8a→main·
The integration suite had no git-refs coverage: every remote-touching test asserted the git-branch v1-branch topology only, while the e2e suite already ran both backends. This adds the missing axis.
TestEnv gains a CheckpointStore field injected as ENTIRE_CHECKPOINTS_PRIMARY into every spawned CLI and git hook (cliEnv + gitHookEnv), and propagated to clones. A ForEachBackend(t, fn) helper runs "git-branch"/"git-refs" subtests, plus backend-aware assertion helpers (CheckpointsPresentLocally/OnRemote, CheckpointExistsOnRemote, RemoteCheckpointState, LatestCheckpointID) mirroring e2e/testutil/backend.go so one test asserts against either topology.
Wires the pre-push and graceful-degradation tests in remote_operations_test.go, the HTTPS push/token tests in http_remote_test.go, and the explain fetch-on-miss test under both backends. Tests whose assertions are inherently v1-branch-shaped (commit counts/subjects, rebase parent counts, checkpoint_remote routing, treeless v1 clone, v1-ref-hash divergence) stay git-branch-only with an explicit rationale pointing at their git-refs follow-up in the test plan.
One genuine git-refs divergence surfaced and is flagged, not papered over: when a session stages its file changes after the stop hook, git-refs condensation creates no per-checkpoint ref (git-branch still creates the local v1 checkpoint). Skipped for git-refs with a KNOWN BUG note; a fresh repo and a stage-before-stop clone both create the ref correctly.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com Claude-Session: https://claude.ai/code/session_012yi3hHGAGepwfrfjPETjGq
Sessions
f96568923ebdView transcript
Changes
5
cmd/entire/cli/integration_test
Abackend.go+144
Mexplain_test.go+48/-56
Mhttp_remote_test.go+76/-58
Mremote_operations_test.go+218/-212
Mtestenv.go+23
//go:build integration
package integration
import (
"os/exec"
"sort"
"strings"
"testing"
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/testutil"
)
const (
StoreGitBranch = "git-branch"
StoreGitRefs = "git-refs"
checkpointRefPrefix = "refs/entire/checkpoints/"
)
func ForEachBackend(t *testing.T, fn func(t *testing.T, backend string)) {
t.Helper()
for _, backend := range []string{StoreGitBranch, StoreGitRefs} {
t.Run(backend, func(t *testing.T) {
t.Parallel()
fn(t, backend)
})
}
}
func (env *TestEnv) usingGitRefs() bool {
return env.CheckpointStore == StoreGitRefs
}
func (env *TestEnv) LatestCheckpointID() string {
env.T.Helper()
if env.usingGitRefs() {
return env.GetLatestCheckpointIDFromHistory()
}
return env.GetLatestCheckpointID()
}
func checkpointRefName(checkpointID string) string {
return checkpointRefPrefix + id.CheckpointID(checkpointID).ShardFor() + "/" + checkpointID
}
func (env *TestEnv) CheckpointsPresentLocally() bool {
env.T.Helper()
if env.usingGitRefs() {
return anyRefUnderPrefix(env.T, env.RepoDir, checkpointRefPrefix)
}
return env.BranchExists(paths.MetadataBranchName)
}
func (env *TestEnv) CheckpointsPresentOnRemote(bareDir string) bool {
env.T.Helper()
if env.usingGitRefs() {
return anyRefUnderPrefix(env.T, bareDir, checkpointRefPrefix)
}
return env.BranchExistsOnRemote(bareDir, paths.MetadataBranchName)
}
func (env *TestEnv) CheckpointExistsOnRemote(bareDir, checkpointID string) bool {
env.T.Helper()
if env.usingGitRefs() {
return refExists(env.T, bareDir, checkpointRefName(checkpointID))
}
return fileExistsOnRemoteBranch(env.T, bareDir, CheckpointSummaryPath(checkpointID))
}
func (env *TestEnv) RemoteCheckpointState(bareDir string) string {
env.T.Helper()
prefix := "refs/heads/" + paths.MetadataBranchName
if env.usingGitRefs() {
prefix = checkpointRefPrefix
}
cmd := exec.CommandContext(env.T.Context(), "git", "for-each-ref", "--format=%(refname) %(objectname)", prefix)
cmd.Dir = bareDir
cmd.Env = testutil.GitIsolatedEnv()
out, err := cmd.Output()
if err != nil {
return ""
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
sort.Strings(lines)
return strings.Join(lines, "\n")
}
func anyRefUnderPrefix(t *testing.T, dir, prefix string) bool {
t.Helper()
cmd := exec.CommandContext(t.Context(), "git", "for-each-ref", "--format=%(refname)", prefix)
cmd.Dir = dir
cmd.Env = testutil.GitIsolatedEnv()
out, err := cmd.Output()
if err != nil {
return false
}
return strings.TrimSpace(string(out)) != ""
}
func refExists(t *testing.T, dir, ref string) bool {
t.Helper()
cmd := exec.CommandContext(t.Context(), "git", "show-ref", "--verify", "--quiet", ref)
cmd.Dir = dir
cmd.Env = testutil.GitIsolatedEnv()
return cmd.Run() == nil
}
Changes
- cmd/entire/cli/integration_test/backend.go+144
- cmd/entire/cli/integration_test/explain_test.go+48/-56
- cmd/entire/cli/integration_test/http_remote_test.go+76/-58
- cmd/entire/cli/integration_test/remote_operations_test.go+218/-212
- cmd/entire/cli/integration_test/testenv.go+23