fix(async): own completion across test and provider boundaries

This commit is contained in:
morluto committed 2026-10-25 08:29:20 +08:00
1 parent fdf5a33fe2
commit 5938581b37
37 files changed
+1134 -406

No files matched your search

+5 -7
View File
@@ -1,5 +1,5 @@
import { createVerifierHttpServer } from "../lib/verifier-http-server.mjs";
import { once } from "node:events";
import { createServer } from "node:http";
import { gzipSync } from "node:zlib";
export const networkFixtureSecret = "私密-network-fixture";
@@ -23,7 +23,7 @@ const html = `<!doctype html><meta charset="utf-8"><body><button id="start">Run<
export async function startBrowserNetworkSite() {
const counts = new Map();
const timers = new Set();
const server = createServer(async (request, response) => {
const handleRequest = async (request, response) => {
const path = new URL(request.url, "http://fixture.test").pathname;
counts.set(path, (counts.get(path) ?? 0) + 1);
if (path === "/same") {
@@ -89,7 +89,8 @@ export async function startBrowserNetworkSite() {
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
response.end(html);
}
});
};
const { server, close } = createVerifierHttpServer(handleRequest);
server.listen(0, "127.0.0.1");
await once(server, "listening");
const address = server.address();
@@ -100,10 +101,7 @@ export async function startBrowserNetworkSite() {
counts,
async close() {
for (const timer of timers) clearTimeout(timer);
server.closeAllConnections();
await new Promise((resolve, reject) =>
server.close((error) => (error ? reject(error) : resolve())),
);
await close();
},
};
}
+5 -9
View File
@@ -1,5 +1,5 @@
import { createVerifierHttpServer } from "../lib/verifier-http-server.mjs";
import { once } from "node:events";
import { createServer } from "node:http";
/** The CSRF cookie and the stored bearer token the page holds; request steps must send both and the capture must not keep them. */
export const requestFixtureCsrf = "csrf-fixture-7c1d2e";
@@ -52,7 +52,7 @@ export async function startBrowserRequestSite() {
};
const writes = [];
const hosts = [];
const server = createServer(async (request, response) => {
const handleRequest = async (request, response) => {
const url = new URL(request.url, "http://fixture.test");
hosts.push(`${request.headers.host} ${url.pathname}`);
const chunks = [];
@@ -108,7 +108,8 @@ export async function startBrowserRequestSite() {
}
const [status, value] = answerItems(store, request.method, id, body);
json(response, status, value);
});
};
const { server, close } = createVerifierHttpServer(handleRequest);
server.listen(0, "127.0.0.1");
await once(server, "listening");
const address = server.address();
@@ -120,11 +121,6 @@ export async function startBrowserRequestSite() {
/** Host header and path of every request the server received. */
hosts,
items: store.items,
async close() {
server.closeAllConnections();
await new Promise((resolve, reject) =>
server.close((error) => (error ? reject(error) : resolve())),
);
},
close,
};
}
+12
View File
@@ -0,0 +1,12 @@
import type { IncomingMessage, Server, ServerResponse } from "node:http";
/** Own admitted fixture requests through transport closure and report unexpected failures. */
export function createVerifierHttpServer(
handleRequest: (
request: IncomingMessage,
response: ServerResponse,
) => Promise<void>,
): {
readonly server: Server;
close(): Promise<void>;
};
+39
View File
@@ -0,0 +1,39 @@
import { createServer } from "node:http";
import { withVerifierCleanup } from "./verifier-cleanup.mjs";
/** Own admitted fixture requests through transport closure and report unexpected failures. */
export function createVerifierHttpServer(handleRequest) {
const pending = new Set();
let failure;
const server = createServer((request, response) => {
const work = handleRequest(request, response)
.catch((cause) => {
failure ??= { cause };
response.destroy();
})
.finally(() => {
pending.delete(work);
});
pending.add(work);
});
return {
server,
close() {
return withVerifierCleanup(
() =>
new Promise((resolve, reject) => {
server.close((cause) =>
cause === undefined ? resolve() : reject(cause),
);
server.closeAllConnections();
}),
[
async () => {
await Promise.all(pending);
if (failure !== undefined) throw failure.cause;
},
],
);
},
};
}