diff options
author | Matt Mastracci <matthew@mastracci.com> | 2024-02-05 12:21:29 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-05 12:21:29 -0700 |
commit | 0a3d329dd82456cd894bda257e01cd50a62d6833 (patch) | |
tree | ba74f8b4b4681f55e87f9e2d22ea5c96443680ff /cli/js | |
parent | aecad7f3531c76306274d86afb458fcbc08edca2 (diff) |
Reland refactor(cli): use new sanitizer for resources (#22226)
Originally in #22125
Reverted in #22153 because of #22148
Fixed in deno_core https://github.com/denoland/deno_core/pull/538
Test plan:
1. Check out: https://github.com/poolifier/poolifier-deno.git
2. `PATH=.../deno/target/release/:$PATH deno task test`
3. `ok | 13 passed (188 steps) | 0 failed (18s)`
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/40_test.js | 183 |
1 files changed, 2 insertions, 181 deletions
diff --git a/cli/js/40_test.js b/cli/js/40_test.js index b6f966f20..146163fdd 100644 --- a/cli/js/40_test.js +++ b/cli/js/40_test.js @@ -15,10 +15,8 @@ const { MapPrototypeGet, MapPrototypeHas, MapPrototypeSet, - ObjectKeys, Promise, SafeArrayIterator, - Set, SymbolToStringTag, TypeError, } = primordials; @@ -342,182 +340,6 @@ function assertOps(fn) { }; } -function prettyResourceNames(name) { - switch (name) { - case "fsFile": - return ["A file", "opened", "closed"]; - case "fetchRequest": - return ["A fetch request", "started", "finished"]; - case "fetchRequestBody": - return ["A fetch request body", "created", "closed"]; - case "fetchResponse": - return ["A fetch response body", "created", "consumed"]; - case "httpClient": - return ["An HTTP client", "created", "closed"]; - case "dynamicLibrary": - return ["A dynamic library", "loaded", "unloaded"]; - case "httpConn": - return ["An inbound HTTP connection", "accepted", "closed"]; - case "httpStream": - return ["An inbound HTTP request", "accepted", "closed"]; - case "tcpStream": - return ["A TCP connection", "opened/accepted", "closed"]; - case "unixStream": - return ["A Unix connection", "opened/accepted", "closed"]; - case "tlsStream": - return ["A TLS connection", "opened/accepted", "closed"]; - case "tlsListener": - return ["A TLS listener", "opened", "closed"]; - case "unixListener": - return ["A Unix listener", "opened", "closed"]; - case "unixDatagram": - return ["A Unix datagram", "opened", "closed"]; - case "tcpListener": - return ["A TCP listener", "opened", "closed"]; - case "udpSocket": - return ["A UDP socket", "opened", "closed"]; - case "timer": - return ["A timer", "started", "fired/cleared"]; - case "textDecoder": - return ["A text decoder", "created", "finished"]; - case "messagePort": - return ["A message port", "created", "closed"]; - case "webSocketStream": - return ["A WebSocket", "opened", "closed"]; - case "fsEvents": - return ["A file system watcher", "created", "closed"]; - case "childStdin": - return ["A child process stdin", "opened", "closed"]; - case "childStdout": - return ["A child process stdout", "opened", "closed"]; - case "childStderr": - return ["A child process stderr", "opened", "closed"]; - case "child": - return ["A child process", "started", "closed"]; - case "signal": - return ["A signal listener", "created", "fired/cleared"]; - case "stdin": - return ["The stdin pipe", "opened", "closed"]; - case "stdout": - return ["The stdout pipe", "opened", "closed"]; - case "stderr": - return ["The stderr pipe", "opened", "closed"]; - case "compression": - return ["A CompressionStream", "created", "closed"]; - default: - return [`A "${name}" resource`, "created", "cleaned up"]; - } -} - -function resourceCloseHint(name) { - switch (name) { - case "fsFile": - return "Close the file handle by calling `file.close()`."; - case "fetchRequest": - return "Await the promise returned from `fetch()` or abort the fetch with an abort signal."; - case "fetchRequestBody": - return "Terminate the request body `ReadableStream` by closing or erroring it."; - case "fetchResponse": - return "Consume or close the response body `ReadableStream`, e.g `await resp.text()` or `await resp.body.cancel()`."; - case "httpClient": - return "Close the HTTP client by calling `httpClient.close()`."; - case "dynamicLibrary": - return "Unload the dynamic library by calling `dynamicLibrary.close()`."; - case "httpConn": - return "Close the inbound HTTP connection by calling `httpConn.close()`."; - case "httpStream": - return "Close the inbound HTTP request by responding with `e.respondWith()` or closing the HTTP connection."; - case "tcpStream": - return "Close the TCP connection by calling `tcpConn.close()`."; - case "unixStream": - return "Close the Unix socket connection by calling `unixConn.close()`."; - case "tlsStream": - return "Close the TLS connection by calling `tlsConn.close()`."; - case "tlsListener": - return "Close the TLS listener by calling `tlsListener.close()`."; - case "unixListener": - return "Close the Unix socket listener by calling `unixListener.close()`."; - case "unixDatagram": - return "Close the Unix datagram socket by calling `unixDatagram.close()`."; - case "tcpListener": - return "Close the TCP listener by calling `tcpListener.close()`."; - case "udpSocket": - return "Close the UDP socket by calling `udpSocket.close()`."; - case "timer": - return "Clear the timer by calling `clearInterval` or `clearTimeout`."; - case "textDecoder": - return "Close the text decoder by calling `textDecoder.decode('')` or `await textDecoderStream.readable.cancel()`."; - case "messagePort": - return "Close the message port by calling `messagePort.close()`."; - case "webSocketStream": - return "Close the WebSocket by calling `webSocket.close()`."; - case "fsEvents": - return "Close the file system watcher by calling `watcher.close()`."; - case "childStdin": - return "Close the child process stdin by calling `proc.stdin.close()`."; - case "childStdout": - return "Close the child process stdout by calling `proc.stdout.close()` or `await child.stdout.cancel()`."; - case "childStderr": - return "Close the child process stderr by calling `proc.stderr.close()` or `await child.stderr.cancel()`."; - case "child": - return "Close the child process by calling `proc.kill()` or `proc.close()`."; - case "signal": - return "Clear the signal listener by calling `Deno.removeSignalListener`."; - case "stdin": - return "Close the stdin pipe by calling `Deno.stdin.close()`."; - case "stdout": - return "Close the stdout pipe by calling `Deno.stdout.close()`."; - case "stderr": - return "Close the stderr pipe by calling `Deno.stderr.close()`."; - case "compression": - return "Close the compression stream by calling `await stream.writable.close()`."; - default: - return "Close the resource before the end of the test."; - } -} - -// Wrap test function in additional assertion that makes sure -// the test case does not "leak" resources - ie. resource table after -// the test has exactly the same contents as before the test. -function assertResources(fn) { - /** @param desc {TestDescription | TestStepDescription} */ - return async function resourceSanitizer(desc) { - const pre = core.resources(); - const innerResult = await fn(desc); - if (innerResult) return innerResult; - const post = core.resources(); - - const allResources = new Set([ - ...new SafeArrayIterator(ObjectKeys(pre)), - ...new SafeArrayIterator(ObjectKeys(post)), - ]); - - const details = []; - for (const resource of allResources) { - const preResource = pre[resource]; - const postResource = post[resource]; - if (preResource === postResource) continue; - - if (preResource === undefined) { - const [name, action1, action2] = prettyResourceNames(postResource); - const hint = resourceCloseHint(postResource); - const detail = - `${name} (rid ${resource}) was ${action1} during the test, but not ${action2} during the test. ${hint}`; - ArrayPrototypePush(details, detail); - } else { - const [name, action1, action2] = prettyResourceNames(preResource); - const detail = - `${name} (rid ${resource}) was ${action1} before the test started, but was ${action2} during the test. Do not close resources in a test that were not created during that test.`; - ArrayPrototypePush(details, detail); - } - } - if (details.length == 0) { - return null; - } - return { failed: { leakedResources: details } }; - }; -} - // Wrap test function in additional assertion that makes sure // that the test case does not accidentally exit prematurely. function assertExit(fn, isTest) { @@ -720,6 +542,8 @@ function testInner( testDesc.name, testDesc.ignore, testDesc.only, + false, /*testDesc.sanitizeOps*/ + testDesc.sanitizeResources, testDesc.location.fileName, testDesc.location.lineNumber, testDesc.location.columnNumber, @@ -910,9 +734,6 @@ function wrapTest(desc) { if (desc.sanitizeOps) { testFn = assertOps(testFn); } - if (desc.sanitizeResources) { - testFn = assertResources(testFn); - } if (desc.sanitizeExit) { testFn = assertExit(testFn, true); } |