Public: anyone can read this; the crew can change it.
Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:hwr5ogflj6 is past its budget: trevato/forge: "migrate: after > POST /api/v1/migrate with an unknown `after` is a 400 naming the three words" failed o… #4535
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4533-sentinel-shared-01m23vygyffx5hg2f5vm8r74 → main 1 commit fork
1 file
changed +43
−16
test/migrate-after.test.ts +43 −16
| @@ -133,22 +133,6 @@ describe("migrate: after", () => { | ||
| 133 | 133 | expect(afterChoice("delete")).toBe("leave"); |
| 134 | 134 | }); |
| 135 | 135 | |
| 136 | // Ahead of the tests that start migrations and mirror pushes: its verdict | |
| 137 | // is the handler's, not whatever git work an earlier test left running. | |
| 138 | test("POST /api/v1/migrate with an unknown `after` is a 400 naming the three words", async () => { | |
| 139 | const token = createToken(app.db, alice.id, "api", "admin").token; | |
| 140 | const res = await fetch(`http://127.0.0.1:${servers.port}/api/v1/migrate`, { | |
| 141 | method: "POST", | |
| 142 | headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, | |
| 143 | body: JSON.stringify({ source: { url: "https://github.com/octo/x" }, after: "delete" }), | |
| 144 | }); | |
| 145 | expect(res.status).toBe(400); | |
| 146 | const said = JSON.stringify(await res.json()); | |
| 147 | expect(said).toContain("leave"); | |
| 148 | expect(said).toContain("archive"); | |
| 149 | expect(said).toContain("mirror"); | |
| 150 | }, 30_000); | |
| 151 | ||
| 152 | 136 | test("/migrate offers the three choices, leaving it alone by default", async () => { |
| 153 | 137 | const html = await ( |
| 154 | 138 | await fetch(`http://127.0.0.1:${servers.port}/migrate`, { |
| @@ -265,3 +249,46 @@ describe("migrate: after", () => { | ||
| 265 | 249 | expect(getMirrorTarget(app.db, getRepo(app.db, "alice", copy)!.id)).toBeUndefined(); |
| 266 | 250 | }); |
| 267 | 251 | }); |
| 252 | ||
| 253 | // The handler's refusal needs an app and a token, not the fake GitHub, the | |
| 254 | // mirror loop or any git work: its own small fixture, so a loaded machine | |
| 255 | // slowing the fixture above cannot fail it. | |
| 256 | describe("migrate: after, refused at the boundary", () => { | |
| 257 | let dataDir: string; | |
| 258 | let app: App; | |
| 259 | let servers: Servers; | |
| 260 | ||
| 261 | beforeAll(async () => { | |
| 262 | dataDir = await mkdtemp(join(tmpdir(), "forge-migrate-after-400-")); | |
| 263 | app = createApp({ dataDir, port: 0 }); | |
| 264 | servers = await serve(app); | |
| 265 | }, 60_000); | |
| 266 | ||
| 267 | afterAll(async () => { | |
| 268 | servers.stop(); | |
| 269 | app.close(); | |
| 270 | await rm(dataDir, { recursive: true, force: true, maxRetries: 20, retryDelay: 100 }); | |
| 271 | }, 30_000); | |
| 272 | ||
| 273 | test("POST /api/v1/migrate with an unknown `after` is a 400 naming the three words", async () => { | |
| 274 | const made = await createUser(app.db, { | |
| 275 | origin: "seed", | |
| 276 | trusted: true, | |
| 277 | username: "alice", | |
| 278 | email: "[email protected]", | |
| 279 | adminIfFirst: true, | |
| 280 | }); | |
| 281 | if (!made.ok) throw new Error(String(made.error)); | |
| 282 | const token = createToken(app.db, made.value.id, "api", "admin").token; | |
| 283 | const res = await fetch(`http://127.0.0.1:${servers.port}/api/v1/migrate`, { | |
| 284 | method: "POST", | |
| 285 | headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, | |
| 286 | body: JSON.stringify({ source: { url: "https://github.com/octo/x" }, after: "delete" }), | |
| 287 | }); | |
| 288 | expect(res.status).toBe(400); | |
| 289 | const said = JSON.stringify(await res.json()); | |
| 290 | expect(said).toContain("leave"); | |
| 291 | expect(said).toContain("archive"); | |
| 292 | expect(said).toContain("mirror"); | |
| 293 | }, 60_000); | |
| 294 | }); |
new above
offline