Make the client-abort log test wait on the handler, not on fixed sleeps
CI / full-gate (push) Successful in 3m21s
CI / full-gate (push) Successful in 3m21s
This commit is contained in:
@@ -457,3 +457,20 @@ Read most (opens and searches):
|
|||||||
- `src/auth/gate.ts` 1
|
- `src/auth/gate.ts` 1
|
||||||
- `src/auth/jwt.ts` 1
|
- `src/auth/jwt.ts` 1
|
||||||
- `src/server.ts` 1
|
- `src/server.ts` 1
|
||||||
|
|
||||||
|
## Reading cost, chunk ac2b7411e145, finished 2026-11-08T20:50:21Z
|
||||||
|
|
||||||
|
105677 new input tokens before the first commit.
|
||||||
|
|
||||||
|
Read most (opens and searches):
|
||||||
|
|
||||||
|
- `README.md` 15
|
||||||
|
- `src/http/app-admin.test.ts` 7
|
||||||
|
- `todo.md` 5
|
||||||
|
- `CHANGELOG.md` 3
|
||||||
|
- `ci.sh` 3
|
||||||
|
- `examples/README.md` 3
|
||||||
|
- `examples/plugins/auth-admin/admin-shared.test.ts` 3
|
||||||
|
- `src/plugin-host/conflicts.ts` 3
|
||||||
|
- `AGENTS.md` 2
|
||||||
|
- `compose.yml` 2
|
||||||
|
|||||||
+19
-7
@@ -169,14 +169,22 @@ test("ctx.log after a client abort doesn't throw: the request log is ended only
|
|||||||
// deferred until the handler settles (regression for the abort race).
|
// deferred until the handler settles (regression for the abort race).
|
||||||
let afterCloseOk = false;
|
let afterCloseOk = false;
|
||||||
let afterCloseErr: string | undefined;
|
let afterCloseErr: string | undefined;
|
||||||
|
const started = Promise.withResolvers<void>();
|
||||||
|
const closed = Promise.withResolvers<void>();
|
||||||
|
const logged = Promise.withResolvers<void>();
|
||||||
|
let calls = 0;
|
||||||
const plugin: Plugin = {
|
const plugin: Plugin = {
|
||||||
apiVersion: "1.0.0",
|
apiVersion: "1.0.0",
|
||||||
id: "slow",
|
id: "slow",
|
||||||
routes: [{
|
routes: [{
|
||||||
handler: async (ctx) => {
|
handler: async (ctx) => {
|
||||||
await new Promise((r) => setTimeout(r, 120)); // outlasts the client abort below
|
if (calls++ === 0) {
|
||||||
try { ctx.log.info("after abort", {}); afterCloseOk = true; } // would throw if end() already ran
|
started.resolve();
|
||||||
catch (e) { afterCloseErr = String(e); }
|
await closed.promise; // the response has closed under the running handler
|
||||||
|
try { ctx.log.info("after abort", {}); afterCloseOk = true; } // would throw if end() already ran
|
||||||
|
catch (e) { afterCloseErr = String(e); }
|
||||||
|
logged.resolve();
|
||||||
|
}
|
||||||
return { json: { ok: true } };
|
return { json: { ok: true } };
|
||||||
},
|
},
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -184,16 +192,20 @@ test("ctx.log after a client abort doesn't throw: the request log is ended only
|
|||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
const app = createApp({ log: createLogger({ level: "none" }), plugins: [plugin] });
|
const app = createApp({ log: createLogger({ level: "none" }), plugins: [plugin] });
|
||||||
|
// Registered after the host's own listener, so this "close" handler runs after the host's.
|
||||||
|
app.once("request", (_req, res) => res.on("close", () => closed.resolve()));
|
||||||
await new Promise<void>((r) => app.listen(0, r));
|
await new Promise<void>((r) => app.listen(0, r));
|
||||||
t.after(() => app.close());
|
t.after(() => app.close());
|
||||||
const base = `http://localhost:${(app.address() as AddressInfo).port}`;
|
const base = `http://localhost:${(app.address() as AddressInfo).port}`;
|
||||||
|
|
||||||
// Abort the request mid-handler (well before the 120ms), forcing res "close" while it still runs.
|
// Abort the request once the handler is running, forcing res "close" while it still runs.
|
||||||
const ac = new AbortController();
|
const ac = new AbortController();
|
||||||
setTimeout(() => ac.abort(), 20);
|
const aborted = assert.rejects(fetch(base + "/slow/go", { signal: ac.signal })); // the client sees the abort
|
||||||
await assert.rejects(fetch(base + "/slow/go", { signal: ac.signal })); // the client sees the abort
|
await started.promise;
|
||||||
|
ac.abort();
|
||||||
|
await aborted;
|
||||||
|
|
||||||
await new Promise((r) => setTimeout(r, 200)); // let the handler finish post-abort
|
await logged.promise; // the handler finished its post-abort log
|
||||||
assert.equal(afterCloseErr, undefined, "ctx.log did not throw after the client disconnected");
|
assert.equal(afterCloseErr, undefined, "ctx.log did not throw after the client disconnected");
|
||||||
assert.ok(afterCloseOk, "the handler logged successfully after close");
|
assert.ok(afterCloseOk, "the handler logged successfully after close");
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
| ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score |
|
| ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score |
|
||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
| 61 | 0.5.0 | | | **Make the client-abort log test in `src/http/app.test.ts` wait on the handler, not on fixed sleeps.** | 1 | 1 | 1 | 1 | 2 | code health by 2 | 12.0 |
|
|
||||||
| 5 | 0.5.0 | | | **List grants that no installed plugin declares, with a remove action.** | 2 | 2 | 2 | 4 | 4 | 2 by 3 | 2.1 |
|
| 5 | 0.5.0 | | | **List grants that no installed plugin declares, with a remove action.** | 2 | 2 | 2 | 4 | 4 | 2 by 3 | 2.1 |
|
||||||
| 41 | 0.5.0 | | | **Apply a permission save as one Keto call, so it cannot stop part-way.** | 2 | 2 | 2 | 4 | 3 | 2 by 2 | 2.1 |
|
| 41 | 0.5.0 | | | **Apply a permission save as one Keto call, so it cannot stop part-way.** | 2 | 2 | 2 | 4 | 3 | 2 by 2 | 2.1 |
|
||||||
| 19 | 0.6.0 | | question | **Run the documented Docker commands on macOS and fix whatever misbehaves.** | 2 | 2 | 1 | 3 | 3 | 1 by 3 | 3.3 |
|
| 19 | 0.6.0 | | question | **Run the documented Docker commands on macOS and fix whatever misbehaves.** | 2 | 2 | 1 | 3 | 3 | 1 by 3 | 3.3 |
|
||||||
@@ -26,12 +25,6 @@
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
### 61. Make the client-abort log test in `src/http/app.test.ts` wait on the handler, not on fixed sleeps.
|
|
||||||
|
|
||||||
"ctx.log after a client abort doesn't throw" aborts at 20 ms, lets the handler log at 120 ms and asserts
|
|
||||||
at 200 ms. On a loaded CI runner the handler hadn't logged by then (PR #226, run 5739), so the gate went
|
|
||||||
red on unrelated work. Await a promise the handler resolves after it logs instead.
|
|
||||||
|
|
||||||
### 5. List grants that no installed plugin declares, with a remove action.
|
### 5. List grants that no installed plugin declares, with a remove action.
|
||||||
|
|
||||||
`grantDiff` never revokes an undeclared name, and nothing shows one either, so it can't be audited or
|
`grantDiff` never revokes an undeclared name, and nothing shows one either, so it can't be audited or
|
||||||
|
|||||||
Reference in New Issue
Block a user