1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00
denoland-deno/cli/tests/unit/net_test.ts
Bartek Iwańczuk 6984b63f2f
refactor: rewrite ops to use ResourceTable2 (#8512)
This commit migrates all ops to use new resource table
and "AsyncRefCell".

Old implementation of resource table was completely 
removed and all code referencing it was updated to use
new system.
2020-12-16 17:14:12 +01:00

628 lines
18 KiB
TypeScript

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
assertNotEquals,
assertThrows,
assertThrowsAsync,
deferred,
unitTest,
} from "./test_util.ts";
unitTest({ perms: { net: true } }, function netTcpListenClose(): void {
const listener = Deno.listen({ hostname: "127.0.0.1", port: 3500 });
assert(listener.addr.transport === "tcp");
assertEquals(listener.addr.hostname, "127.0.0.1");
assertEquals(listener.addr.port, 3500);
assertNotEquals(listener.rid, 0);
listener.close();
});
unitTest(
{
perms: { net: true },
},
function netUdpListenClose(): void {
const socket = Deno.listenDatagram({
hostname: "127.0.0.1",
port: 3500,
transport: "udp",
});
assert(socket.addr.transport === "udp");
assertEquals(socket.addr.hostname, "127.0.0.1");
assertEquals(socket.addr.port, 3500);
socket.close();
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
function netUnixListenClose(): void {
const filePath = Deno.makeTempFileSync();
const socket = Deno.listen({
path: filePath,
transport: "unix",
});
assert(socket.addr.transport === "unix");
assertEquals(socket.addr.path, filePath);
socket.close();
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
function netUnixPacketListenClose(): void {
const filePath = Deno.makeTempFileSync();
const socket = Deno.listenDatagram({
path: filePath,
transport: "unixpacket",
});
assert(socket.addr.transport === "unixpacket");
assertEquals(socket.addr.path, filePath);
socket.close();
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true } },
function netUnixListenWritePermission(): void {
assertThrows(() => {
const filePath = Deno.makeTempFileSync();
const socket = Deno.listen({
path: filePath,
transport: "unix",
});
assert(socket.addr.transport === "unix");
assertEquals(socket.addr.path, filePath);
socket.close();
}, Deno.errors.PermissionDenied);
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true } },
function netUnixPacketListenWritePermission(): void {
assertThrows(() => {
const filePath = Deno.makeTempFileSync();
const socket = Deno.listenDatagram({
path: filePath,
transport: "unixpacket",
});
assert(socket.addr.transport === "unixpacket");
assertEquals(socket.addr.path, filePath);
socket.close();
}, Deno.errors.PermissionDenied);
},
);
unitTest(
{
perms: { net: true },
},
async function netTcpCloseWhileAccept(): Promise<void> {
const listener = Deno.listen({ port: 4501 });
const p = listener.accept();
listener.close();
await assertThrowsAsync(
async (): Promise<void> => {
await p;
},
Deno.errors.BadResource,
"Listener has been closed",
);
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
async function netUnixCloseWhileAccept(): Promise<void> {
const filePath = await Deno.makeTempFile();
const listener = Deno.listen({
path: filePath,
transport: "unix",
});
const p = listener.accept();
listener.close();
await assertThrowsAsync(
async (): Promise<void> => {
await p;
},
Deno.errors.BadResource,
"Listener has been closed",
);
},
);
unitTest(
{ perms: { net: true } },
async function netTcpConcurrentAccept(): Promise<void> {
const listener = Deno.listen({ port: 4502 });
let acceptErrCount = 0;
const checkErr = (e: Error): void => {
if (e.message === "Listener has been closed") {
assertEquals(acceptErrCount, 1);
} else if (e.message === "Another accept task is ongoing") {
acceptErrCount++;
} else {
throw new Error("Unexpected error message");
}
};
const p = listener.accept().catch(checkErr);
const p1 = listener.accept().catch(checkErr);
await Promise.race([p, p1]);
listener.close();
await Promise.all([p, p1]);
assertEquals(acceptErrCount, 1);
},
);
// TODO(jsouto): Enable when tokio updates mio to v0.7!
unitTest(
{ ignore: true, perms: { read: true, write: true } },
async function netUnixConcurrentAccept(): Promise<void> {
const filePath = await Deno.makeTempFile();
const listener = Deno.listen({ transport: "unix", path: filePath });
let acceptErrCount = 0;
const checkErr = (e: Error): void => {
if (e.message === "Listener has been closed") {
assertEquals(acceptErrCount, 1);
} else if (e.message === "Another accept task is ongoing") {
acceptErrCount++;
} else {
throw new Error("Unexpected error message");
}
};
const p = listener.accept().catch(checkErr);
const p1 = listener.accept().catch(checkErr);
await Promise.race([p, p1]);
listener.close();
await [p, p1];
assertEquals(acceptErrCount, 1);
},
);
unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise<
void
> {
const listener = Deno.listen({ port: 3500 });
listener.accept().then(
async (conn): Promise<void> => {
assert(conn.remoteAddr != null);
assert(conn.localAddr.transport === "tcp");
assertEquals(conn.localAddr.hostname, "127.0.0.1");
assertEquals(conn.localAddr.port, 3500);
await conn.write(new Uint8Array([1, 2, 3]));
conn.close();
},
);
const conn = await Deno.connect({ hostname: "127.0.0.1", port: 3500 });
assert(conn.remoteAddr.transport === "tcp");
assertEquals(conn.remoteAddr.hostname, "127.0.0.1");
assertEquals(conn.remoteAddr.port, 3500);
assert(conn.localAddr != null);
const buf = new Uint8Array(1024);
const readResult = await conn.read(buf);
assertEquals(3, readResult);
assertEquals(1, buf[0]);
assertEquals(2, buf[1]);
assertEquals(3, buf[2]);
assert(conn.rid > 0);
assert(readResult !== null);
const readResult2 = await conn.read(buf);
assertEquals(readResult2, null);
listener.close();
conn.close();
});
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
async function netUnixDialListen(): Promise<void> {
const filePath = await Deno.makeTempFile();
const listener = Deno.listen({ path: filePath, transport: "unix" });
listener.accept().then(
async (conn): Promise<void> => {
assert(conn.remoteAddr != null);
assert(conn.localAddr.transport === "unix");
assertEquals(conn.localAddr.path, filePath);
await conn.write(new Uint8Array([1, 2, 3]));
conn.close();
},
);
const conn = await Deno.connect({ path: filePath, transport: "unix" });
assert(conn.remoteAddr.transport === "unix");
assertEquals(conn.remoteAddr.path, filePath);
assert(conn.remoteAddr != null);
const buf = new Uint8Array(1024);
const readResult = await conn.read(buf);
assertEquals(3, readResult);
assertEquals(1, buf[0]);
assertEquals(2, buf[1]);
assertEquals(3, buf[2]);
assert(conn.rid > 0);
assert(readResult !== null);
const readResult2 = await conn.read(buf);
assertEquals(readResult2, null);
listener.close();
conn.close();
},
);
unitTest(
{ perms: { net: true } },
async function netUdpSendReceive(): Promise<void> {
const alice = Deno.listenDatagram({ port: 3500, transport: "udp" });
assert(alice.addr.transport === "udp");
assertEquals(alice.addr.port, 3500);
assertEquals(alice.addr.hostname, "127.0.0.1");
const bob = Deno.listenDatagram({ port: 4501, transport: "udp" });
assert(bob.addr.transport === "udp");
assertEquals(bob.addr.port, 4501);
assertEquals(bob.addr.hostname, "127.0.0.1");
const sent = new Uint8Array([1, 2, 3]);
const byteLength = await alice.send(sent, bob.addr);
assertEquals(byteLength, 3);
const [recvd, remote] = await bob.receive();
assert(remote.transport === "udp");
assertEquals(remote.port, 3500);
assertEquals(recvd.length, 3);
assertEquals(1, recvd[0]);
assertEquals(2, recvd[1]);
assertEquals(3, recvd[2]);
alice.close();
bob.close();
},
);
unitTest(
{ perms: { net: true } },
async function netUdpConcurrentSendReceive(): Promise<void> {
const socket = Deno.listenDatagram({ port: 3500, transport: "udp" });
assert(socket.addr.transport === "udp");
assertEquals(socket.addr.port, 3500);
assertEquals(socket.addr.hostname, "127.0.0.1");
const recvPromise = socket.receive();
const sendBuf = new Uint8Array([1, 2, 3]);
const sendLen = await socket.send(sendBuf, socket.addr);
assertEquals(sendLen, 3);
const [recvBuf, recvAddr] = await recvPromise;
assertEquals(recvBuf.length, 3);
assertEquals(1, recvBuf[0]);
assertEquals(2, recvBuf[1]);
assertEquals(3, recvBuf[2]);
socket.close();
},
);
unitTest(
{ perms: { net: true } },
async function netUdpBorrowMutError(): Promise<void> {
const socket = Deno.listenDatagram({
port: 4501,
transport: "udp",
});
// Panic happened on second send: BorrowMutError
const a = socket.send(new Uint8Array(), socket.addr);
const b = socket.send(new Uint8Array(), socket.addr);
await Promise.all([a, b]);
socket.close();
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
async function netUnixPacketSendReceive(): Promise<void> {
const filePath = await Deno.makeTempFile();
const alice = Deno.listenDatagram({
path: filePath,
transport: "unixpacket",
});
assert(alice.addr.transport === "unixpacket");
assertEquals(alice.addr.path, filePath);
const bob = Deno.listenDatagram({
path: filePath,
transport: "unixpacket",
});
assert(bob.addr.transport === "unixpacket");
assertEquals(bob.addr.path, filePath);
const sent = new Uint8Array([1, 2, 3]);
const byteLength = await alice.send(sent, bob.addr);
assertEquals(byteLength, 3);
const [recvd, remote] = await bob.receive();
assert(remote.transport === "unixpacket");
assertEquals(remote.path, filePath);
assertEquals(recvd.length, 3);
assertEquals(1, recvd[0]);
assertEquals(2, recvd[1]);
assertEquals(3, recvd[2]);
alice.close();
bob.close();
},
);
// TODO(piscisaureus): Enable after Tokio v0.3/v1.0 upgrade.
unitTest(
{ ignore: true, perms: { read: true, write: true } },
async function netUnixPacketConcurrentSendReceive(): Promise<void> {
const filePath = await Deno.makeTempFile();
const socket = Deno.listenDatagram({
path: filePath,
transport: "unixpacket",
});
assert(socket.addr.transport === "unixpacket");
assertEquals(socket.addr.path, filePath);
const recvPromise = socket.receive();
const sendBuf = new Uint8Array([1, 2, 3]);
const sendLen = await socket.send(sendBuf, socket.addr);
assertEquals(sendLen, 3);
const [recvBuf, recvAddr] = await recvPromise;
assertEquals(recvBuf.length, 3);
assertEquals(1, recvBuf[0]);
assertEquals(2, recvBuf[1]);
assertEquals(3, recvBuf[2]);
socket.close();
},
);
unitTest(
{ perms: { net: true } },
async function netTcpListenIteratorBreakClosesResource(): Promise<void> {
const promise = deferred();
async function iterate(listener: Deno.Listener): Promise<void> {
let i = 0;
for await (const conn of listener) {
conn.close();
i++;
if (i > 1) {
break;
}
}
promise.resolve();
}
const addr = { hostname: "127.0.0.1", port: 8888 };
const listener = Deno.listen(addr);
iterate(listener);
await new Promise<void>((resolve) => {
setTimeout(resolve, 100);
});
const conn1 = await Deno.connect(addr);
conn1.close();
const conn2 = await Deno.connect(addr);
conn2.close();
await promise;
},
);
unitTest(
{ perms: { net: true } },
async function netTcpListenCloseWhileIterating(): Promise<void> {
const listener = Deno.listen({ port: 8000 });
const nextWhileClosing = listener[Symbol.asyncIterator]().next();
listener.close();
assertEquals(await nextWhileClosing, { value: undefined, done: true });
const nextAfterClosing = listener[Symbol.asyncIterator]().next();
assertEquals(await nextAfterClosing, { value: undefined, done: true });
},
);
unitTest(
{ perms: { net: true } },
async function netUdpListenCloseWhileIterating(): Promise<void> {
const socket = Deno.listenDatagram({ port: 8000, transport: "udp" });
const nextWhileClosing = socket[Symbol.asyncIterator]().next();
socket.close();
assertEquals(await nextWhileClosing, { value: undefined, done: true });
const nextAfterClosing = socket[Symbol.asyncIterator]().next();
assertEquals(await nextAfterClosing, { value: undefined, done: true });
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
async function netUnixListenCloseWhileIterating(): Promise<void> {
const filePath = Deno.makeTempFileSync();
const socket = Deno.listen({ path: filePath, transport: "unix" });
const nextWhileClosing = socket[Symbol.asyncIterator]().next();
socket.close();
assertEquals(await nextWhileClosing, { value: undefined, done: true });
const nextAfterClosing = socket[Symbol.asyncIterator]().next();
assertEquals(await nextAfterClosing, { value: undefined, done: true });
},
);
unitTest(
{ ignore: Deno.build.os === "windows", perms: { read: true, write: true } },
async function netUnixPacketListenCloseWhileIterating(): Promise<void> {
const filePath = Deno.makeTempFileSync();
const socket = Deno.listenDatagram({
path: filePath,
transport: "unixpacket",
});
const nextWhileClosing = socket[Symbol.asyncIterator]().next();
socket.close();
assertEquals(await nextWhileClosing, { value: undefined, done: true });
const nextAfterClosing = socket[Symbol.asyncIterator]().next();
assertEquals(await nextAfterClosing, { value: undefined, done: true });
},
);
unitTest(
{
// FIXME(bartlomieju)
ignore: true,
perms: { net: true },
},
async function netListenAsyncIterator(): Promise<void> {
const addr = { hostname: "127.0.0.1", port: 3500 };
const listener = Deno.listen(addr);
const runAsyncIterator = async (): Promise<void> => {
for await (const conn of listener) {
await conn.write(new Uint8Array([1, 2, 3]));
conn.close();
}
};
runAsyncIterator();
const conn = await Deno.connect(addr);
const buf = new Uint8Array(1024);
const readResult = await conn.read(buf);
assertEquals(3, readResult);
assertEquals(1, buf[0]);
assertEquals(2, buf[1]);
assertEquals(3, buf[2]);
assert(conn.rid > 0);
assert(readResult !== null);
const readResult2 = await conn.read(buf);
assertEquals(readResult2, null);
listener.close();
conn.close();
},
);
unitTest(
{
// FIXME(bartlomieju)
ignore: true,
perms: { net: true },
},
async function netCloseWriteSuccess() {
const addr = { hostname: "127.0.0.1", port: 3500 };
const listener = Deno.listen(addr);
const closeDeferred = deferred();
listener.accept().then(async (conn) => {
await conn.write(new Uint8Array([1, 2, 3]));
await closeDeferred;
conn.close();
});
const conn = await Deno.connect(addr);
conn.closeWrite(); // closing write
const buf = new Uint8Array(1024);
// Check read not impacted
const readResult = await conn.read(buf);
assertEquals(3, readResult);
assertEquals(1, buf[0]);
assertEquals(2, buf[1]);
assertEquals(3, buf[2]);
// Check write should be closed
await assertThrowsAsync(async () => {
await conn.write(new Uint8Array([1, 2, 3]));
}, Deno.errors.BrokenPipe);
closeDeferred.resolve();
listener.close();
conn.close();
},
);
unitTest(
{
// FIXME(bartlomieju)
ignore: true,
perms: { net: true },
},
async function netDoubleCloseWrite() {
const addr = { hostname: "127.0.0.1", port: 3500 };
const listener = Deno.listen(addr);
const closeDeferred = deferred();
listener.accept().then(async (conn) => {
await closeDeferred;
conn.close();
});
const conn = await Deno.connect(addr);
conn.closeWrite(); // closing write
assertThrows(() => {
// Duplicated close should throw error
conn.closeWrite();
}, Deno.errors.NotConnected);
closeDeferred.resolve();
listener.close();
conn.close();
},
);
unitTest(
{
perms: { net: true },
},
async function netHangsOnClose() {
let acceptedConn: Deno.Conn;
const resolvable = deferred();
async function iteratorReq(listener: Deno.Listener): Promise<void> {
const p = new Uint8Array(10);
const conn = await listener.accept();
acceptedConn = conn;
try {
while (true) {
const nread = await conn.read(p);
if (nread === null) {
break;
}
await conn.write(new Uint8Array([1, 2, 3]));
}
} catch (err) {
assert(!!err);
assert(err instanceof Deno.errors.BadResource);
}
resolvable.resolve();
}
const addr = { hostname: "127.0.0.1", port: 3500 };
const listener = Deno.listen(addr);
iteratorReq(listener);
const conn = await Deno.connect(addr);
await conn.write(new Uint8Array([1, 2, 3, 4]));
const buf = new Uint8Array(10);
await conn.read(buf);
conn!.close();
acceptedConn!.close();
listener.close();
await resolvable;
},
);
unitTest(
{
perms: { net: true },
},
function netExplicitUndefinedHostname() {
const listener = Deno.listen({ hostname: undefined, port: 8080 });
assertEquals((listener.addr as Deno.NetAddr).hostname, "0.0.0.0");
listener.close();
},
);