Public: anyone can read this; the crew can change it.
One test seeds a clog (51 opened against 15 landed, six pulls on one file) and proves the governor and the hot-file hold prevent it #6537
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6523-one-test-seeds-a-clog-51-opened-against → main 1 commit fork
1 file
changed +73
−0
test/flow-clog-prevent.test.ts added +73
| @@ -0,0 +1,73 @@ | ||
| 1 | /** | |
| 2 | * The seeded clog (#6523, part of #5930): 51 pulls opened against 15 landed in | |
| 3 | * the last hour, and six open pulls on one file. The inflow governor lowers the | |
| 4 | * builder slots and says why; the hot-file hold keeps a fresh build off that | |
| 5 | * file while a build on another file may start. Vitals are plain data and the | |
| 6 | * pulls' files are remembered, so no clock and no git. | |
| 7 | */ | |
| 8 | import { afterAll, beforeAll, expect, test } from "bun:test"; | |
| 9 | import { mkdtemp, rm } from "node:fs/promises"; | |
| 10 | import { tmpdir } from "node:os"; | |
| 11 | import { join } from "node:path"; | |
| 12 | import { createApp, type App } from "../src/app.ts"; | |
| 13 | import { openIssue } from "../src/actions/issues.ts"; | |
| 14 | import { createRepo } from "../src/actions/repos.ts"; | |
| 15 | import { createUser, type User } from "../src/core/users.ts"; | |
| 16 | import type { Issue } from "../src/core/issues.ts"; | |
| 17 | import type { Repo } from "../src/core/repos.ts"; | |
| 18 | import { governedSlots } from "../src/crew/governor.ts"; | |
| 19 | import { heldNow } from "../src/crew/held.ts"; | |
| 20 | import { HOT_PULLS, rememberPullFiles } from "../src/crew/hot_files.ts"; | |
| 21 | import type { Vitals } from "../src/flow/vitals.ts"; | |
| 22 | ||
| 23 | let dataDir: string; | |
| 24 | let app: App; | |
| 25 | let alice: User; | |
| 26 | let repo: Repo; | |
| 27 | ||
| 28 | beforeAll(async () => { | |
| 29 | dataDir = await mkdtemp(join(tmpdir(), "forge-clog-")); | |
| 30 | app = createApp({ dataDir, port: 0 }); | |
| 31 | const a = await createUser(app.db, { | |
| 32 | origin: "seed", trusted: true, username: "alice", email: "[email protected]", | |
| 33 | password: "a-good-passphrase", adminIfFirst: true, | |
| 34 | }); | |
| 35 | if (!a.ok) throw new Error(a.error); | |
| 36 | alice = a.value; | |
| 37 | const made = await createRepo(app, alice, { name: "engine" }); | |
| 38 | if (!made.ok) throw new Error(String(made.error)); | |
| 39 | repo = made.value; | |
| 40 | }); | |
| 41 | ||
| 42 | afterAll(async () => { | |
| 43 | rememberPullFiles(repo.id, []); | |
| 44 | app.close(); | |
| 45 | await rm(dataDir, { recursive: true, force: true }); | |
| 46 | }); | |
| 47 | ||
| 48 | const open = (title: string): Issue => { | |
| 49 | const r = openIssue(app, alice, repo, { title, body: "" }); | |
| 50 | if (!r.ok) throw new Error(String(r.error)); | |
| 51 | return r.value; | |
| 52 | }; | |
| 53 | ||
| 54 | test("a seeded clog lowers the slots and holds a fresh build on the hot file", () => { | |
| 55 | const clog: Vitals = { open: 8, opened1h: 51, landed1h: 15, opened6h: 120, landed6h: 40, conflicted: 0 }; | |
| 56 | const ceiling = 7; | |
| 57 | const governed = governedSlots(clog, ceiling); | |
| 58 | expect(governed.slots).toBeLessThan(ceiling); | |
| 59 | expect(governed.slots).toBeGreaterThanOrEqual(1); | |
| 60 | expect(governed.why).toContain("51 opened"); | |
| 61 | expect(governed.why).toContain("15 landed"); | |
| 62 | ||
| 63 | rememberPullFiles( | |
| 64 | repo.id, | |
| 65 | Array.from({ length: HOT_PULLS + 1 }, (_, i) => ({ number: i + 1, files: ["src/hot.ts", `src/own${i}.ts`] })), | |
| 66 | ); | |
| 67 | const hot = open("Add a flag to src/hot.ts"); | |
| 68 | const cold = open("Tidy src/cold.ts"); | |
| 69 | ||
| 70 | const held = heldNow(app, repo); | |
| 71 | expect(held.by.hot_file.map((i) => i.number)).toEqual([hot.number]); | |
| 72 | expect(held.startable.map((r) => r.issue.number)).toEqual([cold.number]); | |
| 73 | }); |
new above
offline