From f3751e498faabd524494a4b70c49b1f53fe5ebdd Mon Sep 17 00:00:00 2001 From: Casper Beyer Date: Mon, 26 Apr 2021 05:38:59 +0800 Subject: feat(cli): add test permissions to Deno.test (#10188) This commits adds adds "permissions" option to the test definitions which allows tests to run with different permission sets than the process's permission. The change will only be in effect within the test function, once the test has completed the original process permission set is restored. Test permissions cannot exceed the process's permission. You can only narrow or drop permissions, failure to acquire a permission results in an error being thrown and the test case will fail. --- runtime/js/40_testing.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'runtime/js/40_testing.js') diff --git a/runtime/js/40_testing.js b/runtime/js/40_testing.js index 7666fa050..4a97f6437 100644 --- a/runtime/js/40_testing.js +++ b/runtime/js/40_testing.js @@ -4,6 +4,7 @@ ((window) => { const core = window.Deno.core; const colors = window.__bootstrap.colors; + const { parsePermissions } = window.__bootstrap.worker; const { setExitHandler, exit } = window.__bootstrap.os; const { Console, inspectArgs } = window.__bootstrap.console; const { stdout } = window.__bootstrap.files; @@ -121,6 +122,7 @@ finishing test case.`; sanitizeOps: true, sanitizeResources: true, sanitizeExit: true, + permissions: null, }; if (typeof t === "string") { @@ -226,6 +228,17 @@ finishing test case.`; } } + function pledgeTestPermissions(permissions) { + return core.opSync( + "op_pledge_test_permissions", + parsePermissions(permissions), + ); + } + + function restoreTestPermissions(token) { + core.opSync("op_restore_test_permissions", token); + } + // TODO(bartlomieju): already implements AsyncGenerator, but add as "implements to class" // TODO(bartlomieju): implements PromiseLike class TestRunner { @@ -257,6 +270,7 @@ finishing test case.`; const results = []; const suiteStart = +new Date(); + for (const test of this.testsToRun) { const endMessage = { name: test.name, @@ -268,15 +282,30 @@ finishing test case.`; this.stats.ignored++; } else { const start = +new Date(); + + let token; try { + if (test.permissions) { + token = pledgeTestPermissions(test.permissions); + } + await test.fn(); + endMessage.status = "passed"; this.stats.passed++; } catch (err) { endMessage.status = "failed"; endMessage.error = err; this.stats.failed++; + } finally { + // Permissions must always be restored for a clean environment, + // otherwise the process can end up dropping permissions + // until there are none left. + if (token) { + restoreTestPermissions(token); + } } + endMessage.duration = +new Date() - start; } results.push(endMessage); -- cgit v1.2.3