summaryrefslogtreecommitdiff
path: root/cli/tests/unit/serve_test.ts
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-09-25 09:23:55 -0600
committerGitHub <noreply@github.com>2023-09-25 17:23:55 +0200
commita27ee8f368dbac33141fdcb9a17d0e4ea907b8ef (patch)
tree4bc1bfa1e23b40bfb726cd5b179091393533dec2 /cli/tests/unit/serve_test.ts
parent83f20007aac0f9ebb0eb59b71a932e7a91d5d9a7 (diff)
fix(ext/http): ensure that resources are closed when request is cancelled (#20641)
Builds on top of #20622 to fix #10854
Diffstat (limited to 'cli/tests/unit/serve_test.ts')
-rw-r--r--cli/tests/unit/serve_test.ts50
1 files changed, 48 insertions, 2 deletions
diff --git a/cli/tests/unit/serve_test.ts b/cli/tests/unit/serve_test.ts
index 2e7836b6a..830817146 100644
--- a/cli/tests/unit/serve_test.ts
+++ b/cli/tests/unit/serve_test.ts
@@ -2699,12 +2699,14 @@ Deno.test(
for (const url of ["text", "file", "stream"]) {
// Ensure that we don't panic when the incoming TCP request was dropped
- // https://github.com/denoland/deno/issues/20315
+ // https://github.com/denoland/deno/issues/20315 and that we correctly
+ // close/cancel the response
Deno.test({
permissions: { read: true, write: true, net: true },
name: `httpServerTcpCancellation_${url}`,
fn: async function () {
const ac = new AbortController();
+ const streamCancelled = url == "stream" ? deferred() : undefined;
const listeningPromise = deferred();
const waitForAbort = deferred();
const waitForRequest = deferred();
@@ -2727,7 +2729,9 @@ for (const url of ["text", "file", "stream"]) {
start(controller) {
_body = null;
controller.enqueue(new Uint8Array([1]));
- controller.close();
+ },
+ cancel(reason) {
+ streamCancelled!.resolve(reason);
},
}),
);
@@ -2753,15 +2757,57 @@ for (const url of ["text", "file", "stream"]) {
// Give it a few milliseconds for the serve machinery to work
await new Promise((r) => setTimeout(r, 10));
+ // Wait for cancellation before we shut the server down
+ if (streamCancelled !== undefined) {
+ await streamCancelled;
+ }
+
// Since the handler has a chance of creating resources or running async ops, we need to use a
// graceful shutdown here to ensure they have fully drained.
await server.shutdown();
+
await server.finished;
},
});
}
Deno.test(
+ { permissions: { net: true } },
+ async function httpServerCancelFetch() {
+ const request2 = deferred();
+ const request2Aborted = deferred();
+ const { finished, abort } = await makeServer(async (req) => {
+ if (req.url.endsWith("/1")) {
+ const fetchRecursive = await fetch(`http://localhost:${servePort}/2`);
+ return new Response(fetchRecursive.body);
+ } else if (req.url.endsWith("/2")) {
+ request2.resolve();
+ return new Response(
+ new ReadableStream({
+ start(_controller) {/* just hang */},
+ cancel(reason) {
+ request2Aborted.resolve(reason);
+ },
+ }),
+ );
+ }
+ fail();
+ });
+ const fetchAbort = new AbortController();
+ const fetchPromise = await fetch(`http://localhost:${servePort}/1`, {
+ signal: fetchAbort.signal,
+ });
+ await fetchPromise;
+ await request2;
+ fetchAbort.abort();
+ assertEquals("resource closed", await request2Aborted);
+
+ abort();
+ await finished;
+ },
+);
+
+Deno.test(
{ permissions: { read: true, net: true } },
async function httpServerWithTls() {
const ac = new AbortController();