1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-03 04:48:52 -05:00
denoland-deno/tests/unit/quic_test.ts
snek 65b647909d
feat(unstable): Implement QUIC (#21942)
Implements a QUIC interface, loosely based on the WebTransport API (a
future change could add the WebTransport API, built on top of this one).

[quinn](https://docs.rs/quinn/latest/quinn/) is used for the underlying
QUIC implementation, for a few reasons:
- A cloneable "handle" api which fits quite nicely into deno resources.
- Good collaboration with the rust ecosystem, especially rustls.
- I like it.

<!--
Before submitting a PR, please read https://deno.com/manual/contributing

1. Give the PR a descriptive title.

  Examples of good title:
    - fix(std/http): Fix race condition in server
    - docs(console): Update docstrings
    - feat(doc): Handle nested reexports

  Examples of bad title:
    - fix #7123
    - update docs
    - fix bugs

2. Ensure there is a related issue and it is referenced in the PR text.
3. Ensure there are tests that cover the changes.
4. Ensure `cargo test` passes.
5. Ensure `./tools/format.js` passes without changing files.
6. Ensure `./tools/lint.js` passes.
7. Open as a draft PR if your work is still in progress. The CI won't
run
   all steps, but you can add '[ci]' to a commit message to force it to.
8. If you would like to run the benchmarks on the CI, add the 'ci-bench'
label.
-->
2024-12-20 13:48:48 +01:00

172 lines
4.4 KiB
TypeScript

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "./test_util.ts";
const cert = Deno.readTextFileSync("tests/testdata/tls/localhost.crt");
const key = Deno.readTextFileSync("tests/testdata/tls/localhost.key");
const caCerts = [Deno.readTextFileSync("tests/testdata/tls/RootCA.pem")];
async function pair(opt?: Deno.QuicTransportOptions): Promise<
[Deno.QuicConn, Deno.QuicConn, Deno.QuicListener]
> {
const listener = await Deno.listenQuic({
hostname: "localhost",
port: 0,
cert,
key,
alpnProtocols: ["deno-test"],
...opt,
});
const [server, client] = await Promise.all([
listener.accept(),
Deno.connectQuic({
hostname: "localhost",
port: listener.addr.port,
caCerts,
alpnProtocols: ["deno-test"],
...opt,
}),
]);
assertEquals(server.protocol, "deno-test");
assertEquals(client.protocol, "deno-test");
assertEquals(client.remoteAddr, listener.addr);
return [server, client, listener];
}
Deno.test("bidirectional stream", async () => {
const [server, client, listener] = await pair();
const encoded = (new TextEncoder()).encode("hi!");
{
const bi = await server.createBidirectionalStream({ sendOrder: 42 });
assertEquals(bi.writable.sendOrder, 42);
bi.writable.sendOrder = 0;
assertEquals(bi.writable.sendOrder, 0);
await bi.writable.getWriter().write(encoded);
}
{
const { value: bi } = await client.incomingBidirectionalStreams
.getReader()
.read();
const { value: data } = await bi!.readable.getReader().read();
assertEquals(data, encoded);
}
listener.close({ closeCode: 0, reason: "" });
client.close({ closeCode: 0, reason: "" });
});
Deno.test("unidirectional stream", async () => {
const [server, client, listener] = await pair();
const encoded = (new TextEncoder()).encode("hi!");
{
const uni = await server.createUnidirectionalStream({ sendOrder: 42 });
assertEquals(uni.sendOrder, 42);
uni.sendOrder = 0;
assertEquals(uni.sendOrder, 0);
await uni.getWriter().write(encoded);
}
{
const { value: uni } = await client.incomingUnidirectionalStreams
.getReader()
.read();
const { value: data } = await uni!.getReader().read();
assertEquals(data, encoded);
}
listener.close({ closeCode: 0, reason: "" });
client.close({ closeCode: 0, reason: "" });
});
Deno.test("datagrams", async () => {
const [server, client, listener] = await pair();
const encoded = (new TextEncoder()).encode("hi!");
await server.sendDatagram(encoded);
const data = await client.readDatagram();
assertEquals(data, encoded);
listener.close({ closeCode: 0, reason: "" });
client.close({ closeCode: 0, reason: "" });
});
Deno.test("closing", async () => {
const [server, client, listener] = await pair();
server.close({ closeCode: 42, reason: "hi!" });
assertEquals(await client.closed, { closeCode: 42, reason: "hi!" });
listener.close({ closeCode: 0, reason: "" });
});
Deno.test("max concurrent streams", async () => {
const [server, client, listener] = await pair({
maxConcurrentBidirectionalStreams: 1,
maxConcurrentUnidirectionalStreams: 1,
});
{
await server.createBidirectionalStream();
await server.createBidirectionalStream()
.then(() => {
throw new Error("expected failure");
}, () => {
// success!
});
}
{
await server.createUnidirectionalStream();
await server.createUnidirectionalStream()
.then(() => {
throw new Error("expected failure");
}, () => {
// success!
});
}
listener.close({ closeCode: 0, reason: "" });
server.close({ closeCode: 0, reason: "" });
client.close({ closeCode: 0, reason: "" });
});
Deno.test("incoming", async () => {
const listener = await Deno.listenQuic({
hostname: "localhost",
port: 0,
cert,
key,
alpnProtocols: ["deno-test"],
});
const connect = () =>
Deno.connectQuic({
hostname: "localhost",
port: listener.addr.port,
caCerts,
alpnProtocols: ["deno-test"],
});
const c1p = connect();
const i1 = await listener.incoming();
const server = await i1.accept();
const client = await c1p;
assertEquals(server.protocol, "deno-test");
assertEquals(client.protocol, "deno-test");
assertEquals(client.remoteAddr, listener.addr);
listener.close({ closeCode: 0, reason: "" });
client.close({ closeCode: 0, reason: "" });
});