2019-07-31 07:13:05 -04:00
|
|
|
#!/usr/bin/env -S deno run --reload --allow-run
|
2020-01-02 15:13:47 -05:00
|
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
2019-05-08 19:15:24 -04:00
|
|
|
import "./unit_tests.ts";
|
2019-10-27 11:22:53 -04:00
|
|
|
import {
|
2020-03-13 10:57:32 -04:00
|
|
|
assert,
|
|
|
|
readLines,
|
2019-10-27 11:22:53 -04:00
|
|
|
permissionCombinations,
|
2020-03-13 10:57:32 -04:00
|
|
|
Permissions,
|
|
|
|
registerUnitTests,
|
|
|
|
SocketReporter,
|
|
|
|
fmtPerms
|
2019-10-27 11:22:53 -04:00
|
|
|
} from "./test_util.ts";
|
2019-05-08 19:15:24 -04:00
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
interface PermissionSetTestResult {
|
|
|
|
perms: Permissions;
|
|
|
|
passed: boolean;
|
|
|
|
stats: Deno.TestStats;
|
|
|
|
permsStr: string;
|
|
|
|
duration: number;
|
2019-06-01 11:13:36 -04:00
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
const PERMISSIONS: Deno.PermissionName[] = [
|
|
|
|
"read",
|
|
|
|
"write",
|
|
|
|
"net",
|
|
|
|
"env",
|
|
|
|
"run",
|
|
|
|
"plugin",
|
|
|
|
"hrtime"
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Take a list of permissions and revoke missing permissions.
|
|
|
|
*/
|
|
|
|
async function dropWorkerPermissions(
|
|
|
|
requiredPermissions: Deno.PermissionName[]
|
|
|
|
): Promise<void> {
|
|
|
|
const permsToDrop = PERMISSIONS.filter((p): boolean => {
|
|
|
|
return !requiredPermissions.includes(p);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (const perm of permsToDrop) {
|
|
|
|
await Deno.permissions.revoke({ name: perm });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function workerRunnerMain(args: string[]): Promise<void> {
|
|
|
|
const addrArg = args.find(e => e.includes("--addr"));
|
|
|
|
assert(typeof addrArg === "string", "Missing --addr argument");
|
|
|
|
const addrStr = addrArg.split("=")[1];
|
|
|
|
const [hostname, port] = addrStr.split(":");
|
|
|
|
const addr = { hostname, port: Number(port) };
|
|
|
|
|
|
|
|
let perms: Deno.PermissionName[] = [];
|
|
|
|
const permsArg = args.find(e => e.includes("--perms"));
|
|
|
|
assert(typeof permsArg === "string", "Missing --perms argument");
|
|
|
|
const permsStr = permsArg.split("=")[1];
|
|
|
|
if (permsStr.length > 0) {
|
|
|
|
perms = permsStr.split(",") as Deno.PermissionName[];
|
|
|
|
}
|
|
|
|
// Setup reporter
|
|
|
|
const conn = await Deno.connect(addr);
|
|
|
|
const socketReporter = new SocketReporter(conn);
|
|
|
|
// Drop current process permissions to requested set
|
|
|
|
await dropWorkerPermissions(perms);
|
|
|
|
// Register unit tests that match process permissions
|
|
|
|
await registerUnitTests();
|
|
|
|
// Execute tests
|
|
|
|
await Deno.runTests({
|
|
|
|
failFast: false,
|
|
|
|
exitOnFail: false,
|
|
|
|
reporter: socketReporter
|
|
|
|
});
|
|
|
|
// Notify parent process we're done
|
|
|
|
socketReporter.close();
|
|
|
|
}
|
2019-11-13 13:42:34 -05:00
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
function spawnWorkerRunner(addr: string, perms: Permissions): Deno.Process {
|
|
|
|
// run subsequent tests using same deno executable
|
|
|
|
const permStr = Object.keys(perms)
|
|
|
|
.filter((permName): boolean => {
|
|
|
|
return perms[permName as Deno.PermissionName] === true;
|
2019-11-13 13:42:34 -05:00
|
|
|
})
|
2020-03-13 10:57:32 -04:00
|
|
|
.join(",");
|
|
|
|
|
|
|
|
const args = [
|
|
|
|
Deno.execPath(),
|
|
|
|
"run",
|
|
|
|
"-A",
|
|
|
|
"cli/js/tests/unit_test_runner.ts",
|
|
|
|
"--",
|
|
|
|
"--worker",
|
|
|
|
`--addr=${addr}`,
|
|
|
|
`--perms=${permStr}`
|
|
|
|
];
|
|
|
|
|
|
|
|
const p = Deno.run({
|
|
|
|
args,
|
|
|
|
stdin: "null",
|
|
|
|
stdout: "piped",
|
|
|
|
stderr: "null"
|
|
|
|
});
|
|
|
|
|
|
|
|
return p;
|
2019-05-08 19:15:24 -04:00
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
async function runTestsForPermissionSet(
|
|
|
|
reporter: Deno.ConsoleTestReporter,
|
|
|
|
perms: Permissions
|
|
|
|
): Promise<PermissionSetTestResult> {
|
|
|
|
const permsFmt = fmtPerms(perms);
|
|
|
|
console.log(`Running tests for: ${permsFmt}`);
|
|
|
|
const addr = { hostname: "127.0.0.1", port: 4510 };
|
|
|
|
const addrStr = `${addr.hostname}:${addr.port}`;
|
|
|
|
const workerListener = Deno.listen(addr);
|
|
|
|
|
|
|
|
const workerProcess = spawnWorkerRunner(addrStr, perms);
|
|
|
|
|
|
|
|
// Wait for worker subprocess to go online
|
|
|
|
const conn = await workerListener.accept();
|
|
|
|
|
|
|
|
let err;
|
|
|
|
let hasThrown = false;
|
|
|
|
let expectedPassedTests;
|
|
|
|
let endEvent;
|
|
|
|
|
|
|
|
try {
|
|
|
|
for await (const line of readLines(conn)) {
|
|
|
|
const msg = JSON.parse(line);
|
|
|
|
|
|
|
|
if (msg.kind === Deno.TestEvent.Start) {
|
|
|
|
expectedPassedTests = msg.tests;
|
|
|
|
await reporter.start(msg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.kind === Deno.TestEvent.Result) {
|
|
|
|
await reporter.result(msg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
endEvent = msg;
|
|
|
|
await reporter.end(msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
hasThrown = true;
|
|
|
|
err = e;
|
|
|
|
} finally {
|
|
|
|
workerListener.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasThrown) {
|
|
|
|
throw err;
|
|
|
|
}
|
2019-05-08 19:15:24 -04:00
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
if (typeof expectedPassedTests === "undefined") {
|
|
|
|
throw new Error("Worker runner didn't report start");
|
2019-05-08 19:15:24 -04:00
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
if (typeof endEvent === "undefined") {
|
|
|
|
throw new Error("Worker runner didn't report end");
|
|
|
|
}
|
|
|
|
|
|
|
|
const workerStatus = await workerProcess.status();
|
|
|
|
if (!workerStatus.success) {
|
|
|
|
throw new Error(
|
|
|
|
`Worker runner exited with status code: ${workerStatus.code}`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
workerProcess.close();
|
|
|
|
|
|
|
|
const passed = expectedPassedTests === endEvent.stats.passed;
|
|
|
|
|
|
|
|
return {
|
|
|
|
perms,
|
|
|
|
passed,
|
|
|
|
permsStr: permsFmt,
|
|
|
|
duration: endEvent.duration,
|
|
|
|
stats: endEvent.stats
|
|
|
|
};
|
2019-05-08 19:15:24 -04:00
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
async function masterRunnerMain(): Promise<void> {
|
2019-05-08 19:15:24 -04:00
|
|
|
console.log(
|
|
|
|
"Discovered permission combinations for tests:",
|
|
|
|
permissionCombinations.size
|
|
|
|
);
|
|
|
|
|
|
|
|
for (const perms of permissionCombinations.values()) {
|
|
|
|
console.log("\t" + fmtPerms(perms));
|
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
const testResults = new Set<PermissionSetTestResult>();
|
|
|
|
const consoleReporter = new Deno.ConsoleTestReporter();
|
2019-05-08 19:15:24 -04:00
|
|
|
|
|
|
|
for (const perms of permissionCombinations.values()) {
|
2020-03-13 10:57:32 -04:00
|
|
|
const result = await runTestsForPermissionSet(consoleReporter, perms);
|
|
|
|
testResults.add(result);
|
2019-05-08 19:15:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// if any run tests returned non-zero status then whole test
|
|
|
|
// run should fail
|
2020-03-13 10:57:32 -04:00
|
|
|
let testsPassed = true;
|
2019-05-08 19:15:24 -04:00
|
|
|
|
2019-06-01 11:13:36 -04:00
|
|
|
for (const testResult of testResults) {
|
2020-03-13 10:57:32 -04:00
|
|
|
const { permsStr, stats, duration } = testResult;
|
|
|
|
console.log(`Summary for ${permsStr}`);
|
|
|
|
await consoleReporter.end({
|
|
|
|
kind: Deno.TestEvent.End,
|
|
|
|
stats,
|
|
|
|
duration,
|
|
|
|
results: []
|
|
|
|
});
|
|
|
|
testsPassed = testsPassed && testResult.passed;
|
2019-05-08 19:15:24 -04:00
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
if (!testsPassed) {
|
2019-05-08 19:15:24 -04:00
|
|
|
console.error("Unit tests failed");
|
|
|
|
Deno.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log("Unit tests passed");
|
|
|
|
}
|
|
|
|
|
2020-03-13 10:57:32 -04:00
|
|
|
async function main(): Promise<void> {
|
|
|
|
const args = Deno.args;
|
|
|
|
|
|
|
|
const isWorker = args.includes("--worker");
|
|
|
|
|
|
|
|
if (isWorker) {
|
|
|
|
return await workerRunnerMain(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
return await masterRunnerMain();
|
|
|
|
}
|
|
|
|
|
2019-05-08 19:15:24 -04:00
|
|
|
main();
|