fix(cli/test): clear connection pool after tests (#20680)

This helps reduce flakes where a test starts an HTTP server and makes a
request using fetch, then shuts down the server, then starting a new
test with a new server, but the connection pool still has a "not quite
closed yet" connection to the old server, and a new request to the new
server gets sent on the closed connection, which obviously errors out.
This commit is contained in:
Luca Casonato 2023-09-26 19:46:06 +09:00 committed by GitHub
parent 6f87962a77
commit c68650d532
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 17 additions and 53 deletions

View file

@ -20,6 +20,7 @@ use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::OpMetrics;
use deno_core::OpState;
use deno_runtime::deno_fetch::reqwest;
use deno_runtime::permissions::create_child_permissions;
use deno_runtime::permissions::ChildPermissionsArg;
use deno_runtime::permissions::PermissionsContainer;
@ -348,6 +349,10 @@ fn op_test_op_sanitizer_finish(
#[smi] op_id_host_recv_msg: usize,
#[smi] op_id_host_recv_ctrl: usize,
) -> Result<u8, AnyError> {
// Drop `fetch` connection pool at the end of a test
state.try_take::<reqwest::Client>();
// Generate a report of pending ops
let report = {
let after_metrics = match try_collect_metrics(
state,

View file

@ -1752,8 +1752,7 @@ Deno.test(
// if transfer-encoding is sent, content-length is ignored
// even if it has an invalid value (content-length > totalLength)
const listener = invalidServer(addr, body);
const client = Deno.createHttpClient({});
const response = await fetch(`http://${addr}/`, { client });
const response = await fetch(`http://${addr}/`);
const res = await response.arrayBuffer();
const buf = new TextEncoder().encode(data);
@ -1761,7 +1760,6 @@ Deno.test(
assertEquals(new Uint8Array(res), buf);
listener.close();
client.close();
},
);
@ -1783,17 +1781,15 @@ Deno.test(
// It should fail if multiple content-length headers with different values are sent
const listener = invalidServer(addr, body);
const client = Deno.createHttpClient({});
await assertRejects(
async () => {
await fetch(`http://${addr}/`, { client });
await fetch(`http://${addr}/`);
},
TypeError,
"invalid content-length parsed",
);
listener.close();
client.close();
},
);
@ -1811,8 +1807,7 @@ Deno.test(
);
const listener = invalidServer(addr, body);
const client = Deno.createHttpClient({});
const response = await fetch(`http://${addr}/`, { client });
const response = await fetch(`http://${addr}/`);
// If content-length < totalLength, a maximum of content-length bytes
// should be returned.
@ -1822,7 +1817,6 @@ Deno.test(
assertEquals(new Uint8Array(res), buf.subarray(contentLength));
listener.close();
client.close();
},
);
@ -1840,8 +1834,7 @@ Deno.test(
);
const listener = invalidServer(addr, body);
const client = Deno.createHttpClient({});
const response = await fetch(`http://${addr}/`, { client });
const response = await fetch(`http://${addr}/`);
// If content-length > totalLength, a maximum of content-length bytes
// should be returned.
await assertRejects(
@ -1853,7 +1846,6 @@ Deno.test(
);
listener.close();
client.close();
},
);
@ -1943,12 +1935,10 @@ Deno.test(
},
});
const client = Deno.createHttpClient({});
const err = await assertRejects(() =>
fetch(`http://localhost:${listenPort}/`, {
body: stream,
method: "POST",
client,
})
);
@ -1958,7 +1948,6 @@ Deno.test(
assertEquals(err.cause.message, "foo");
await server;
client.close();
},
);

View file

