Skip to content

Instantly share code, notes, and snippets.

@jasonLaster
Created September 15, 2020 15:13
Show Gist options
  • Select an option

  • Save jasonLaster/2d0571e1239b2c654736b04001ab2b20 to your computer and use it in GitHub Desktop.

Select an option

Save jasonLaster/2d0571e1239b2c654736b04001ab2b20 to your computer and use it in GitHub Desktop.
diff --git a/test/run.js b/test/run.js
index 17d165c1..7657aa8c 100644
--- a/test/run.js
+++ b/test/run.js
@@ -10,29 +10,28 @@ const url = require("url");
const minimist = require("minimist");
const Manifest = require("./manifest.json");
+let count = 1;
+const patterns = [];
+let stripeIndex, stripeCount, dispatchServer, gInstallDir;
+let shouldRecordExamples = false;
+let shouldRecordAll = false;
+let shouldRecordViewer = false;
+const startTime = Date.now();
+
if (isRunningLocally()) {
const argsObject = minimist(process.argv.slice(2));
- runTestRunner(argsObject);
+ startTestRunner(argsObject);
}
function isRunningLocally() {
return process?.env?._ === "/usr/local/bin/node";
}
-function startTestRunner(argsObject) {
- let count = 1;
- const patterns = [];
- let stripeIndex, stripeCount, dispatchServer, gInstallDir;
- let shouldRecordExamples = false;
- let shouldRecordAll = false;
- let shouldRecordViewer = false;
- const startTime = Date.now();
-
- function processArgs(argsObject) {
- const argv = argsObject;
+function processArgs(argsObject) {
+ const argv = argsObject;
- if ((argv._.length == 0 && Object.keys(argv).length == 1) || argv["h"] || argv["help"]) {
- const usage = `
+ if ((argv._.length == 0 && Object.keys(argv).length == 1) || argv["h"] || argv["help"]) {
+ const usage = `
Usage: run.js arguments
Arguments:
--count N: Run tests N times
@@ -41,241 +40,240 @@ function startTestRunner(argsObject) {
--record-viewer: Record the viewer while the test is running
--record-all: Record examples and save the recordings locally, and record the viewer
`;
- console.log(usage);
- process.exit(0);
- }
-
- shouldRecordExamples = argv._.find(() => "record-examples") || shouldRecordExamples;
- shouldRecordViewer = argv._.find(() => "record-viewer") || shouldRecordViewer;
- shouldRecordAll = argv._.find(() => "record-all") || shouldRecordAll;
- count += argv.count || 0;
-
- if (argv.pattern) {
- patterns.push(argv.pattern);
- }
+ console.log(usage);
+ process.exit(0);
}
- function processEnvironmentVariables() {
- /*
- * RECORD_REPLAY_DONT_RECORD_VIEWER Disables recording the viewer
- */
-
- // The INPUT_STRIPE environment variable is set when running as a Github action.
- // This splits testing across multiple machines by having each only do every
- // other stripeCount tests, staggered so that all tests run on some machine.
- if (process.env.INPUT_STRIPE) {
- const match = /(\d+)\/(\d+)/.exec(process.env.INPUT_STRIPE);
- stripeIndex = +match[1];
- stripeCount = +match[2];
- }
-
- gInstallDir = process.env.RECORD_REPLAY_PATH || "/Applications/Replay.app";
+ shouldRecordExamples = argv._.find(() => "record-examples") || shouldRecordExamples;
+ shouldRecordViewer = argv._.find(() => "record-viewer") || shouldRecordViewer;
+ shouldRecordAll = argv._.find(() => "record-all") || shouldRecordAll;
+ count += argv.count || 0;
- // Get the address to use for the dispatch server.
- dispatchServer = process.env.RECORD_REPLAY_SERVER || "wss://dispatch.replay.io";
+ if (argv.pattern) {
+ patterns.push(argv.pattern);
}
+}
- function startExampleServer() {
- // Server for content in the examples directory.
- console.log(`Starting example server on port 7998`);
- const exampleServer = http.createServer((request, response) => {
- try {
- const content = fs.readFileSync(`test/examples/${request.url}`);
- response.writeHead(200, { "Content-Type": getContentType(request.url) });
- response.end(content);
- } catch (e) {
- response.writeHead(404);
- response.end();
- }
- });
- exampleServer.listen(7998);
+function processEnvironmentVariables() {
+ /*
+ * RECORD_REPLAY_DONT_RECORD_VIEWER Disables recording the viewer
+ */
+
+ // The INPUT_STRIPE environment variable is set when running as a Github action.
+ // This splits testing across multiple machines by having each only do every
+ // other stripeCount tests, staggered so that all tests run on some machine.
+ if (process.env.INPUT_STRIPE) {
+ const match = /(\d+)\/(\d+)/.exec(process.env.INPUT_STRIPE);
+ stripeIndex = +match[1];
+ stripeCount = +match[2];
}
- function elapsedTime() {
- return (Date.now() - startTime) / 1000;
- }
+ gInstallDir = process.env.RECORD_REPLAY_PATH || "/Applications/Replay.app";
- function getContentType(url) {
- return url.endsWith(".js") ? "text/javascript" : "";
- }
+ // Get the address to use for the dispatch server.
+ dispatchServer = process.env.RECORD_REPLAY_SERVER || "wss://dispatch.replay.io";
+}
- async function runMatchingTests() {
- for (let i = 0; i < Manifest.length; i++) {
- const [test, example] = Manifest[i];
- const exampleRecordingId = ExampleRecordings[example];
- if (stripeCount && i % stripeCount != stripeIndex) {
- continue;
- }
+function startExampleServer() {
+ // Server for content in the examples directory.
+ console.log(`Starting example server on port 7998`);
+ const exampleServer = http.createServer((request, response) => {
+ try {
+ const content = fs.readFileSync(`test/examples/${request.url}`);
+ response.writeHead(200, { "Content-Type": getContentType(request.url) });
+ response.end(content);
+ } catch (e) {
+ response.writeHead(404);
+ response.end();
+ }
+ });
+ exampleServer.listen(7998);
+}
+
+function elapsedTime() {
+ return (Date.now() - startTime) / 1000;
+}
- // To make tests run faster, we save recordings of the examples locally. This happens just once -
- // when the test is first run. In subsequent tests that require that example, we simply use the
- // saved recording of the example instead of making another recording. To re-record an example,
- // the user can pass in the `--record-examples` or `--record-all` flag to the test runner.
- const env = {
- RECORD_REPLAY_RECORD_EXAMPLE: shouldRecordAll || shouldRecordExamples || !exampleRecordingId,
- RECORD_REPLAY_DONT_RECORD_VIEWER: shouldRecordAll ? false : !shouldRecordViewer,
- RECORD_REPLAY_TEST_URL:
- shouldRecordExamples || !exampleRecordingId
- ? `http://localhost:7998/${example}`
- : `http://localhost:8080/view?id=${exampleRecordingId}&test=${test}`,
- };
-
- await runTest("test/harness.js", test, 240, env);
+function getContentType(url) {
+ return url.endsWith(".js") ? "text/javascript" : "";
+}
+
+async function runMatchingTests() {
+ for (let i = 0; i < Manifest.length; i++) {
+ const [test, example] = Manifest[i];
+ const exampleRecordingId = ExampleRecordings[example];
+ if (stripeCount && i % stripeCount != stripeIndex) {
+ continue;
}
- }
- function tmpFile() {
- return os.tmpdir() + ((Math.random() * 1e9) | 0);
+ // To make tests run faster, we save recordings of the examples locally. This happens just once -
+ // when the test is first run. In subsequent tests that require that example, we simply use the
+ // saved recording of the example instead of making another recording. To re-record an example,
+ // the user can pass in the `--record-examples` or `--record-all` flag to the test runner.
+ const env = {
+ RECORD_REPLAY_RECORD_EXAMPLE: shouldRecordAll || shouldRecordExamples || !exampleRecordingId,
+ RECORD_REPLAY_DONT_RECORD_VIEWER: shouldRecordAll ? false : !shouldRecordViewer,
+ RECORD_REPLAY_TEST_URL:
+ shouldRecordExamples || !exampleRecordingId
+ ? `http://localhost:7998/${example}`
+ : `http://localhost:8080/view?id=${exampleRecordingId}&test=${test}`,
+ };
+
+ await runTest("test/harness.js", test, 240, env);
}
+}
- function createTestScript({ path }) {
- const generatedScriptPath = tmpFile();
- const generatedScriptFd = fs.openSync(generatedScriptPath, "w");
- spawnSync("clang", ["-C", "-E", "-P", "-nostdinc", "-undef", "-x", "c++", path], {
- stdio: [, generatedScriptFd, generatedScriptFd],
- });
- fs.closeSync(generatedScriptFd);
-
- // print test file
- if (false) {
- const testFile = fs.readFileSync(generatedScriptPath, { encoding: "utf-8" });
- console.log(testFile);
- }
+function tmpFile() {
+ return os.tmpdir() + ((Math.random() * 1e9) | 0);
+}
- return generatedScriptPath;
+function createTestScript({ path }) {
+ const generatedScriptPath = tmpFile();
+ const generatedScriptFd = fs.openSync(generatedScriptPath, "w");
+ spawnSync("clang", ["-C", "-E", "-P", "-nostdinc", "-undef", "-x", "c++", path], {
+ stdio: [, generatedScriptFd, generatedScriptFd],
+ });
+ fs.closeSync(generatedScriptFd);
+
+ // print test file
+ if (false) {
+ const testFile = fs.readFileSync(generatedScriptPath, { encoding: "utf-8" });
+ console.log(testFile);
}
- let failures = [];
+ return generatedScriptPath;
+}
- async function runTest(path, local, timeout = 60, env = {}) {
- const testURL = env.RECORD_REPLAY_TEST_URL || "";
- for (const pattern of patterns) {
- if (!path.includes(pattern) && !testURL.includes(pattern) && !local.includes(pattern)) {
- console.log(`Skipping test ${path} ${testURL} ${local}`);
- return;
- }
+let failures = [];
+
+async function runTest(path, local, timeout = 60, env = {}) {
+ const testURL = env.RECORD_REPLAY_TEST_URL || "";
+ for (const pattern of patterns) {
+ if (!path.includes(pattern) && !testURL.includes(pattern) && !local.includes(pattern)) {
+ console.log(`Skipping test ${path} ${testURL} ${local}`);
+ return;
}
+ }
- console.log(`[${elapsedTime()}] Starting test ${path} ${testURL} ${local}`);
- const testScript = createTestScript({ path });
+ console.log(`[${elapsedTime()}] Starting test ${path} ${testURL} ${local}`);
+ const testScript = createTestScript({ path });
- const profileArgs = [];
- if (!process.env.NORMAL_PROFILE) {
- const profile = tmpFile();
- profileArgs.push("-profile", profile);
- }
+ const profileArgs = [];
+ if (!process.env.NORMAL_PROFILE) {
+ const profile = tmpFile();
+ profileArgs.push("-profile", profile);
+ }
- const gecko = spawn(`${gInstallDir}/Contents/MacOS/replay`, ["-foreground", ...profileArgs], {
- env: {
- ...process.env,
- ...env,
- MOZ_CRASHREPORTER_AUTO_SUBMIT: "1",
- RECORD_REPLAY_TEST_SCRIPT: testScript,
- RECORD_REPLAY_LOCAL_TEST: local,
- RECORD_REPLAY_NO_UPDATE: "1",
- RECORD_REPLAY_SERVER: dispatchServer,
- RECORD_REPLAY_VIEW_HOST: "http://localhost:8080",
- },
- });
-
- let passed = false;
-
- // Recording ID of any viewer recording we've detected.
- let recordingId;
-
- const waiter = defer();
-
- function processOutput(data) {
- const match = /CreateRecording (.*?) (.*)/.exec(data.toString());
- if (match && match[2].startsWith("http://localhost:8080/view")) {
- recordingId = match[1];
- }
- if (match && match[2].startsWith("http://localhost:7998")) {
- const exampleRecordingId = match[1];
- const example = url.parse(match[2]).pathname.slice(1);
- console.log(`example`, exampleRecordingId, example, url.parse(match[2]));
+ const gecko = spawn(`${gInstallDir}/Contents/MacOS/replay`, ["-foreground", ...profileArgs], {
+ env: {
+ ...process.env,
+ ...env,
+ MOZ_CRASHREPORTER_AUTO_SUBMIT: "1",
+ RECORD_REPLAY_TEST_SCRIPT: testScript,
+ RECORD_REPLAY_LOCAL_TEST: local,
+ RECORD_REPLAY_NO_UPDATE: "1",
+ RECORD_REPLAY_SERVER: dispatchServer,
+ RECORD_REPLAY_VIEW_HOST: "http://localhost:8080",
+ },
+ });
+
+ let passed = false;
+
+ // Recording ID of any viewer recording we've detected.
+ let recordingId;
+
+ const waiter = defer();
+
+ function processOutput(data) {
+ const match = /CreateRecording (.*?) (.*)/.exec(data.toString());
+ if (match && match[2].startsWith("http://localhost:8080/view")) {
+ recordingId = match[1];
+ }
+ if (match && match[2].startsWith("http://localhost:7998")) {
+ const exampleRecordingId = match[1];
+ const example = url.parse(match[2]).pathname.slice(1);
+ console.log(`example`, exampleRecordingId, example, url.parse(match[2]));
- const newExampleRecordings = { ...ExampleRecordings, [example]: exampleRecordingId };
+ const newExampleRecordings = { ...ExampleRecordings, [example]: exampleRecordingId };
- fs.writeFileSync(
- "./test/example-recordings.json",
- JSON.stringify(newExampleRecordings, null, 2)
- );
- }
+ fs.writeFileSync(
+ "./test/example-recordings.json",
+ JSON.stringify(newExampleRecordings, null, 2)
+ );
+ }
- if (/TestPassed/.test(data.toString())) {
- passed = true;
- }
- process.stdout.write(data);
+ if (/TestPassed/.test(data.toString())) {
+ passed = true;
}
+ process.stdout.write(data);
+ }
- function logFailure(why) {
- failures.push[`Failed test: ${local} ${why}`];
- console.log(`[${elapsedTime()}] Test failed: ${why}`);
+ function logFailure(why) {
+ failures.push[`Failed test: ${local} ${why}`];
+ console.log(`[${elapsedTime()}] Test failed: ${why}`);
- // Log an error which github will recognize.
- let msg = `::error ::Failure ${local}`;
- if (recordingId) {
- msg += ` https://replay.io/view?id=${recordingId}`;
- }
- spawnChecked("echo", [msg], { stdio: "inherit" });
+ // Log an error which github will recognize.
+ let msg = `::error ::Failure ${local}`;
+ if (recordingId) {
+ msg += ` https://replay.io/view?id=${recordingId}`;
}
+ spawnChecked("echo", [msg], { stdio: "inherit" });
+ }
- gecko.stdout.on("data", processOutput);
- gecko.stderr.on("data", processOutput);
-
- let timedOut = false;
- let closed = false;
- gecko.on("close", code => {
- closed = true;
- if (!timedOut) {
- if (code) {
- logFailure(`Exited with code ${code}`);
- } else if (!passed) {
- logFailure("Exited without passing test");
- }
+ gecko.stdout.on("data", processOutput);
+ gecko.stderr.on("data", processOutput);
+
+ let timedOut = false;
+ let closed = false;
+ gecko.on("close", code => {
+ closed = true;
+ if (!timedOut) {
+ if (code) {
+ logFailure(`Exited with code ${code}`);
+ } else if (!passed) {
+ logFailure("Exited without passing test");
}
- waiter.resolve();
- });
-
- if (!process.env.RECORD_REPLAY_NO_TIMEOUT) {
- setTimeout(() => {
- if (!closed) {
- logFailure("Timed out");
- timedOut = true;
- gecko.kill();
- }
- }, timeout * 1000);
}
-
- await waiter.promise;
+ waiter.resolve();
+ });
+
+ if (!process.env.RECORD_REPLAY_NO_TIMEOUT) {
+ setTimeout(() => {
+ if (!closed) {
+ logFailure("Timed out");
+ timedOut = true;
+ gecko.kill();
+ }
+ }, timeout * 1000);
}
- function spawnChecked(...args) {
- const rv = spawnSync.apply(this, args);
- if (rv.status != 0 || rv.error) {
- throw new Error("Spawned process failed");
- }
+ await waiter.promise;
+}
+
+function spawnChecked(...args) {
+ const rv = spawnSync.apply(this, args);
+ if (rv.status != 0 || rv.error) {
+ throw new Error("Spawned process failed");
}
+}
- (async function () {
- processArgs(argsObject);
- processEnvironmentVariables();
- startExampleServer();
+async function startTestRunner(argsObject) {
+ processArgs(argsObject);
+ processEnvironmentVariables();
+ startExampleServer();
- for (let i = 0; i < count; i++) {
- await runMatchingTests();
- }
+ for (let i = 0; i < count; i++) {
+ await runMatchingTests();
+ }
- if (failures.length) {
- console.log(`[${elapsedTime()}] Had ${failures.length} test failures.`);
- failures.forEach(failure => console.log(failure));
- } else {
- console.log(`[${elapsedTime()}] All tests passed.`);
- }
+ if (failures.length) {
+ console.log(`[${elapsedTime()}] Had ${failures.length} test failures.`);
+ failures.forEach(failure => console.log(failure));
+ } else {
+ console.log(`[${elapsedTime()}] All tests passed.`);
+ }
- process.exit(failures.length ? 1 : 0);
- })();
+ process.exit(failures.length ? 1 : 0);
}
module.exports = startTestRunner;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment