1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-28 01:59:06 -05:00
denoland-deno/cli/tests/node_compat/test.ts
Yoshiya Hinosawa 3deade4b14
chore(ext/node): run node compat parallel tests in core number concurrency (#18505)
We currently run the all test cases in `parallel` category at the same
time, which invokes hundreds process at the same time, and that seems
causing some flakiness in CI. (maybe related to #18487)

This PR limits the concurrency to the number of cpu cores. This is more
aligned to how Node.js run their `parallel` test in their repository.
42c4a35952/Makefile (L356)
2023-03-30 16:35:45 +02:00

150 lines
4.8 KiB
TypeScript

// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { magenta } from "std/fmt/colors.ts";
import { pooledMap } from "std/async/pool.ts";
import { dirname, fromFileUrl, join } from "std/path/mod.ts";
import { fail } from "std/testing/asserts.ts";
import {
config,
getPathsFromTestSuites,
partitionParallelTestPaths,
} from "./common.ts";
// If the test case is invoked like
// deno test -A cli/tests/node_compat/test.ts -- <test-names>
// Use the test-names as filters
const filters = Deno.args;
const hasFilters = filters.length > 0;
/**
* This script will run the test files specified in the configuration file
*
* Each test file will be run independently and wait until completion, if an abnormal
* code for the test is reported, the test suite will fail immediately
*/
const toolsPath = dirname(fromFileUrl(import.meta.url));
const stdRootUrl = new URL("../../", import.meta.url).href;
const testPaths = partitionParallelTestPaths(
getPathsFromTestSuites(config.tests),
);
const cwd = new URL(".", import.meta.url);
const importMap = "import_map.json";
const windowsIgnorePaths = new Set(
getPathsFromTestSuites(config.windowsIgnore),
);
const darwinIgnorePaths = new Set(
getPathsFromTestSuites(config.darwinIgnore),
);
const decoder = new TextDecoder();
let testSerialId = 0;
async function runTest(t: Deno.TestContext, path: string): Promise<void> {
// If filter patterns are given and any pattern doesn't match
// to the file path, then skip the case
if (
filters.length > 0 &&
filters.every((pattern) => !path.includes(pattern))
) {
return;
}
const ignore =
(Deno.build.os === "windows" && windowsIgnorePaths.has(path)) ||
(Deno.build.os === "darwin" && darwinIgnorePaths.has(path));
await t.step({
name: `Node.js compatibility "${path}"`,
ignore,
sanitizeOps: false,
sanitizeResources: false,
sanitizeExit: false,
fn: async () => {
const testCase = join(toolsPath, "test", path);
const v8Flags = ["--stack-size=4000"];
const testSource = await Deno.readTextFile(testCase);
// TODO(kt3k): Parse `Flags` directive correctly
if (testSource.includes("Flags: --expose_externalize_string")) {
v8Flags.push("--expose-externalize-string");
}
const args = [
"run",
"-A",
"--quiet",
"--unstable",
//"--unsafely-ignore-certificate-errors",
"--v8-flags=" + v8Flags.join(),
testCase.endsWith(".mjs") ? "--import-map=" + importMap : "runner.ts",
testCase,
];
// Pipe stdout in order to output each test result as Deno.test output
// That way the tests will respect the `--quiet` option when provided
const command = new Deno.Command(Deno.execPath(), {
args,
env: {
DENO_NODE_COMPAT_URL: stdRootUrl,
TEST_SERIAL_ID: String(testSerialId++),
},
cwd,
});
const { code, stdout, stderr } = await command.output();
if (code !== 0) {
// If the test case failed, show the stdout, stderr, and instruction
// for repeating the single test case.
if (stdout.length) console.log(decoder.decode(stdout));
console.log(`Error: "${path}" failed`);
console.log(
"You can repeat only this test with the command:",
magenta(
`./target/debug/deno test -A --import-map cli/tests/node_compat/import_map.json cli/tests/node_compat/test.ts -- ${path}`,
),
);
fail(decoder.decode(stderr));
} else if (hasFilters) {
// Even if the test case is successful, shows the stdout and stderr
// when test case filtering is specified.
if (stdout.length) console.log(decoder.decode(stdout));
if (stderr.length) console.log(decoder.decode(stderr));
}
},
});
}
Deno.test("Node.js compatibility", async (t) => {
for (const path of testPaths.sequential) {
await runTest(t, path);
}
const testPool = pooledMap(
navigator.hardwareConcurrency,
testPaths.parallel,
(path) => runTest(t, path),
);
const testCases = [];
for await (const testCase of testPool) {
testCases.push(testCase);
}
await Promise.all(testCases);
});
function checkConfigTestFilesOrder(testFileLists: Array<string[]>) {
for (const testFileList of testFileLists) {
const sortedTestList = JSON.parse(JSON.stringify(testFileList));
sortedTestList.sort();
if (JSON.stringify(testFileList) !== JSON.stringify(sortedTestList)) {
throw new Error(
`File names in \`config.json\` are not correct order.`,
);
}
}
}
if (!hasFilters) {
Deno.test("checkConfigTestFilesOrder", function () {
checkConfigTestFilesOrder([
...Object.keys(config.ignore).map((suite) => config.ignore[suite]),
...Object.keys(config.tests).map((suite) => config.tests[suite]),
]);
});
}