1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 16:19:12 -05:00

fix(std/http): Fix respond error test on Windows (#4408)

This commit is contained in:
Nayeem Rahman 2020-03-19 23:15:21 +00:00 committed by GitHub
parent a6d8098b35
commit b7e6a31a42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 15 additions and 50 deletions

View file

@ -242,7 +242,7 @@ export async function writeResponse(
const statusText = STATUS_TEXT.get(statusCode); const statusText = STATUS_TEXT.get(statusCode);
const writer = BufWriter.create(w); const writer = BufWriter.create(w);
if (!statusText) { if (!statusText) {
throw Error("bad status code"); throw new Deno.errors.InvalidData("Bad status code");
} }
if (!r.body) { if (!r.body) {
r.body = new Uint8Array(); r.body = new Uint8Array();

View file

@ -10,11 +10,12 @@ import {
assert, assert,
assertEquals, assertEquals,
assertNotEOF, assertNotEOF,
assertStrContains assertStrContains,
assertThrowsAsync
} from "../testing/asserts.ts"; } from "../testing/asserts.ts";
import { Response, ServerRequest, Server, serve } from "./server.ts"; import { Response, ServerRequest, Server, serve } from "./server.ts";
import { BufReader, BufWriter } from "../io/bufio.ts"; import { BufReader, BufWriter } from "../io/bufio.ts";
import { delay, deferred } from "../util/async.ts"; import { delay } from "../util/async.ts";
import { encode, decode } from "../strings/mod.ts"; import { encode, decode } from "../strings/mod.ts";
import { mockConn } from "./mock.ts"; import { mockConn } from "./mock.ts";
@ -488,57 +489,23 @@ test({
} }
}); });
// TODO(kevinkassimo): create a test that works on Windows.
// The following test is to ensure that if an error occurs during respond
// would result in connection closed. (such that fd/resource is freed).
// On *nix, a delayed second attempt to write to a CLOSE_WAIT connection would
// receive a RST and thus trigger an error during response for us to test.
// We need to find a way to similarly trigger an error on Windows so that
// we can test if connection is closed.
test({ test({
ignore: Deno.build.os == "win", name: "respond error closes connection",
name: "respond error handling",
async fn(): Promise<void> { async fn(): Promise<void> {
const connClosedPromise = deferred();
const serverRoutine = async (): Promise<void> => { const serverRoutine = async (): Promise<void> => {
let reqCount = 0;
const server = serve(":8124"); const server = serve(":8124");
// @ts-ignore // @ts-ignore
const serverRid = server.listener["rid"];
let connRid = -1;
for await (const req of server) { for await (const req of server) {
connRid = req.conn.rid; await assertThrowsAsync(async () => {
reqCount++;
await Deno.readAll(req.body);
await connClosedPromise;
try {
await req.respond({ await req.respond({
status: 12345,
body: new TextEncoder().encode("Hello World") body: new TextEncoder().encode("Hello World")
}); });
await delay(100); }, Deno.errors.InvalidData);
req.done = deferred();
// This duplicate respond is to ensure we get a write failure from the
// other side. Our client would enter CLOSE_WAIT stage after close(),
// meaning first server .send (.respond) after close would still work.
// However, a second send would fail under RST, which is similar
// to the scenario where a failure happens during .respond
await req.respond({
body: new TextEncoder().encode("Hello World")
});
} catch {
break;
}
}
server.close();
// Let event loop do another turn so server
// finishes all pending ops.
await delay(0);
const resources = Deno.resources();
assert(reqCount === 1);
// Server should be gone
assert(!(serverRid in resources));
// The connection should be destroyed // The connection should be destroyed
assert(!(connRid in resources)); assert(!(req.conn.rid in Deno.resources()));
server.close();
}
}; };
const p = serverRoutine(); const p = serverRoutine();
const conn = await Deno.connect({ const conn = await Deno.connect({
@ -549,9 +516,7 @@ test({
conn, conn,
new TextEncoder().encode("GET / HTTP/1.1\r\n\r\n") new TextEncoder().encode("GET / HTTP/1.1\r\n\r\n")
); );
conn.close(); // abruptly closing connection before response. conn.close();
// conn on server side enters CLOSE_WAIT state.
connClosedPromise.resolve();
await p; await p;
} }
}); });

View file

@ -348,9 +348,9 @@ export async function assertThrowsAsync(
await fn(); await fn();
} catch (e) { } catch (e) {
if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) { if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) {
msg = `Expected error to be instance of "${ErrorClass.name}"${ msg = `Expected error to be instance of "${ErrorClass.name}", but got "${
msg ? `: ${msg}` : "." e.name
}`; }"${msg ? `: ${msg}` : "."}`;
throw new AssertionError(msg); throw new AssertionError(msg);
} }
if (msgIncludes && !e.message.includes(msgIncludes)) { if (msgIncludes && !e.message.includes(msgIncludes)) {