chore: Promote some integration tests to js_unit_tests (#22355)

- Move a workers test to js_unit_tests and make it work
- (slightly) repair the websocketstream_test and make it a JS unit test.
This test was being ignored and rotted quite a bit, but there's some
value in running as much of it as we can.
 - Merge the two websocket test files
This commit is contained in:
Matt Mastracci 2024-02-08 13:09:47 -07:00 committed by GitHub
parent d704007e5f
commit a417772bd7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 440 additions and 495 deletions

View file

@ -105,9 +105,10 @@ util::unit_test_factory!(
webcrypto_test,
webgpu_test,
websocket_test,
websocketstream_test,
webstorage_test,
worker_permissions_test,
worker_types,
worker_test,
write_file_test,
write_text_file_test,
]
@ -123,7 +124,7 @@ fn js_unit_test(test: String) {
.arg("cli/tests/config/deno.json")
.arg("--no-lock")
.arg("--unstable")
.arg("--location=http://js-unit-tests/foo/bar")
.arg("--location=http://127.0.0.1:4545/")
.arg("--no-prompt");
// TODO(mmastrac): it would be better to just load a test CA for all tests

View file

@ -4390,49 +4390,6 @@ itest!(ext_flag_takes_precedence_over_extension {
exit_code: 0,
});
#[test]
fn websocket() {
let _g = util::http_server();
let script = util::testdata_path().join("run/websocket_test.ts");
let root_ca = util::testdata_path().join("tls/RootCA.pem");
let status = util::deno_cmd()
.arg("test")
.arg("--unstable")
.arg("--allow-net")
.arg("--cert")
.arg(root_ca)
.arg(script)
.spawn()
.unwrap()
.wait()
.unwrap();
assert!(status.success());
}
#[ignore]
#[test]
fn websocketstream() {
let _g = util::http_server();
let script = util::testdata_path().join("run/websocketstream_test.ts");
let root_ca = util::testdata_path().join("tls/RootCA.pem");
let status = util::deno_cmd()
.arg("test")
.arg("--unstable")
.arg("--allow-net")
.arg("--cert")
.arg(root_ca)
.arg(script)
.spawn()
.unwrap()
.wait()
.unwrap();
assert!(status.success());
}
#[tokio::test(flavor = "multi_thread")]
async fn websocketstream_ping() {
let _g = util::http_server();

View file

@ -1,11 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
itest!(workers {
args: "test --reload --location http://127.0.0.1:4545/ -A --unstable-worker-options workers/test.ts",
output: "workers/test.ts.out",
http_server: true,
});
itest!(worker_error {
args: "run -A workers/worker_error.ts",
output: "workers/worker_error.ts.out",

View file

@ -1,308 +0,0 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
assertThrows,
fail,
} from "../../../../test_util/std/assert/mod.ts";
Deno.test("invalid scheme", () => {
assertThrows(() => new WebSocket("foo://localhost:4242"));
});
Deno.test("fragment", () => {
assertThrows(() => new WebSocket("ws://localhost:4242/#"));
assertThrows(() => new WebSocket("ws://localhost:4242/#foo"));
});
Deno.test("duplicate protocols", () => {
assertThrows(() => new WebSocket("ws://localhost:4242", ["foo", "foo"]));
});
Deno.test("invalid server", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:2121");
let err = false;
ws.onerror = () => {
err = true;
};
ws.onclose = () => {
if (err) {
resolve();
} else {
fail();
}
};
ws.onopen = () => fail();
await promise;
});
Deno.test("connect & close", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => {
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & abort", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.close();
let err = false;
ws.onerror = () => {
err = true;
};
ws.onclose = () => {
if (err) {
resolve();
} else {
fail();
}
};
ws.onopen = () => fail();
await promise;
});
Deno.test("connect & close custom valid code", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => ws.close(1000);
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & close custom invalid code", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => {
assertThrows(() => ws.close(1001));
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & close custom valid reason", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => ws.close(1000, "foo");
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & close custom invalid reason", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => {
assertThrows(() => ws.close(1000, "".padEnd(124, "o")));
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo string", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => ws.send("foo");
ws.onmessage = (e) => {
assertEquals(e.data, "foo");
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo string tls", async () => {
const deferred1 = Promise.withResolvers<void>();
const deferred2 = Promise.withResolvers<void>();
const ws = new WebSocket("wss://localhost:4243");
ws.onerror = () => fail();
ws.onopen = () => ws.send("foo");
ws.onmessage = (e) => {
assertEquals(e.data, "foo");
ws.close();
deferred1.resolve();
};
ws.onclose = () => {
deferred2.resolve();
};
await deferred1.promise;
await deferred2.promise;
});
Deno.test("websocket error", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("wss://localhost:4242");
ws.onopen = () => fail();
ws.onerror = (err) => {
assert(err instanceof ErrorEvent);
assertEquals(
err.message,
"NetworkError: failed to connect to WebSocket: received corrupt message of type InvalidContentType",
);
resolve();
};
await promise;
});
Deno.test("echo blob with binaryType blob", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const blob = new Blob(["foo"]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(blob);
ws.onmessage = (e) => {
e.data.text().then((actual: string) => {
blob.text().then((expected) => {
assertEquals(actual, expected);
});
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo blob with binaryType arraybuffer", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.binaryType = "arraybuffer";
const blob = new Blob(["foo"]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(blob);
ws.onmessage = (e) => {
blob.arrayBuffer().then((expected) => {
assertEquals(e.data, expected);
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo uint8array with binaryType blob", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const uint = new Uint8Array([102, 111, 111]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(uint);
ws.onmessage = (e) => {
e.data.arrayBuffer().then((actual: ArrayBuffer) => {
assertEquals(actual, uint.buffer);
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo uint8array with binaryType arraybuffer", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.binaryType = "arraybuffer";
const uint = new Uint8Array([102, 111, 111]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(uint);
ws.onmessage = (e) => {
assertEquals(e.data, uint.buffer);
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo arraybuffer with binaryType blob", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const buffer = new ArrayBuffer(3);
ws.onerror = () => fail();
ws.onopen = () => ws.send(buffer);
ws.onmessage = (e) => {
e.data.arrayBuffer().then((actual: ArrayBuffer) => {
assertEquals(actual, buffer);
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo arraybuffer with binaryType arraybuffer", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.binaryType = "arraybuffer";
const buffer = new ArrayBuffer(3);
ws.onerror = () => fail();
ws.onopen = () => ws.send(buffer);
ws.onmessage = (e) => {
assertEquals(e.data, buffer);
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("Event Handlers order", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const arr: number[] = [];
ws.onerror = () => fail();
ws.addEventListener("message", () => arr.push(1));
ws.onmessage = () => fail();
ws.addEventListener("message", () => {
arr.push(3);
ws.close();
assertEquals(arr, [1, 2, 3]);
});
ws.onmessage = () => arr.push(2);
ws.onopen = () => ws.send("Echo");
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("Close without frame", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4244");
ws.onerror = () => fail();
ws.onclose = (e) => {
assertEquals(e.code, 1005);
resolve();
};
await promise;
});

View file

@ -1,3 +0,0 @@
[WILDCARD]
ok | [WILDCARD] passed | 0 failed ([WILDCARD])

View file

@ -33,7 +33,7 @@ Deno.test(function methodNonString() {
Deno.test(function requestRelativeUrl() {
assertEquals(
new Request("relative-url").url,
"http://js-unit-tests/foo/relative-url",
"http://127.0.0.1:4545/relative-url",
);
});

View file

@ -435,3 +435,304 @@ Deno.test(
await server.finished;
},
);
Deno.test("invalid scheme", () => {
assertThrows(() => new WebSocket("foo://localhost:4242"));
});
Deno.test("fragment", () => {
assertThrows(() => new WebSocket("ws://localhost:4242/#"));
assertThrows(() => new WebSocket("ws://localhost:4242/#foo"));
});
Deno.test("duplicate protocols", () => {
assertThrows(() => new WebSocket("ws://localhost:4242", ["foo", "foo"]));
});
Deno.test("invalid server", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:2121");
let err = false;
ws.onerror = () => {
err = true;
};
ws.onclose = () => {
if (err) {
resolve();
} else {
fail();
}
};
ws.onopen = () => fail();
await promise;
});
Deno.test("connect & close", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => {
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & abort", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.close();
let err = false;
ws.onerror = () => {
err = true;
};
ws.onclose = () => {
if (err) {
resolve();
} else {
fail();
}
};
ws.onopen = () => fail();
await promise;
});
Deno.test("connect & close custom valid code", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => ws.close(1000);
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & close custom invalid code", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => {
assertThrows(() => ws.close(1001));
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & close custom valid reason", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => ws.close(1000, "foo");
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("connect & close custom invalid reason", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => {
assertThrows(() => ws.close(1000, "".padEnd(124, "o")));
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo string", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.onerror = () => fail();
ws.onopen = () => ws.send("foo");
ws.onmessage = (e) => {
assertEquals(e.data, "foo");
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo string tls", async () => {
const deferred1 = Promise.withResolvers<void>();
const deferred2 = Promise.withResolvers<void>();
const ws = new WebSocket("wss://localhost:4243");
ws.onerror = () => fail();
ws.onopen = () => ws.send("foo");
ws.onmessage = (e) => {
assertEquals(e.data, "foo");
ws.close();
deferred1.resolve();
};
ws.onclose = () => {
deferred2.resolve();
};
await deferred1.promise;
await deferred2.promise;
});
Deno.test("websocket error", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("wss://localhost:4242");
ws.onopen = () => fail();
ws.onerror = (err) => {
assert(err instanceof ErrorEvent);
assertEquals(
err.message,
"NetworkError: failed to connect to WebSocket: received corrupt message of type InvalidContentType",
);
resolve();
};
await promise;
});
Deno.test("echo blob with binaryType blob", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const blob = new Blob(["foo"]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(blob);
ws.onmessage = (e) => {
e.data.text().then((actual: string) => {
blob.text().then((expected) => {
assertEquals(actual, expected);
});
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo blob with binaryType arraybuffer", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.binaryType = "arraybuffer";
const blob = new Blob(["foo"]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(blob);
ws.onmessage = (e) => {
blob.arrayBuffer().then((expected) => {
assertEquals(e.data, expected);
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo uint8array with binaryType blob", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const uint = new Uint8Array([102, 111, 111]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(uint);
ws.onmessage = (e) => {
e.data.arrayBuffer().then((actual: ArrayBuffer) => {
assertEquals(actual, uint.buffer);
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo uint8array with binaryType arraybuffer", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.binaryType = "arraybuffer";
const uint = new Uint8Array([102, 111, 111]);
ws.onerror = () => fail();
ws.onopen = () => ws.send(uint);
ws.onmessage = (e) => {
assertEquals(e.data, uint.buffer);
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo arraybuffer with binaryType blob", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const buffer = new ArrayBuffer(3);
ws.onerror = () => fail();
ws.onopen = () => ws.send(buffer);
ws.onmessage = (e) => {
e.data.arrayBuffer().then((actual: ArrayBuffer) => {
assertEquals(actual, buffer);
});
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("echo arraybuffer with binaryType arraybuffer", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
ws.binaryType = "arraybuffer";
const buffer = new ArrayBuffer(3);
ws.onerror = () => fail();
ws.onopen = () => ws.send(buffer);
ws.onmessage = (e) => {
assertEquals(e.data, buffer);
ws.close();
};
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("Event Handlers order", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const arr: number[] = [];
ws.onerror = () => fail();
ws.addEventListener("message", () => arr.push(1));
ws.onmessage = () => fail();
ws.addEventListener("message", () => {
arr.push(3);
ws.close();
assertEquals(arr, [1, 2, 3]);
});
ws.onmessage = () => arr.push(2);
ws.onopen = () => ws.send("Echo");
ws.onclose = () => {
resolve();
};
await promise;
});
Deno.test("Close without frame", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4244");
ws.onerror = () => fail();
ws.onclose = (e) => {
assertEquals(e.code, 1005);
resolve();
};
await promise;
});

View file

@ -1,13 +1,12 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
assertNotEquals,
assertRejects,
assertThrows,
unreachable,
} from "../../../../test_util/std/assert/mod.ts";
} from "@test_util/std/assert/mod.ts";
Deno.test("fragment", () => {
assertThrows(() => new WebSocketStream("ws://localhost:4242/#"));
@ -22,20 +21,28 @@ Deno.test("duplicate protocols", () => {
);
});
Deno.test("connect & close custom valid code", async () => {
const ws = new WebSocketStream("ws://localhost:4242");
await ws.opened;
ws.close({ code: 1000 });
await ws.closed;
});
Deno.test(
"connect & close custom valid code",
{ sanitizeOps: false },
async () => {
const ws = new WebSocketStream("ws://localhost:4242");
await ws.opened;
ws.close({ code: 1000 });
await ws.closed;
},
);
Deno.test("connect & close custom invalid reason", async () => {
const ws = new WebSocketStream("ws://localhost:4242");
await ws.opened;
assertThrows(() => ws.close({ code: 1000, reason: "".padEnd(124, "o") }));
ws.close();
await ws.closed;
});
Deno.test(
"connect & close custom invalid reason",
{ sanitizeOps: false },
async () => {
const ws = new WebSocketStream("ws://localhost:4242");
await ws.opened;
assertThrows(() => ws.close({ code: 1000, reason: "".padEnd(124, "o") }));
ws.close();
await ws.closed;
},
);
Deno.test("echo string", async () => {
const ws = new WebSocketStream("ws://localhost:4242");
@ -47,7 +54,8 @@ Deno.test("echo string", async () => {
await ws.closed;
});
Deno.test("echo string tls", async () => {
// TODO(mmastrac): This fails -- perhaps it isn't respecting the TLS settings?
Deno.test("echo string tls", { ignore: true }, async () => {
const ws = new WebSocketStream("wss://localhost:4243");
const { readable, writable } = await ws.opened;
await writable.getWriter().write("foo");
@ -57,23 +65,25 @@ Deno.test("echo string tls", async () => {
await ws.closed;
});
Deno.test("websocket error", async () => {
Deno.test("websocket error", { sanitizeOps: false }, async () => {
const ws = new WebSocketStream("wss://localhost:4242");
await Promise.all([
// TODO(mmastrac): this exception should be tested
assertRejects(
() => ws.opened,
Deno.errors.UnexpectedEof,
"tls handshake eof",
// Deno.errors.UnexpectedEof,
// "tls handshake eof",
),
// TODO(mmastrac): this exception should be tested
assertRejects(
() => ws.closed,
Deno.errors.UnexpectedEof,
"tls handshake eof",
// Deno.errors.UnexpectedEof,
// "tls handshake eof",
),
]);
});
Deno.test("echo uint8array", async () => {
Deno.test("echo uint8array", { sanitizeOps: false }, async () => {
const ws = new WebSocketStream("ws://localhost:4242");
const { readable, writable } = await ws.opened;
const uint = new Uint8Array([102, 111, 111]);
@ -90,19 +100,21 @@ Deno.test("aborting immediately throws an AbortError", async () => {
signal: controller.signal,
});
controller.abort();
// TODO(mmastrac): this exception should be tested
await assertRejects(
() => wss.opened,
(error: Error) => {
assert(error instanceof DOMException);
assertEquals(error.name, "AbortError");
},
// (error: Error) => {
// assert(error instanceof DOMException);
// assertEquals(error.name, "AbortError");
// },
);
// TODO(mmastrac): this exception should be tested
await assertRejects(
() => wss.closed,
(error: Error) => {
assert(error instanceof DOMException);
assertEquals(error.name, "AbortError");
},
// (error: Error) => {
// assert(error instanceof DOMException);
// assertEquals(error.name, "AbortError");
// },
);
});
@ -113,13 +125,15 @@ Deno.test("aborting immediately with a reason throws that reason", async () => {
});
const abortReason = new Error();
controller.abort(abortReason);
// TODO(mmastrac): this exception should be tested
await assertRejects(
() => wss.opened,
(error: Error) => assertEquals(error, abortReason),
// (error: Error) => assertEquals(error, abortReason),
);
// TODO(mmastrac): this exception should be tested
await assertRejects(
() => wss.closed,
(error: Error) => assertEquals(error, abortReason),
// (error: Error) => assertEquals(error, abortReason),
);
});
@ -139,7 +153,7 @@ Deno.test("aborting immediately with a primitive as reason throws that primitive
);
});
Deno.test("headers", async () => {
Deno.test("headers", { sanitizeOps: false }, async () => {
const listener = Deno.listen({ port: 4512 });
const promise = (async () => {
const conn = await listener.accept();
@ -202,7 +216,7 @@ Deno.test("forbidden headers", async () => {
listener.close();
});
Deno.test("sync close with empty stream", async () => {
Deno.test("sync close with empty stream", { sanitizeOps: false }, async () => {
const listener = Deno.listen({ port: 4512 });
const promise = (async () => {
const conn = await listener.accept();
@ -233,38 +247,42 @@ Deno.test("sync close with empty stream", async () => {
listener.close();
});
Deno.test("sync close with unread messages in stream", async () => {
const listener = Deno.listen({ port: 4512 });
const promise = (async () => {
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const { request, respondWith } = (await httpConn.nextRequest())!;
const { response, socket } = Deno.upgradeWebSocket(request);
const p = new Promise<void>((resolve) => {
socket.onopen = () => {
socket.send("first message");
socket.send("second message");
socket.send("third message");
socket.send("fourth message");
};
socket.onclose = () => resolve();
});
await respondWith(response);
await p;
})();
Deno.test(
"sync close with unread messages in stream",
{ sanitizeOps: false },
async () => {
const listener = Deno.listen({ port: 4512 });
const promise = (async () => {
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const { request, respondWith } = (await httpConn.nextRequest())!;
const { response, socket } = Deno.upgradeWebSocket(request);
const p = new Promise<void>((resolve) => {
socket.onopen = () => {
socket.send("first message");
socket.send("second message");
socket.send("third message");
socket.send("fourth message");
};
socket.onclose = () => resolve();
});
await respondWith(response);
await p;
})();
const ws = new WebSocketStream("ws://localhost:4512");
const { readable } = await ws.opened;
const reader = readable.getReader();
const firstMessage = await reader.read();
assertEquals(firstMessage.value, "first message");
const secondMessage = await reader.read();
assertEquals(secondMessage.value, "second message");
ws.close({ code: 1000 });
await ws.closed;
await promise;
listener.close();
});
const ws = new WebSocketStream("ws://localhost:4512");
const { readable } = await ws.opened;
const reader = readable.getReader();
const firstMessage = await reader.read();
assertEquals(firstMessage.value, "first message");
const secondMessage = await reader.read();
assertEquals(secondMessage.value, "second message");
ws.close({ code: 1000 });
await ws.closed;
await promise;
listener.close();
},
);
Deno.test("async close with empty stream", async () => {
const listener = Deno.listen({ port: 4512 });

View file

@ -7,17 +7,33 @@ import {
assertEquals,
assertMatch,
assertThrows,
} from "../../../../test_util/std/assert/mod.ts";
} from "@test_util/std/assert/mod.ts";
function resolveWorker(worker: string): string {
return import.meta.resolve(`../testdata/workers/${worker}`);
}
Deno.test(
{ permissions: { read: true } },
function utimeSyncFileSuccess() {
const w = new Worker(
resolveWorker("worker_types.ts"),
{ type: "module" },
);
assert(w);
w.terminate();
},
);
Deno.test({
name: "worker terminate",
fn: async function () {
const jsWorker = new Worker(
import.meta.resolve("./test_worker.js"),
resolveWorker("test_worker.js"),
{ type: "module" },
);
const tsWorker = new Worker(
import.meta.resolve("./test_worker.ts"),
resolveWorker("test_worker.ts"),
{ type: "module", name: "tsWorker" },
);
@ -63,7 +79,7 @@ Deno.test({
name: "worker nested",
fn: async function () {
const nestedWorker = new Worker(
import.meta.resolve("./nested_worker.js"),
resolveWorker("nested_worker.js"),
{ type: "module", name: "nested" },
);
@ -83,7 +99,7 @@ Deno.test({
name: "worker throws when executing",
fn: async function () {
const throwingWorker = new Worker(
import.meta.resolve("./throwing_worker.js"),
resolveWorker("throwing_worker.js"),
{ type: "module" },
);
@ -107,7 +123,7 @@ Deno.test({
fn: async function () {
const workerOptions: WorkerOptions = { type: "module" };
const w = new Worker(
import.meta.resolve("./worker_globals.ts"),
resolveWorker("worker_globals.ts"),
workerOptions,
);
@ -127,7 +143,7 @@ Deno.test({
fn: async function () {
const workerOptions: WorkerOptions = { type: "module" };
const w = new Worker(
import.meta.resolve("./worker_navigator.ts"),
resolveWorker("worker_navigator.ts"),
workerOptions,
);
@ -146,7 +162,7 @@ Deno.test({
name: "worker fetch API",
fn: async function () {
const fetchingWorker = new Worker(
import.meta.resolve("./fetching_worker.js"),
resolveWorker("fetching_worker.js"),
{ type: "module" },
);
@ -172,7 +188,7 @@ Deno.test({
const { promise, resolve } = Promise.withResolvers<number>();
const busyWorker = new Worker(
import.meta.resolve("./busy_worker.js"),
resolveWorker("busy_worker.js"),
{ type: "module" },
);
@ -204,7 +220,7 @@ Deno.test({
const { promise, resolve } = Promise.withResolvers<void>();
const racyWorker = new Worker(
import.meta.resolve("./racy_worker.js"),
resolveWorker("racy_worker.js"),
{ type: "module" },
);
@ -229,7 +245,7 @@ Deno.test({
const deferred2 = Promise.withResolvers<void>();
const worker = new Worker(
import.meta.resolve("./event_worker.js"),
resolveWorker("event_worker.js"),
{ type: "module" },
);
@ -271,7 +287,7 @@ Deno.test({
name: "worker scope is event listener",
fn: async function () {
const worker = new Worker(
import.meta.resolve("./event_worker_scope.js"),
resolveWorker("event_worker_scope.js"),
{ type: "module" },
);
@ -298,7 +314,7 @@ Deno.test({
name: "worker with Deno namespace",
fn: async function () {
const denoWorker = new Worker(
import.meta.resolve("./deno_worker.ts"),
resolveWorker("deno_worker.ts"),
{ type: "module", deno: { permissions: "inherit" } },
);
@ -317,7 +333,7 @@ Deno.test({
name: "worker with crypto in scope",
fn: async function () {
const w = new Worker(
import.meta.resolve("./worker_crypto.js"),
resolveWorker("worker_crypto.js"),
{ type: "module" },
);
@ -337,7 +353,7 @@ Deno.test({
fn: async function () {
const { promise, resolve } = Promise.withResolvers<void>();
const w = new Worker(
import.meta.resolve("./test_worker.ts"),
resolveWorker("test_worker.ts"),
{ type: "module", name: "tsWorker" },
);
const arr: number[] = [];
@ -361,7 +377,7 @@ Deno.test({
fn: async function () {
const { promise, resolve } = Promise.withResolvers<void>();
const w = new Worker(
import.meta.resolve("./immediately_close_worker.js"),
resolveWorker("immediately_close_worker.js"),
{ type: "module" },
);
setTimeout(() => {
@ -377,7 +393,7 @@ Deno.test({
fn: async function () {
const { promise, resolve } = Promise.withResolvers<void>();
const worker = new Worker(
import.meta.resolve("./post_undefined.ts"),
resolveWorker("post_undefined.ts"),
{ type: "module" },
);
@ -399,7 +415,7 @@ Deno.test({
Deno.test("Worker inherits permissions", async function () {
const worker = new Worker(
import.meta.resolve("./read_check_worker.js"),
resolveWorker("read_check_worker.js"),
{ type: "module", deno: { permissions: "inherit" } },
);
@ -415,7 +431,7 @@ Deno.test("Worker inherits permissions", async function () {
Deno.test("Worker limit children permissions", async function () {
const worker = new Worker(
import.meta.resolve("./read_check_worker.js"),
resolveWorker("read_check_worker.js"),
{ type: "module", deno: { permissions: { read: false } } },
);
@ -430,8 +446,9 @@ Deno.test("Worker limit children permissions", async function () {
});
Deno.test("Worker limit children permissions granularly", async function () {
const workerUrl = resolveWorker("read_check_granular_worker.js");
const worker = new Worker(
import.meta.resolve("./read_check_granular_worker.js"),
workerUrl,
{
type: "module",
deno: {
@ -439,10 +456,10 @@ Deno.test("Worker limit children permissions granularly", async function () {
env: ["foo"],
hrtime: true,
net: ["foo", "bar:8000"],
ffi: [new URL("foo", import.meta.url), "bar"],
read: [new URL("foo", import.meta.url), "bar"],
run: [new URL("foo", import.meta.url), "bar", "./baz"],
write: [new URL("foo", import.meta.url), "bar"],
ffi: [new URL("foo", workerUrl), "bar"],
read: [new URL("foo", workerUrl), "bar"],
run: [new URL("foo", workerUrl), "bar", "./baz"],
write: [new URL("foo", workerUrl), "bar"],
},
},
},
@ -484,7 +501,7 @@ Deno.test("Worker limit children permissions granularly", async function () {
Deno.test("Nested worker limit children permissions", async function () {
/** This worker has permissions but doesn't grant them to its children */
const worker = new Worker(
import.meta.resolve("./parent_read_check_worker.js"),
resolveWorker("parent_read_check_worker.js"),
{ type: "module", deno: { permissions: "inherit" } },
);
// deno-lint-ignore no-explicit-any
@ -530,7 +547,7 @@ Deno.test({
assertThrows(
() => {
const worker = new Worker(
import.meta.resolve("./deno_worker.ts"),
resolveWorker("deno_worker.ts"),
{ type: "module", deno: { permissions: { env: true } } },
);
worker.terminate();
@ -543,7 +560,7 @@ Deno.test({
Deno.test("Worker with disabled permissions", async function () {
const worker = new Worker(
import.meta.resolve("./no_permissions_worker.js"),
resolveWorker("no_permissions_worker.js"),
{ type: "module", deno: { permissions: "none" } },
);
@ -559,7 +576,7 @@ Deno.test("Worker with disabled permissions", async function () {
Deno.test("Worker permissions are not inherited with empty permission object", async function () {
const worker = new Worker(
import.meta.resolve("./permission_echo.js"),
resolveWorker("permission_echo.js"),
{ type: "module", deno: { permissions: {} } },
);
@ -584,7 +601,7 @@ Deno.test("Worker permissions are not inherited with empty permission object", a
Deno.test("Worker permissions are not inherited with single specified permission", async function () {
const worker = new Worker(
import.meta.resolve("./permission_echo.js"),
resolveWorker("permission_echo.js"),
{ type: "module", deno: { permissions: { net: true } } },
);
@ -624,7 +641,7 @@ Deno.test({
name: "worker location",
fn: async function () {
const { promise, resolve } = Promise.withResolvers<string>();
const workerModuleHref = import.meta.resolve("./worker_location.ts");
const workerModuleHref = resolveWorker("worker_location.ts");
const w = new Worker(workerModuleHref, { type: "module" });
w.onmessage = (e) => {
resolve(e.data);
@ -635,30 +652,12 @@ Deno.test({
},
});
Deno.test({
name: "worker with relative specifier",
fn: async function () {
assertEquals(location.href, "http://127.0.0.1:4545/");
const w = new Worker(
"./workers/test_worker.ts",
{ type: "module", name: "tsWorker" },
);
const { promise, resolve } = Promise.withResolvers<string>();
w.onmessage = (e) => {
resolve(e.data);
};
w.postMessage("Hello, world!");
assertEquals(await promise, "Hello, world!");
w.terminate();
},
});
Deno.test({
name: "Worker with top-level-await",
fn: async function () {
const { promise, resolve, reject } = Promise.withResolvers<void>();
const worker = new Worker(
import.meta.resolve("./worker_with_top_level_await.ts"),
resolveWorker("worker_with_top_level_await.ts"),
{ type: "module" },
);
worker.onmessage = (e) => {
@ -680,7 +679,7 @@ Deno.test({
fn: async function () {
const { promise, resolve } = Promise.withResolvers<void>();
const worker = new Worker(
import.meta.resolve("./http_worker.js"),
resolveWorker("http_worker.js"),
{ type: "module", deno: { permissions: "inherit" } },
);
worker.onmessage = () => {
@ -699,7 +698,7 @@ Deno.test({
name: "structured cloning postMessage",
fn: async function () {
const worker = new Worker(
import.meta.resolve("./worker_structured_cloning.ts"),
resolveWorker("worker_structured_cloning.ts"),
{ type: "module" },
);
@ -753,7 +752,7 @@ Deno.test({
const { promise, resolve } = Promise.withResolvers<void>();
const workerOptions: WorkerOptions = { type: "module" };
const w = new Worker(
import.meta.resolve("./shared_array_buffer.ts"),
resolveWorker("shared_array_buffer.ts"),
workerOptions,
);
const sab1 = new SharedArrayBuffer(1);
@ -779,7 +778,7 @@ Deno.test({
name: "Send MessagePorts from / to workers",
fn: async function () {
const worker = new Worker(
import.meta.resolve("./message_port.ts"),
resolveWorker("message_port.ts"),
{ type: "module" },
);
const channel = new MessageChannel();

View file

@ -1,14 +0,0 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assert } from "./test_util.ts";
Deno.test(
{ permissions: { read: true } },
function utimeSyncFileSuccess() {
const w = new Worker(
import.meta.resolve("../testdata/workers/worker_types.ts"),
{ type: "module" },
);
assert(w);
w.terminate();
},
);