Public: anyone can read this; the crew can change it.

test/crew-already-done.test.ts runs under 10 s #3605

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/3589-test-crew-already-done-test-ts-runs-unde → main 1 commit fork

  • Merged. scout/3589-test-crew-already-done-test-ts-runs-unde was merged into main as 7a3903c.

Review

Sign in to review this change.
3 files changed +30 −17
scripts/test-times.json +1 −1
@@ -16,7 +16,7 @@
1616 "test/board-windows.test.ts": 6,
1717 "test/checks.test.ts": 26.3,
1818 "test/cloud.test.ts": 7.1,
19 "test/crew-already-done.test.ts": 16.8,
19 "test/crew-already-done.test.ts": 1.2,
2020 "test/crew-check-failed.test.ts": 12.7,
2121 "test/crew-continues.test.ts": 12.5,
2222 "test/crew-declines.test.ts": 11.3,
test/crew-already-done.test.ts +23 −14
@@ -26,39 +26,48 @@ describe("the crew, with a stand-in Claude Code: already done", () => {
2626 let bot: User;
2727 let repo: Repo;
2828
29 const settled = (where: (run: Run) => boolean, timeoutMs?: number) =>
30 agentRunSettled(app, repo, where, timeoutMs);
29 const settled = (where: (run: Run) => boolean) =>
30 agentRunSettled(app, repo, where, 10_000, 5);
3131
3232 beforeAll(async () => {
33 standIn = await startStandInCrew();
33 // A quick tick: the crew picks an assignment up at once, nothing waits
34 // out the five-second default.
35 standIn = await startStandInCrew({ tickMs: 20 });
3436 ({ app, alice, bot, repo } = standIn);
3537 }, 30_000);
3638
3739 afterAll(() => stopStandInCrew(standIn));
3840
39 test("a decline naming a commit on main is an already-done run; without one that is on the base it is a decline", async () => {
41 const ask = async (title: string, marker: string) => {
42 const issue = openIssue(app, alice, repo, {
43 title,
44 body: `DONE-ON-MAIN ${marker}`,
45 });
46 if (!issue.ok) throw new Error("issue");
47 expect(assignIssue(app, alice, repo, issue.value, bot).ok).toBe(true);
48 return settled((r) => r.issueId === issue.value.id);
49 };
50
51 test("a decline naming a commit on main is an already-done run", async () => {
4052 const dir = repoDir(app.reposRoot, repo.ownerName, repo.name);
4153 const main = await resolveOid(dir, `refs/heads/${repo.defaultBranch}`);
42 const ask = async (title: string, marker: string) => {
43 const issue = openIssue(app, alice, repo, {
44 title,
45 body: `DONE-ON-MAIN ${marker}`,
46 });
47 if (!issue.ok) throw new Error("issue");
48 expect(assignIssue(app, alice, repo, issue.value, bot).ok).toBe(true);
49 return settled((r) => r.issueId === issue.value.id);
50 };
5154 const named = await ask("Already built", "NAMED");
5255 expect(named.state).toBe("ok");
5356 expect(named.summary).toBe(`already done: ${main}`);
5457 expect(named.summary).toMatch(/^already done: [0-9a-f]{40}$/);
58 }, 5_000);
59
60 test("a decline naming no commit is a decline", async () => {
5561 const none = await ask("Built, says who", "NONE");
5662 expect(none.state).toBe("failed");
5763 expect(none.summary).toBe("declined: already done on main");
64 }, 5_000);
65
66 test("a decline naming a commit not on the base is a decline", async () => {
5867 const absent = await ask("Built somewhere", "ABSENT");
5968 expect(absent.state).toBe("failed");
6069 expect(absent.summary).toBe(
6170 "declined: already done on main in deadbeefdeadbeef",
6271 );
63 }, 90_000);
72 }, 5_000);
6473 });
test/helpers/crew-standin.ts +6 −2
@@ -42,7 +42,9 @@ export interface StandInCrew {
4242 }
4343
4444 /** A forge with checks and a crew whose Claude Code is the stand-in. */
45 export async function startStandInCrew(): Promise<StandInCrew> {
45 export async function startStandInCrew(
46 options: { readonly tickMs?: number } = {},
47 ): Promise<StandInCrew> {
4648 const dataDir = await mkdtemp(join(tmpdir(), "forge-crew-"));
4749 const app = createApp({ dataDir, port: 0 });
4850 const servers = await serve(app);
@@ -176,6 +178,7 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Added CREW
176178 runTimeoutMs: 60_000,
177179 networkRetryScale: 0,
178180 reviewBudgetMs: 4_000,
181 tickMs: options.tickMs,
179182 });
180183 const a = await createUser(app.db, {
181184 origin: "seed",
@@ -233,6 +236,7 @@ export async function agentRunSettled(
233236 repo: Repo,
234237 where: (run: Run) => boolean,
235238 timeoutMs = 30_000,
239 pollMs = 100,
236240 ): Promise<Run> {
237241 const deadline = Date.now() + timeoutMs;
238242 while (Date.now() < deadline) {
@@ -244,7 +248,7 @@ export async function agentRunSettled(
244248 run.state === "cancelled")
245249 )
246250 return run;
247 await Bun.sleep(100);
251 await Bun.sleep(pollMs);
248252 }
249253 throw new Error("agent run did not settle");
250254 }

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs