// Package e2e runs the compiled agent-lib binary as a black box against // local fixture git repositories — fully offline. package e2e import ( "os" "os/exec" "path/filepath" "strings" "testing" ) var binPath string func TestMain(m *testing.M) { dir, err := os.MkdirTemp("", "agent-lib-e2e-bin") if err != nil { os.Exit(1) } binPath = filepath.Join(dir, "agent-lib") build := exec.Command("go", "build", "-o", binPath, ".") build.Dir = "../.." if out, err := build.CombinedOutput(); err != nil { os.Stderr.Write(out) os.Exit(1) } code := m.Run() os.RemoveAll(dir) os.Exit(code) } type harness struct { t *testing.T workDir string upstreamDir string } func newHarness(t *testing.T) *harness { t.Helper() base := t.TempDir() h := &harness{ t: t, workDir: filepath.Join(base, "work"), upstreamDir: filepath.Join(base, "upstream"), } for _, d := range []string{h.workDir, h.upstreamDir} { if err := os.MkdirAll(d, 0o755); err != nil { t.Fatal(err) } } h.git(t, h.upstreamDir, "init", "-b", "main") return h } func (h *harness) git(t *testing.T, dir string, args ...string) string { t.Helper() cmd := exec.Command("git", args...) cmd.Dir = dir cmd.Env = append(os.Environ(), "GIT_AUTHOR_NAME=test", "GIT_AUTHOR_EMAIL=test@test", "GIT_COMMITTER_NAME=test", "GIT_COMMITTER_EMAIL=test@test", "GIT_AUTHOR_DATE=1700000000 +0000", "GIT_COMMITTER_DATE=1700000000 +0000", ) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("git %v in %s: %v\n%s", args, dir, err, out) } return string(out) } func (h *harness) write(t *testing.T, rel, content string) { t.Helper() path := filepath.Join(h.upstreamDir, rel) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, []byte(content), 0o644); err != nil { t.Fatal(err) } } func (h *harness) commitUpstream(t *testing.T, msg string) { t.Helper() h.git(t, h.upstreamDir, "add", "-A") h.git(t, h.upstreamDir, "commit", "-m", msg) } func (h *harness) run(t *testing.T, args ...string) (string, error) { t.Helper() cmd := exec.Command(binPath, args...) cmd.Dir = h.workDir out, err := cmd.CombinedOutput() return string(out), err } func (h *harness) mustRun(t *testing.T, args ...string) string { t.Helper() out, err := h.run(t, args...) if err != nil { t.Fatalf("agent-lib %v: %v\n%s", args, err, out) } return out } func standardFixture(h *harness, t *testing.T) { h.write(t, "skills/good-skill/SKILL.md", "---\nname: Good Skill\ndescription: works\ntags: a, b\n---\n# Good\n") h.write(t, "skills/good-skill/helper.py", "print('hi')\n") h.write(t, "skills/broken-skill/SKILL.md", "---\nname: Broken\nthis line has no colon\n") h.write(t, "commands/review.md", "---\nname: Review\ndescription: review things\n---\nbody\n") h.write(t, "agents/scout.md", "---\nname: Scout\n---\nbody\n") h.write(t, "mcp/search.yaml", "servers:\n search:\n command: search\n") h.write(t, "README.md", "upstream readme\n") h.commitUpstream(t, "fixture: initial content") } func TestVendorAddAllMode(t *testing.T) { h := newHarness(t) standardFixture(h, t) out := h.mustRun(t, "vendor", "add", "superpowers", h.upstreamDir) if !contains(out, "ref: main") { t.Errorf("report missing resolved ref:\n%s", out) } if !contains(out, "4 skills") && !contains(out, "2 skills") { t.Errorf("report should list skill count:\n%s", out) } if !contains(out, "warnings") { t.Errorf("malformed frontmatter must produce a warning in the report:\n%s", out) } for _, p := range []string{ "external/superpowers/skills/good-skill/SKILL.md", "external/superpowers/skills/good-skill/helper.py", "external/superpowers/skills/broken-skill/SKILL.md", "external/superpowers/commands/review.md", "external/superpowers/agents/scout.md", "external/superpowers/mcp/search.yaml", } { if _, err := os.Stat(filepath.Join(h.workDir, p)); err != nil { t.Errorf("missing materialized file %s", p) } } if _, err := os.Stat(filepath.Join(h.workDir, "external/superpowers/README.md")); err == nil { t.Error("README must not be vendored") } lockBytes, err := os.ReadFile(filepath.Join(h.workDir, "agent-lib.lock.json")) if err != nil { t.Fatal(err) } lock := string(lockBytes) if !contains(lock, `"version": 2`) { t.Errorf("lockfile must be schema v2:\n%s", lock) } if !contains(lock, `"mode": "all"`) { t.Errorf("default selection must be all:\n%s", lock) } if !contains(lock, h.upstreamDir) { t.Errorf("lockfile must pin the url:\n%s", lock) } if !contains(lock, "frontmatter") { t.Errorf("recorded warnings missing from lockfile:\n%s", lock) } } func TestVendorAddDeterministicRerun(t *testing.T) { h := newHarness(t) standardFixture(h, t) h.mustRun(t, "vendor", "add", "superpowers", h.upstreamDir) secondWork := filepath.Join(t.TempDir(), "work2") if err := os.MkdirAll(secondWork, 0o755); err != nil { t.Fatal(err) } cmd := exec.Command(binPath, "vendor", "add", "superpowers", h.upstreamDir) cmd.Dir = secondWork if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("second add: %v\n%s", err, out) } b1 := readFile(t, filepath.Join(h.workDir, "agent-lib.lock.json")) b2 := readFile(t, filepath.Join(secondWork, "agent-lib.lock.json")) if b1 != b2 { t.Fatalf("same upstream commit must produce identical lockfiles:\n%s\n---\n%s", b1, b2) } } func TestVendorAddIncludeMode(t *testing.T) { h := newHarness(t) standardFixture(h, t) h.mustRun(t, "vendor", "add", "curated", h.upstreamDir, "--include", "good-skill,review") if _, err := os.Stat(filepath.Join(h.workDir, "external/curated/skills/good-skill/SKILL.md")); err != nil { t.Error("included skill must be materialized") } if _, err := os.Stat(filepath.Join(h.workDir, "external/curated/commands/review.md")); err != nil { t.Error("included command must be materialized") } if _, err := os.Stat(filepath.Join(h.workDir, "external/curated/agents/scout.md")); err == nil { t.Error("non-included agent must NOT be materialized") } lock := readFile(t, filepath.Join(h.workDir, "agent-lib.lock.json")) if !contains(lock, `"mode": "include"`) { t.Errorf("selection mode must be include:\n%s", lock) } if !contains(lock, `"include": [`) { t.Errorf("include list missing:\n%s", lock) } } func TestVendorAddIncludeTypoFailsClean(t *testing.T) { h := newHarness(t) standardFixture(h, t) out, err := h.run(t, "vendor", "add", "curated", h.upstreamDir, "--include", "good-skill,nope") if err == nil { t.Fatalf("typo in include list must fail:\n%s", out) } if !contains(out, "nope") { t.Errorf("error must name the missing entry:\n%s", out) } if _, err := os.Stat(filepath.Join(h.workDir, "agent-lib.lock.json")); err == nil { t.Error("failed add must not write a lockfile") } if _, err := os.Stat(filepath.Join(h.workDir, "external")); err == nil { t.Error("failed add must not create the external area") } } func TestVendorAddDuplicateName(t *testing.T) { h := newHarness(t) standardFixture(h, t) h.mustRun(t, "vendor", "add", "superpowers", h.upstreamDir) out, err := h.run(t, "vendor", "add", "superpowers", h.upstreamDir) if err == nil { t.Fatalf("duplicate source name must fail:\n%s", out) } if !contains(out, "already exists") { t.Errorf("error must be explicit about the duplicate:\n%s", out) } } func TestVendorAddOrphanExternalDir(t *testing.T) { h := newHarness(t) standardFixture(h, t) os.MkdirAll(filepath.Join(h.workDir, "external", "ghost"), 0o755) out, err := h.run(t, "vendor", "add", "ghost", h.upstreamDir) if err == nil { t.Fatalf("orphan external dir must fail:\n%s", out) } if !contains(out, "not in the lockfile") { t.Errorf("error must explain the orphan:\n%s", out) } } func TestVendorAddAtRef(t *testing.T) { h := newHarness(t) standardFixture(h, t) h.git(t, h.upstreamDir, "tag", "v1.0") out := h.mustRun(t, "vendor", "add", "pinned", h.upstreamDir, "--ref", "v1.0") if !contains(out, "ref: v1.0") { t.Errorf("tag ref must be pinned:\n%s", out) } } func contains(haystack, needle string) bool { return strings.Contains(haystack, needle) } func readFile(t *testing.T, path string) string { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatal(err) } return string(data) }