Created
September 15, 2020 15:13
-
-
Save jasonLaster/2d0571e1239b2c654736b04001ab2b20 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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