|
1 | 1 | import { mkdtempSync, rmSync } from 'node:fs'; |
2 | 2 | import { tmpdir } from 'node:os'; |
3 | 3 | import { join } from 'node:path'; |
| 4 | +import { request as httpRequest } from 'node:http'; |
| 5 | +import { DatabaseSync } from 'node:sqlite'; |
4 | 6 | import { createHash, randomUUID } from 'node:crypto'; |
5 | 7 | import { choiceKeys } from '../core/approvals.ts'; |
6 | 8 | import { afterEach, describe, expect, it, vi } from 'vitest'; |
@@ -160,6 +162,28 @@ describe('planning API for lane G', () => { |
160 | 162 | for (let i = 0; i < 50 && (await api(app, 'GET', `/api/plan/suggestions/${ready}`)).body.state !== 'ready'; i++) await new Promise(r => setTimeout(r, 20)); |
161 | 163 | expect((await api(app, 'POST', `/api/plan/suggestions/${ready}/cancel`, { actionId: randomUUID() })).body.result).toEqual({ state: 'cancelled' }); |
162 | 164 | }); |
| 165 | + it('starts no planning agent for a suggestion request that finishes arriving after shutdown began', async () => { |
| 166 | + const { deps, calls } = planning(); |
| 167 | + const { app, config, close } = await serve({ planning: deps }); |
| 168 | + const view = await review(app), url = new URL(app.url); |
| 169 | + const text = JSON.stringify({ expectedRevision: view.plan.revision, snapshotId: view.snapshot.id, feedback: '', actionId: randomUUID() }); |
| 170 | + let finish!: () => void; |
| 171 | + const response = new Promise<number>((resolve, reject) => { |
| 172 | + const req = httpRequest({ host: url.hostname, port: url.port, path: '/api/plan/suggestions', method: 'POST', |
| 173 | + headers: { 'x-codeboost-token': app.token, 'content-type': 'application/json', 'content-length': Buffer.byteLength(text) } }, res => { res.resume(); resolve(res.statusCode!); }); |
| 174 | + req.on('error', reject); req.write(text.slice(0, 5)); finish = () => req.end(text.slice(5)); |
| 175 | + }); |
| 176 | + await new Promise(r => setTimeout(r, 20)); |
| 177 | + const closing = close(); |
| 178 | + await new Promise(r => setTimeout(r, 20)); |
| 179 | + finish(); |
| 180 | + expect(await response).toBe(503); |
| 181 | + await closing; |
| 182 | + expect(calls).toHaveLength(0); |
| 183 | + // No suggestion request was allocated either. |
| 184 | + const db = new DatabaseSync(config.database); |
| 185 | + try { expect(db.prepare('SELECT COUNT(*) AS n FROM requests').get()).toEqual({ n: 0 }); } finally { db.close(); } |
| 186 | + }); |
163 | 187 | it('settles a pending suggestion at shutdown instead of leaving it pending', async () => { |
164 | 188 | const { deps, calls } = planning(); |
165 | 189 | const { app, config, close } = await serve({ planning: deps }); |
|
0 commit comments