@ -198,14 +198,12 @@ Deno.test(
await respondWith(new Response(stream.readable));
})();
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${listenPort}/`, { client });
const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
const respBody = await resp.text();
assertEquals("hello world", respBody);
await promise;
httpConn!.close();
listener.close();
client.close();
},
);
@ -237,17 +235,14 @@ Deno.test(
listener.close();
})();
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
body: stream.readable,
method: "POST",
headers: { "connection": "close" },
client,
});
await resp.arrayBuffer();
await promise;
client.close();
},
);
@ -354,13 +349,13 @@ Deno.test(
const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem");
const client = Deno.createHttpClient({ caCerts: [caCert] });
const resp = await fetch(`https://${hostname}:${port}/`, {
client,
headers: { "connection": "close" },
client,
});
client.close();
const respBody = await resp.text();
assertEquals("Hello World", respBody);
await promise;
client.close();
},
);
@ -380,11 +375,9 @@ Deno.test(
await respondWith(new Response("response"));
})();
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
method: "POST",
body: "request",
client,
});
const respBody = await resp.text();
assertEquals("response", respBody);
@ -392,7 +385,6 @@ Deno.test(
httpConn!.close();
listener.close();
client.close();
},
);
@ -435,11 +427,9 @@ Deno.test(
listener.close();
})();
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
await resp.body!.cancel();
await promise;
client.close();
},
);

View file

@ -965,8 +965,7 @@ function createStreamTest(count: number, delay: number, action: string) {
try {
await listeningPromise;
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${servePort}/`, { client });
const resp = await fetch(`http://127.0.0.1:${servePort}/`);
if (action == "Throw") {
await assertRejects(async () => {
await resp.text();
@ -981,7 +980,6 @@ function createStreamTest(count: number, delay: number, action: string) {
assertEquals(text, expected);
}
client.close();
} finally {
ac.abort();
await server.shutdown();
@ -1098,14 +1096,12 @@ Deno.test(
});
await listeningPromise;
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${servePort}/`, { client });
const resp = await fetch(`http://127.0.0.1:${servePort}/`);
const respBody = await resp.text();
assertEquals("", respBody);
ac.abort();
await server.finished;
client.close();
},
);
@ -1142,14 +1138,12 @@ Deno.test(
});
await listeningPromise;
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${servePort}/`, { client });
const resp = await fetch(`http://127.0.0.1:${servePort}/`);
// Incorrectly implemented reader ReadableStream should reject.
assertStringIncludes(await resp.text(), "Failed to execute 'enqueue'");
await errorPromise;
ac.abort();
await server.finished;
client.close();
},
);
@ -1606,11 +1600,9 @@ Deno.test(
);
const { readable, writable } = new TransformStream();
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
method: "POST",
body: readable,
client,
});
await promise;
@ -1618,7 +1610,6 @@ Deno.test(
await testDuplex(resp.body.getReader(), writable.getWriter());
ac.abort();
await server.finished;
client.close();
},
);
@ -1653,11 +1644,9 @@ Deno.test(
);
const { readable, writable } = new TransformStream();
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
method: "POST",
body: readable,
client,
});
await promise;
@ -1665,7 +1654,6 @@ Deno.test(
await testDuplex(resp.body.getReader(), writable.getWriter());
ac.abort();
await server.finished;
client.close();
},
);
@ -2624,12 +2612,9 @@ for (const testCase of compressionTestCases) {
});
try {
await listeningPromise;
const client = Deno.createHttpClient({});
const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
headers: testCase.in as HeadersInit,
client,
});
client.close();
await promise;
const body = await resp.arrayBuffer();
if (testCase.expect == null) {
@ -3260,16 +3245,14 @@ Deno.test(
let count = 0;
const server = Deno.serve({
async onListen({ port }: { port: number }) {
const client = Deno.createHttpClient({});
const res1 = await fetch(`http://localhost:${port}/`, { client });
const res1 = await fetch(`http://localhost:${port}/`);
assertEquals(await res1.text(), "hello world 1");
const res2 = await fetch(`http://localhost:${port}/`, { client });
const res2 = await fetch(`http://localhost:${port}/`);
assertEquals(await res2.text(), "hello world 2");
promise.resolve();
ac.abort();
client.close();
},
signal: ac.signal,
}, () => {
@ -3322,16 +3305,13 @@ Deno.test(
try {
const port = await listeningPromise;
const client = Deno.createHttpClient({});
const resp = await fetch(`http://localhost:${port}/`, {
headers: { connection: "close" },
method: "POST",
body: '{"sus":true}',
client,
});
const text = await resp.text();
assertEquals(text, "ok");
client.close();
} finally {
ac.abort();
await server.finished;