From ee452ad883c1c711839655a307b39e8eea5bf410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 3 Mar 2020 18:22:53 +0100 Subject: add assertOps sanitizer in cli/js/ unit tests (#4209) * add "assertOps" test assertion which makes sure test case is not "leaking" ops - ie. after test finishes there are no pending async ops * apply "assertOps" to all tests in "cli/js/" * fix numerous tests leaking ops * document problem with edge case in "clearInterval" and "clearTimeout" implementation where they may leak async ops * move "cli/js/worker_test.ts" to "cli/tests/worker_test.ts" and run as integration test; workers leak ops because of missing "terminate" implementation --- cli/js/test_util.ts | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'cli/js/test_util.ts') diff --git a/cli/js/test_util.ts b/cli/js/test_util.ts index 6f52c01df..027610dd9 100644 --- a/cli/js/test_util.ts +++ b/cli/js/test_util.ts @@ -106,11 +106,37 @@ function normalizeTestPermissions(perms: TestPermissions): Permissions { }; } +// Wrap `TestFunction` in additional assertion that makes sure +// the test case does not leak async "ops" - ie. number of async +// completed ops after the test is the same as number of dispatched +// ops. Note that "unref" ops are ignored since in nature that are +// optional. +function assertOps(fn: Deno.TestFunction): Deno.TestFunction { + return async function asyncOpSanitizer(): Promise { + const pre = Deno.metrics(); + await fn(); + const post = Deno.metrics(); + // We're checking diff because one might spawn HTTP server in the background + // that will be a pending async op before test starts. + assertEquals( + post.opsDispatchedAsync - pre.opsDispatchedAsync, + post.opsCompletedAsync - pre.opsCompletedAsync, + `Test case is leaking async ops. + Before: + - dispatched: ${pre.opsDispatchedAsync} + - completed: ${pre.opsCompletedAsync} + After: + - dispatched: ${post.opsDispatchedAsync} + - completed: ${post.opsCompletedAsync}` + ); + }; +} + // Wrap `TestFunction` 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: Deno.TestFunction): Deno.TestFunction { - return async function(): Promise { + return async function resourceSanitizer(): Promise { const preResources = Deno.resources(); await fn(); const postResources = Deno.resources(); @@ -131,7 +157,7 @@ export function testPerm(perms: TestPermissions, fn: Deno.TestFunction): void { return; } - Deno.test(fn.name, assertResources(fn)); + Deno.test(fn.name, assertResources(assertOps(fn))); } export function test(fn: Deno.TestFunction): void { -- cgit v1.2.3