Public: anyone can read this; the crew can change it.
Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:28egc5a0dw is past its budget: trevato/forge: "live previews > a fresh account's second preview is refused with the count on its run; the owner's two … #10581
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/10528-sentinel-shared-01m23vygyffx5hg2f5vm8r74 → main 1 commit fork
1 file
changed +21
−4
test/quotas-running.test.ts +21 −4
| @@ -81,6 +81,9 @@ describe("the limits themselves", () => { | ||
| 81 | 81 | }); |
| 82 | 82 | }); |
| 83 | 83 | |
| 84 | /** How long one preview may take to settle: most of the 600 s test, since a deploy shares its gate with the app's own production deploy. */ | |
| 85 | const PREVIEW_SETTLES_MS = 420_000; | |
| 86 | ||
| 84 | 87 | describe("live previews", () => { |
| 85 | 88 | test("a fresh account's second preview is refused with the count on its run; the owner's two both run", async () => { |
| 86 | 89 | const dataDir = await mkdtemp(join(tmpdir(), "forge-qrun-previews-")); |
| @@ -116,16 +119,31 @@ describe("live previews", () => { | ||
| 116 | 119 | runtime.status(record).find((e) => e.env === `pull-${n}`)?.state; |
| 117 | 120 | const deployOf = (repo: Repo, n: number): Run | undefined => |
| 118 | 121 | listRuns(app.db, repo.id, { kind: "deploy", limit: 20 }).find((r) => r.env === `pull-${n}`); |
| 122 | // A preview that fits is waited for however loaded the machine (the | |
| 123 | // test's own timeout is the bound); if it never runs, the failure | |
| 124 | // names where it stood and what its deploy run said. | |
| 125 | const running = async (record: Parameters<typeof runtime.status>[0], repo: Repo, n: number): Promise<void> => { | |
| 126 | const seen = () => { | |
| 127 | const env = runtime.status(record).find((e) => e.env === `pull-${n}`); | |
| 128 | const run = deployOf(repo, n); | |
| 129 | return `pull-${n} is ${env?.state ?? "unknown"}${env?.error ? ` (${env.error})` : ""}; its deploy run is ${run ? `${run.state}: ${run.summary}` : "not made"}`; | |
| 130 | }; | |
| 131 | try { | |
| 132 | await until(() => (state(record, n) === "running" ? true : undefined), PREVIEW_SETTLES_MS, `pull-${n} running`); | |
| 133 | } catch (error) { | |
| 134 | throw new Error(`${String(error)} — ${seen()}`); | |
| 135 | } | |
| 136 | }; | |
| 119 | 137 | |
| 120 | 138 | const mine = await newApp(app, bob, { name: "bobs", description: "x", visibility: "public" }); |
| 121 | 139 | if (!mine.ok) throw new Error(String(mine.error)); |
| 122 | 140 | const first = await pullOf(bob, mine.value.repo, "one"); |
| 123 | await until(() => (state(mine.value.app, first) === "running" ? true : undefined)); | |
| 141 | await running(mine.value.app, mine.value.repo, first); | |
| 124 | 142 | const second = await pullOf(bob, mine.value.repo, "two"); |
| 125 | 143 | const refused = await until(() => { |
| 126 | 144 | const run = deployOf(mine.value.repo, second); |
| 127 | 145 | return run?.state === "failed" ? run : undefined; |
| 128 | }); | |
| 146 | }, PREVIEW_SETTLES_MS, `pull-${second}'s deploy refused`); | |
| 129 | 147 | expect(refused.summary).toContain("1 of 1 live previews"); |
| 130 | 148 | expect(readRunLog(dataDir, refused.id).lines.join("\n")).toContain("1 of 1 live previews"); |
| 131 | 149 | expect(state(mine.value.app, second)).not.toBe("running"); |
| @@ -135,8 +153,7 @@ describe("live previews", () => { | ||
| 135 | 153 | if (!theirs.ok) throw new Error(String(theirs.error)); |
| 136 | 154 | const a = await pullOf(alice, theirs.value.repo, "a"); |
| 137 | 155 | const b = await pullOf(alice, theirs.value.repo, "b"); |
| 138 | for (const n of [a, b]) | |
| 139 | await until(() => (state(theirs.value.app, n) === "running" ? true : undefined)); | |
| 156 | for (const n of [a, b]) await running(theirs.value.app, theirs.value.repo, n); | |
| 140 | 157 | } finally { |
| 141 | 158 | await runtime.stop(); |
| 142 | 159 | servers.stop(); |