diff options
author | Bert Belder <bertbelder@gmail.com> | 2021-10-09 22:37:19 +0200 |
---|---|---|
committer | Bert Belder <bertbelder@gmail.com> | 2021-10-17 19:50:42 +0200 |
commit | ff932b411d63269dbd4d30ea6bd0aa5160fd8aff (patch) | |
tree | 5dad617aea815c4145262860d6e3b5115224ab92 /cli/tests/unit | |
parent | ff95fc167d7124f3c7f2c6951070e2c40701cf32 (diff) |
fix(core): poll async ops eagerly (#12385)
Currently all async ops are polled lazily, which means that op
initialization code is postponed until control is yielded to the event
loop. This has some weird consequences, e.g.
```js
let listener = Deno.listen(...);
let conn_promise = listener.accept();
listener.close();
// `BadResource` is thrown. A reasonable error would be `Interrupted`.
let conn = await conn_promise;
```
JavaScript promises are expected to be eagerly evaluated. This patch
makes ops actually do that.
Diffstat (limited to 'cli/tests/unit')
-rw-r--r-- | cli/tests/unit/http_test.ts | 47 | ||||
-rw-r--r-- | cli/tests/unit/net_test.ts | 37 |
2 files changed, 31 insertions, 53 deletions
diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts index 0f23a2bb5..080b94a1d 100644 --- a/cli/tests/unit/http_test.ts +++ b/cli/tests/unit/http_test.ts @@ -892,15 +892,13 @@ unitTest( respondPromise, ]); + httpConn.close(); listener.close(); assert(errors.length >= 1); for (const error of errors) { assertEquals(error.name, "Http"); - assertEquals( - error.message, - "connection closed before message completed", - ); + assert(error.message.includes("connection")); } }, ); @@ -975,44 +973,29 @@ unitTest( unitTest( { permissions: { net: true } }, async function droppedConnSenderNoPanic() { - async function server(listener: Deno.Listener) { + async function server() { + const listener = Deno.listen({ port: 8000 }); const conn = await listener.accept(); const http = Deno.serveHttp(conn); - - for (;;) { - const req = await http.nextRequest(); - if (req == null) break; - - nextloop() - .then(() => { - http.close(); - return req.respondWith(new Response("boom")); - }) - .catch(() => {}); - } - + const evt = await http.nextRequest(); + http.close(); try { - http.close(); + await evt!.respondWith(new Response("boom")); } catch { - "nop"; + // Ignore error. } - listener.close(); } async function client() { - const resp = await fetch("http://127.0.0.1:8000/"); - await resp.body?.cancel(); - } - - function nextloop() { - return new Promise((resolve) => setTimeout(resolve, 0)); + try { + const resp = await fetch("http://127.0.0.1:8000/"); + await resp.body?.cancel(); + } catch { + // Ignore error + } } - async function main() { - const listener = Deno.listen({ port: 8000 }); - await Promise.all([server(listener), client()]); - } - await main(); + await Promise.all([server(), client()]); }, ); diff --git a/cli/tests/unit/net_test.ts b/cli/tests/unit/net_test.ts index a1585ce6b..eabe26c84 100644 --- a/cli/tests/unit/net_test.ts +++ b/cli/tests/unit/net_test.ts @@ -117,10 +117,10 @@ unitTest( const listener = Deno.listen({ port: 4501 }); const p = listener.accept(); listener.close(); + // TODO(piscisaureus): the error type should be `Interrupted` here, which + // gets thrown, but then ext/net catches it and rethrows `BadResource`. await assertRejects( - async () => { - await p; - }, + () => p, Deno.errors.BadResource, "Listener has been closed", ); @@ -141,11 +141,8 @@ unitTest( const p = listener.accept(); listener.close(); await assertRejects( - async () => { - await p; - }, - Deno.errors.BadResource, - "Listener has been closed", + () => p, + Deno.errors.Interrupted, ); }, ); @@ -173,27 +170,29 @@ unitTest( }, ); -// TODO(jsouto): Enable when tokio updates mio to v0.7! unitTest( - { ignore: true, permissions: { read: true, write: true } }, + { + ignore: Deno.build.os === "windows", + permissions: { read: true, write: true }, + }, async function netUnixConcurrentAccept() { const filePath = await Deno.makeTempFile(); const listener = Deno.listen({ transport: "unix", path: filePath }); let acceptErrCount = 0; const checkErr = (e: Error) => { - if (e.message === "Listener has been closed") { + if (e instanceof Deno.errors.Interrupted) { // "operation canceled" assertEquals(acceptErrCount, 1); - } else if (e.message === "Another accept task is ongoing") { + } else if (e instanceof Deno.errors.Busy) { // "Listener already in use" acceptErrCount++; } else { - throw new Error("Unexpected error message"); + throw e; } }; const p = listener.accept().catch(checkErr); const p1 = listener.accept().catch(checkErr); await Promise.race([p, p1]); listener.close(); - await [p, p1]; + await Promise.all([p, p1]); assertEquals(acceptErrCount, 1); }, ); @@ -500,11 +499,7 @@ unitTest( ); unitTest( - { - // FIXME(bartlomieju) - ignore: true, - permissions: { net: true }, - }, + { permissions: { net: true } }, async function netListenAsyncIterator() { const addr = { hostname: "127.0.0.1", port: 3500 }; const listener = Deno.listen(addr); @@ -590,8 +585,8 @@ unitTest( await conn.write(new Uint8Array([1, 2, 3])); } } catch (err) { - assert(!!err); - assert(err instanceof Deno.errors.BadResource); + assert(err); + assert(err instanceof Deno.errors.Interrupted); } } |