Public: anyone can read this; the crew can change it.
test/crew-remotes.test.ts runs in under 10 s, every test under 1 s, proving what it proves today #10234
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/10227-test-crew-remotes-test-ts-runs-in-under → main 1 commit fork
1 file
changed +28
−13
test/crew-remotes.test.ts +28 −13
| @@ -18,6 +18,7 @@ import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | ||
| 18 | 18 | import { createApp, type App } from "../src/app.ts"; |
| 19 | 19 | import { startCrew, type CrewHandle } from "../src/crew/dispatch.ts"; |
| 20 | 20 | import { listPulls } from "../src/core/pulls.ts"; |
| 21 | import type { Issue } from "../src/core/issues.ts"; | |
| 21 | 22 | import type { Repo } from "../src/core/repos.ts"; |
| 22 | 23 | import { listRuns, type Run } from "../src/core/runs.ts"; |
| 23 | 24 | import { createUser, type User } from "../src/core/users.ts"; |
| @@ -42,11 +43,11 @@ describe("the remotes an agent is handed", () => { | ||
| 42 | 43 | let remotesFile: string; |
| 43 | 44 | |
| 44 | 45 | async function settled(where: (run: Run) => boolean): Promise<Run> { |
| 45 | const deadline = Date.now() + 30_000; | |
| 46 | const deadline = Date.now() + 4_000; | |
| 46 | 47 | while (Date.now() < deadline) { |
| 47 | 48 | const run = listRuns(app.db, repo.id, { kind: "agent" }).find(where); |
| 48 | 49 | if (run && run.state !== "queued" && run.state !== "running") return run; |
| 49 | await Bun.sleep(100); | |
| 50 | await Bun.sleep(20); | |
| 50 | 51 | } |
| 51 | 52 | throw new Error("agent run did not settle"); |
| 52 | 53 | } |
| @@ -81,6 +82,8 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Added CREW | ||
| 81 | 82 | concurrency: 1, |
| 82 | 83 | budgetUsd: 1, |
| 83 | 84 | runTimeoutMs: 60_000, |
| 85 | // The pump's clock: a run queued is taken on the next tick, not 5 s on. | |
| 86 | tickMs: 20, | |
| 84 | 87 | }); |
| 85 | 88 | const a = await createUser(app.db, { |
| 86 | 89 | origin: "seed", |
| @@ -116,18 +119,26 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Added CREW | ||
| 116 | 119 | await rm(dataDir, { recursive: true, force: true }); |
| 117 | 120 | }); |
| 118 | 121 | |
| 122 | // The issue and its first run, made by the first test; the second visits | |
| 123 | // the clone that run left. | |
| 124 | let issue: Issue; | |
| 125 | let firstRun: Run; | |
| 126 | ||
| 119 | 127 | // The stand-in runs outside any sandbox, so what this proves is the |
| 120 | 128 | // address the agent is handed and that a plain push over it lands — not |
| 121 | 129 | // the sandbox's own reach, which is Claude Code's to hold. |
| 122 | 130 | test("carry the forge's public URL, fetch from the repository and push to the agent's fork, and a plain push lands", async () => { |
| 131 | // Invariant: a fresh clone's fetch and push remotes are the forge's public URL, and a plain `git push` over them opens the pull. | |
| 123 | 132 | expect(publicUrl).not.toBe(servers.url); |
| 124 | const issue = openIssue(app, alice, repo, { | |
| 133 | const opened = openIssue(app, alice, repo, { | |
| 125 | 134 | title: "Plant tulips", |
| 126 | 135 | body: "Along the fence.", |
| 127 | 136 | }); |
| 128 | if (!issue.ok) throw new Error(String(issue.error)); | |
| 129 | expect(assignIssue(app, alice, repo, issue.value, bot).ok).toBe(true); | |
| 130 | const run = await settled((r) => r.issueId === issue.value.id); | |
| 137 | if (!opened.ok) throw new Error(String(opened.error)); | |
| 138 | issue = opened.value; | |
| 139 | expect(assignIssue(app, alice, repo, issue, bot).ok).toBe(true); | |
| 140 | const run = await settled((r) => r.issueId === issue.id); | |
| 141 | firstRun = run; | |
| 131 | 142 | expect(run.state).toBe("ok"); |
| 132 | 143 | expect(run.summary).toMatch(/^opened pull #\d+( \([0-9a-f]{7,40}\))?$/); |
| 133 | 144 | const [fetchUrl, pushUrl] = readFileSync(remotesFile, "utf8") |
| @@ -137,16 +148,20 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Added CREW | ||
| 137 | 148 | expect(pushUrl).toBe(`${publicUrl}/bot/garden.git`); |
| 138 | 149 | const pull = listPulls(app.db, repo.id, { state: "open" })[0]!; |
| 139 | 150 | expect(pull.headBranch).toBe(run.branch); |
| 151 | }); | |
| 140 | 152 | |
| 141 | // A clone kept from before the forge changed where its remotes point — | |
| 142 | // a run resumed after a release — is set right again on every visit, | |
| 143 | // not only when it is first made. | |
| 153 | // A clone kept from before the forge changed where its remotes point — | |
| 154 | // a run resumed after a release — is set right again on every visit, | |
| 155 | // not only when it is first made. | |
| 156 | test("are set right again on a kept clone whose remotes went stale", async () => { | |
| 157 | // Invariant: a kept clone's stale remotes are reset to the forge's public URL on every visit, and the next push updates the pull. | |
| 158 | expect(firstRun?.state).toBe("ok"); | |
| 144 | 159 | const clone = join( |
| 145 | 160 | dataDir, |
| 146 | 161 | "crew", |
| 147 | 162 | "bot", |
| 148 | 163 | repo.id, |
| 149 | String(issue.value.number), | |
| 164 | String(issue.number), | |
| 150 | 165 | ); |
| 151 | 166 | for (const key of ["remote.origin.url", "remote.origin.pushurl"]) { |
| 152 | 167 | const stale = Bun.spawnSync( |
| @@ -159,12 +174,12 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Added CREW | ||
| 159 | 174 | app, |
| 160 | 175 | alice, |
| 161 | 176 | repo, |
| 162 | issue.value, | |
| 177 | issue, | |
| 163 | 178 | "Also plant daffodils.", |
| 164 | 179 | ); |
| 165 | 180 | if (!said.ok) throw new Error(String(said.error)); |
| 166 | 181 | const again = await settled( |
| 167 | (r) => r.issueId === issue.value.id && r.id !== run.id, | |
| 182 | (r) => r.issueId === issue.id && r.id !== firstRun.id, | |
| 168 | 183 | ); |
| 169 | 184 | expect(again.state).toBe("ok"); |
| 170 | 185 | expect(again.summary).toMatch(/^updated pull #\d+/); |
| @@ -173,5 +188,5 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Added CREW | ||
| 173 | 188 | .split("\n"); |
| 174 | 189 | expect(fetchAgain).toBe(`${publicUrl}/alice/garden.git`); |
| 175 | 190 | expect(pushAgain).toBe(`${publicUrl}/bot/garden.git`); |
| 176 | }, 90_000); | |
| 191 | }); | |
| 177 | 192 | }); |