| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109 | 
							- /*
 
-  * Copyright 2014 Mozilla Foundation
 
-  *
 
-  * Licensed under the Apache License, Version 2.0 (the "License");
 
-  * you may not use this file except in compliance with the License.
 
-  * You may obtain a copy of the License at
 
-  *
 
-  *     http://www.apache.org/licenses/LICENSE-2.0
 
-  *
 
-  * Unless required by applicable law or agreed to in writing, software
 
-  * distributed under the License is distributed on an "AS IS" BASIS,
 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-  * See the License for the specific language governing permissions and
 
-  * limitations under the License.
 
-  */
 
- /* eslint-disable no-var, unicorn/prefer-at */
 
- "use strict";
 
- var WebServer = require("./webserver.js").WebServer;
 
- var path = require("path");
 
- var fs = require("fs");
 
- var os = require("os");
 
- var puppeteer = require("puppeteer");
 
- var url = require("url");
 
- var testUtils = require("./testutils.js");
 
- const dns = require("dns");
 
- const readline = require("readline");
 
- const yargs = require("yargs");
 
- // Chrome uses host `127.0.0.1` in the browser's websocket endpoint URL while
 
- // Firefox uses `localhost`, which before Node.js 17 also resolved to the IPv4
 
- // address `127.0.0.1` by Node.js' DNS resolver. However, this behavior changed
 
- // in Node.js 17 where the default is to prefer an IPv6 address if one is
 
- // offered (which varies based on the OS and/or how the `localhost` hostname
 
- // resolution is configured), so it can now also resolve to `::1`. This causes
 
- // Firefox to not start anymore since it doesn't bind on the `::1` interface.
 
- // To avoid this, we switch Node.js' DNS resolver back to preferring IPv4
 
- // since we connect to a local browser anyway. Only do this for Node.js versions
 
- // that actually have this API since it got introduced in Node.js 14.18.0 and
 
- // it's not relevant for older versions anyway.
 
- if (dns.setDefaultResultOrder !== undefined) {
 
-   dns.setDefaultResultOrder("ipv4first");
 
- }
 
- function parseOptions() {
 
-   yargs
 
-     .usage("Usage: $0")
 
-     .option("downloadOnly", {
 
-       default: false,
 
-       describe: "Download test PDFs without running the tests.",
 
-       type: "boolean",
 
-     })
 
-     .option("fontTest", {
 
-       default: false,
 
-       describe: "Run the font tests.",
 
-       type: "boolean",
 
-     })
 
-     .option("help", {
 
-       alias: "h",
 
-       default: false,
 
-       describe: "Show this help message.",
 
-       type: "boolean",
 
-     })
 
-     .option("integration", {
 
-       default: false,
 
-       describe: "Run the integration tests.",
 
-       type: "boolean",
 
-     })
 
-     .option("manifestFile", {
 
-       default: "test_manifest.json",
 
-       describe: "A path to JSON file in the form of `test_manifest.json`.",
 
-       type: "string",
 
-     })
 
-     .option("masterMode", {
 
-       alias: "m",
 
-       default: false,
 
-       describe: "Run the script in master mode.",
 
-       type: "boolean",
 
-     })
 
-     .option("noChrome", {
 
-       default: false,
 
-       describe: "Skip Chrome when running tests.",
 
-       type: "boolean",
 
-     })
 
-     .option("noDownload", {
 
-       default: false,
 
-       describe: "Skip downloading of test PDFs.",
 
-       type: "boolean",
 
-     })
 
-     .option("noPrompts", {
 
-       default: false,
 
-       describe: "Uses default answers (intended for CLOUD TESTS only!).",
 
-       type: "boolean",
 
-     })
 
-     .option("port", {
 
-       default: 0,
 
-       describe: "The port the HTTP server should listen on.",
 
-       type: "number",
 
-     })
 
-     .option("reftest", {
 
-       default: false,
 
-       describe:
 
-         "Automatically start reftest showing comparison test failures, if there are any.",
 
-       type: "boolean",
 
-     })
 
-     .option("statsDelay", {
 
-       default: 0,
 
-       describe:
 
-         "The amount of time in milliseconds the browser should wait before starting stats.",
 
-       type: "number",
 
-     })
 
-     .option("statsFile", {
 
-       default: "",
 
-       describe: "The file where to store stats.",
 
-       type: "string",
 
-     })
 
-     .option("strictVerify", {
 
-       default: false,
 
-       describe: "Error if verifying the manifest files fails.",
 
-       type: "boolean",
 
-     })
 
-     .option("testfilter", {
 
-       alias: "t",
 
-       default: [],
 
-       describe: "Run specific reftest(s).",
 
-       type: "array",
 
-     })
 
-     .example(
 
-       "testfilter",
 
-       "$0 -t=issue5567 -t=issue5909\n" +
 
-         "Run the reftest identified by issue5567 and issue5909."
 
-     )
 
-     .option("unitTest", {
 
-       default: false,
 
-       describe: "Run the unit tests.",
 
-       type: "boolean",
 
-     })
 
-     .option("xfaOnly", {
 
-       default: false,
 
-       describe: "Only run the XFA reftest(s).",
 
-       type: "boolean",
 
-     })
 
-     .check(argv => {
 
-       if (
 
-         +argv.reftest + argv.unitTest + argv.fontTest + argv.masterMode <=
 
-         1
 
-       ) {
 
-         return true;
 
-       }
 
-       throw new Error(
 
-         "--reftest, --unitTest, --fontTest, and --masterMode must not be specified together."
 
-       );
 
-     })
 
-     .check(argv => {
 
-       if (
 
-         +argv.unitTest + argv.fontTest + argv.integration + argv.xfaOnly <=
 
-         1
 
-       ) {
 
-         return true;
 
-       }
 
-       throw new Error(
 
-         "--unitTest, --fontTest, --integration, and --xfaOnly must not be specified together."
 
-       );
 
-     })
 
-     .check(argv => {
 
-       if (argv.testfilter && argv.testfilter.length > 0 && argv.xfaOnly) {
 
-         throw new Error("--testfilter and --xfaOnly cannot be used together.");
 
-       }
 
-       return true;
 
-     })
 
-     .check(argv => {
 
-       if (!argv.noDownload || !argv.downloadOnly) {
 
-         return true;
 
-       }
 
-       throw new Error(
 
-         "--noDownload and --downloadOnly cannot be used together."
 
-       );
 
-     })
 
-     .check(argv => {
 
-       if (!argv.masterMode || argv.manifestFile === "test_manifest.json") {
 
-         return true;
 
-       }
 
-       throw new Error(
 
-         "when --masterMode is specified --manifestFile shall be equal to `test_manifest.json`."
 
-       );
 
-     });
 
-   const result = yargs.argv;
 
-   if (result.help) {
 
-     yargs.showHelp();
 
-     process.exit(0);
 
-   }
 
-   result.testfilter = Array.isArray(result.testfilter)
 
-     ? result.testfilter
 
-     : [result.testfilter];
 
-   return result;
 
- }
 
- var refsTmpDir = "tmp";
 
- var testResultDir = "test_snapshots";
 
- var refsDir = "ref";
 
- var eqLog = "eq.log";
 
- var browserTimeout = 120;
 
- function monitorBrowserTimeout(session, onTimeout) {
 
-   if (session.timeoutMonitor) {
 
-     clearTimeout(session.timeoutMonitor);
 
-   }
 
-   if (!onTimeout) {
 
-     session.timeoutMonitor = null;
 
-     return;
 
-   }
 
-   session.timeoutMonitor = setTimeout(function () {
 
-     onTimeout(session);
 
-   }, browserTimeout * 1000);
 
- }
 
- function updateRefImages() {
 
-   function sync(removeTmp) {
 
-     console.log("  Updating ref/ ... ");
 
-     testUtils.copySubtreeSync(refsTmpDir, refsDir);
 
-     if (removeTmp) {
 
-       testUtils.removeDirSync(refsTmpDir);
 
-     }
 
-     console.log("done");
 
-   }
 
-   if (options.noPrompts) {
 
-     sync(false); // don't remove tmp/ for botio
 
-     return;
 
-   }
 
-   const reader = readline.createInterface(process.stdin, process.stdout);
 
-   reader.question(
 
-     "Would you like to update the master copy in ref/? [yn] ",
 
-     function (answer) {
 
-       if (answer.toLowerCase() === "y") {
 
-         sync(true);
 
-       } else {
 
-         console.log("  OK, not updating.");
 
-       }
 
-       reader.close();
 
-     }
 
-   );
 
- }
 
- function examineRefImages() {
 
-   startServer();
 
-   const startUrl = `http://${host}:${server.port}/test/resources/reftest-analyzer.html#web=/test/eq.log`;
 
-   startBrowser("firefox", startUrl).then(function (browser) {
 
-     browser.on("disconnected", function () {
 
-       stopServer();
 
-       process.exit(0);
 
-     });
 
-   });
 
- }
 
- function startRefTest(masterMode, showRefImages) {
 
-   function finalize() {
 
-     stopServer();
 
-     var numErrors = 0;
 
-     var numFBFFailures = 0;
 
-     var numEqFailures = 0;
 
-     var numEqNoSnapshot = 0;
 
-     sessions.forEach(function (session) {
 
-       numErrors += session.numErrors;
 
-       numFBFFailures += session.numFBFFailures;
 
-       numEqFailures += session.numEqFailures;
 
-       numEqNoSnapshot += session.numEqNoSnapshot;
 
-     });
 
-     var numFatalFailures = numErrors + numFBFFailures;
 
-     console.log();
 
-     if (numFatalFailures + numEqFailures > 0) {
 
-       console.log("OHNOES!  Some tests failed!");
 
-       if (numErrors > 0) {
 
-         console.log("  errors: " + numErrors);
 
-       }
 
-       if (numEqFailures > 0) {
 
-         console.log("  different ref/snapshot: " + numEqFailures);
 
-       }
 
-       if (numFBFFailures > 0) {
 
-         console.log("  different first/second rendering: " + numFBFFailures);
 
-       }
 
-     } else {
 
-       console.log("All regression tests passed.");
 
-     }
 
-     var runtime = (Date.now() - startTime) / 1000;
 
-     console.log("Runtime was " + runtime.toFixed(1) + " seconds");
 
-     if (options.statsFile) {
 
-       fs.writeFileSync(options.statsFile, JSON.stringify(stats, null, 2));
 
-     }
 
-     if (masterMode) {
 
-       if (numEqFailures + numEqNoSnapshot > 0) {
 
-         console.log();
 
-         console.log("Some eq tests failed or didn't have snapshots.");
 
-         console.log("Checking to see if master references can be updated...");
 
-         if (numFatalFailures > 0) {
 
-           console.log("  No.  Some non-eq tests failed.");
 
-         } else {
 
-           console.log(
 
-             "  Yes!  The references in tmp/ can be synced with ref/."
 
-           );
 
-           updateRefImages();
 
-         }
 
-       }
 
-     } else if (showRefImages && numEqFailures > 0) {
 
-       console.log();
 
-       console.log(
 
-         `Starting reftest harness to examine ${numEqFailures} eq test failures.`
 
-       );
 
-       examineRefImages();
 
-     }
 
-   }
 
-   function setup() {
 
-     if (fs.existsSync(refsTmpDir)) {
 
-       console.error("tmp/ exists -- unable to proceed with testing");
 
-       process.exit(1);
 
-     }
 
-     if (fs.existsSync(eqLog)) {
 
-       fs.unlinkSync(eqLog);
 
-     }
 
-     if (fs.existsSync(testResultDir)) {
 
-       testUtils.removeDirSync(testResultDir);
 
-     }
 
-     startTime = Date.now();
 
-     startServer();
 
-     server.hooks.POST.push(refTestPostHandler);
 
-     onAllSessionsClosed = finalize;
 
-     const startUrl = `http://${host}:${server.port}/test/test_slave.html`;
 
-     startBrowsers(function (session) {
 
-       session.masterMode = masterMode;
 
-       session.taskResults = {};
 
-       session.tasks = {};
 
-       session.remaining = manifest.length;
 
-       manifest.forEach(function (item) {
 
-         var rounds = item.rounds || 1;
 
-         var roundsResults = [];
 
-         roundsResults.length = rounds;
 
-         session.taskResults[item.id] = roundsResults;
 
-         session.tasks[item.id] = item;
 
-       });
 
-       session.numErrors = 0;
 
-       session.numFBFFailures = 0;
 
-       session.numEqNoSnapshot = 0;
 
-       session.numEqFailures = 0;
 
-       monitorBrowserTimeout(session, handleSessionTimeout);
 
-     }, makeTestUrl(startUrl));
 
-   }
 
-   function checkRefsTmp() {
 
-     if (masterMode && fs.existsSync(refsTmpDir)) {
 
-       if (options.noPrompts) {
 
-         testUtils.removeDirSync(refsTmpDir);
 
-         setup();
 
-         return;
 
-       }
 
-       console.log("Temporary snapshot dir tmp/ is still around.");
 
-       console.log("tmp/ can be removed if it has nothing you need.");
 
-       const reader = readline.createInterface(process.stdin, process.stdout);
 
-       reader.question(
 
-         "SHOULD THIS SCRIPT REMOVE tmp/? THINK CAREFULLY [yn] ",
 
-         function (answer) {
 
-           if (answer.toLowerCase() === "y") {
 
-             testUtils.removeDirSync(refsTmpDir);
 
-           }
 
-           setup();
 
-           reader.close();
 
-         }
 
-       );
 
-     } else {
 
-       setup();
 
-     }
 
-   }
 
-   var startTime;
 
-   var manifest = getTestManifest();
 
-   if (!manifest) {
 
-     return;
 
-   }
 
-   if (options.noDownload) {
 
-     checkRefsTmp();
 
-   } else {
 
-     ensurePDFsDownloaded(checkRefsTmp);
 
-   }
 
- }
 
- function handleSessionTimeout(session) {
 
-   if (session.closed) {
 
-     return;
 
-   }
 
-   var browser = session.name;
 
-   console.log(
 
-     "TEST-UNEXPECTED-FAIL | test failed " +
 
-       browser +
 
-       " has not responded in " +
 
-       browserTimeout +
 
-       "s"
 
-   );
 
-   session.numErrors += session.remaining;
 
-   session.remaining = 0;
 
-   closeSession(browser);
 
- }
 
- function getTestManifest() {
 
-   var manifest = JSON.parse(fs.readFileSync(options.manifestFile));
 
-   const testFilter = options.testfilter.slice(0),
 
-     xfaOnly = options.xfaOnly;
 
-   if (testFilter.length || xfaOnly) {
 
-     manifest = manifest.filter(function (item) {
 
-       var i = testFilter.indexOf(item.id);
 
-       if (i !== -1) {
 
-         testFilter.splice(i, 1);
 
-         return true;
 
-       }
 
-       if (xfaOnly && item.enableXfa) {
 
-         return true;
 
-       }
 
-       return false;
 
-     });
 
-     if (testFilter.length) {
 
-       console.error("Unrecognized test IDs: " + testFilter.join(" "));
 
-       return undefined;
 
-     }
 
-   }
 
-   return manifest;
 
- }
 
- function checkEq(task, results, browser, masterMode) {
 
-   var taskId = task.id;
 
-   var refSnapshotDir = path.join(refsDir, os.platform(), browser, taskId);
 
-   var testSnapshotDir = path.join(
 
-     testResultDir,
 
-     os.platform(),
 
-     browser,
 
-     taskId
 
-   );
 
-   var pageResults = results[0];
 
-   var taskType = task.type;
 
-   var numEqNoSnapshot = 0;
 
-   var numEqFailures = 0;
 
-   for (var page = 0; page < pageResults.length; page++) {
 
-     if (!pageResults[page]) {
 
-       continue;
 
-     }
 
-     const pageResult = pageResults[page];
 
-     let testSnapshot = pageResult.snapshot;
 
-     if (testSnapshot && testSnapshot.startsWith("data:image/png;base64,")) {
 
-       testSnapshot = Buffer.from(testSnapshot.substring(22), "base64");
 
-     } else {
 
-       console.error("Valid snapshot was not found.");
 
-     }
 
-     var refSnapshot = null;
 
-     var eq = false;
 
-     var refPath = path.join(refSnapshotDir, page + 1 + ".png");
 
-     if (!fs.existsSync(refPath)) {
 
-       numEqNoSnapshot++;
 
-       if (!masterMode) {
 
-         console.log("WARNING: no reference snapshot " + refPath);
 
-       }
 
-     } else {
 
-       refSnapshot = fs.readFileSync(refPath);
 
-       eq = refSnapshot.toString("hex") === testSnapshot.toString("hex");
 
-       if (!eq) {
 
-         console.log(
 
-           "TEST-UNEXPECTED-FAIL | " +
 
-             taskType +
 
-             " " +
 
-             taskId +
 
-             " | in " +
 
-             browser +
 
-             " | rendering of page " +
 
-             (page + 1) +
 
-             " != reference rendering"
 
-         );
 
-         testUtils.ensureDirSync(testSnapshotDir);
 
-         fs.writeFileSync(
 
-           path.join(testSnapshotDir, page + 1 + ".png"),
 
-           testSnapshot
 
-         );
 
-         fs.writeFileSync(
 
-           path.join(testSnapshotDir, page + 1 + "_ref.png"),
 
-           refSnapshot
 
-         );
 
-         // This no longer follows the format of Mozilla reftest output.
 
-         const viewportString = `(${pageResult.viewportWidth}x${pageResult.viewportHeight}x${pageResult.outputScale})`;
 
-         fs.appendFileSync(
 
-           eqLog,
 
-           "REFTEST TEST-UNEXPECTED-FAIL | " +
 
-             browser +
 
-             "-" +
 
-             taskId +
 
-             "-page" +
 
-             (page + 1) +
 
-             " | image comparison (==)\n" +
 
-             `REFTEST   IMAGE 1 (TEST)${viewportString}: ` +
 
-             path.join(testSnapshotDir, page + 1 + ".png") +
 
-             "\n" +
 
-             `REFTEST   IMAGE 2 (REFERENCE)${viewportString}: ` +
 
-             path.join(testSnapshotDir, page + 1 + "_ref.png") +
 
-             "\n"
 
-         );
 
-         numEqFailures++;
 
-       }
 
-     }
 
-     if (masterMode && (!refSnapshot || !eq)) {
 
-       var tmpSnapshotDir = path.join(
 
-         refsTmpDir,
 
-         os.platform(),
 
-         browser,
 
-         taskId
 
-       );
 
-       testUtils.ensureDirSync(tmpSnapshotDir);
 
-       fs.writeFileSync(
 
-         path.join(tmpSnapshotDir, page + 1 + ".png"),
 
-         testSnapshot
 
-       );
 
-     }
 
-   }
 
-   var session = getSession(browser);
 
-   session.numEqNoSnapshot += numEqNoSnapshot;
 
-   if (numEqFailures > 0) {
 
-     session.numEqFailures += numEqFailures;
 
-   } else {
 
-     console.log(
 
-       "TEST-PASS | " + taskType + " test " + taskId + " | in " + browser
 
-     );
 
-   }
 
- }
 
- function checkFBF(task, results, browser, masterMode) {
 
-   var numFBFFailures = 0;
 
-   var round0 = results[0],
 
-     round1 = results[1];
 
-   if (round0.length !== round1.length) {
 
-     console.error("round 1 and 2 sizes are different");
 
-   }
 
-   for (var page = 0; page < round1.length; page++) {
 
-     var r0Page = round0[page],
 
-       r1Page = round1[page];
 
-     if (!r0Page) {
 
-       continue;
 
-     }
 
-     if (r0Page.snapshot !== r1Page.snapshot) {
 
-       // The FBF tests fail intermittently in Firefox and Google Chrome when run
 
-       // on the bots, ignoring `makeref` failures for now; see
 
-       //  - https://github.com/mozilla/pdf.js/pull/12368
 
-       //  - https://github.com/mozilla/pdf.js/pull/11491
 
-       //
 
-       // TODO: Figure out why this happens, so that we can remove the hack; see
 
-       //       https://github.com/mozilla/pdf.js/issues/12371
 
-       if (masterMode) {
 
-         console.log(
 
-           "TEST-SKIPPED | forward-back-forward test " +
 
-             task.id +
 
-             " | in " +
 
-             browser +
 
-             " | page" +
 
-             (page + 1)
 
-         );
 
-         continue;
 
-       }
 
-       console.log(
 
-         "TEST-UNEXPECTED-FAIL | forward-back-forward test " +
 
-           task.id +
 
-           " | in " +
 
-           browser +
 
-           " | first rendering of page " +
 
-           (page + 1) +
 
-           " != second"
 
-       );
 
-       numFBFFailures++;
 
-     }
 
-   }
 
-   if (numFBFFailures > 0) {
 
-     getSession(browser).numFBFFailures += numFBFFailures;
 
-   } else {
 
-     console.log(
 
-       "TEST-PASS | forward-back-forward test " + task.id + " | in " + browser
 
-     );
 
-   }
 
- }
 
- function checkLoad(task, results, browser) {
 
-   // Load just checks for absence of failure, so if we got here the
 
-   // test has passed
 
-   console.log("TEST-PASS | load test " + task.id + " | in " + browser);
 
- }
 
- function checkRefTestResults(browser, id, results) {
 
-   var failed = false;
 
-   var session = getSession(browser);
 
-   var task = session.tasks[id];
 
-   results.forEach(function (roundResults, round) {
 
-     roundResults.forEach(function (pageResult, page) {
 
-       if (!pageResult) {
 
-         return; // no results
 
-       }
 
-       if (pageResult.failure) {
 
-         failed = true;
 
-         if (fs.existsSync(task.file + ".error")) {
 
-           console.log(
 
-             "TEST-SKIPPED | PDF was not downloaded " +
 
-               id +
 
-               " | in " +
 
-               browser +
 
-               " | page" +
 
-               (page + 1) +
 
-               " round " +
 
-               (round + 1) +
 
-               " | " +
 
-               pageResult.failure
 
-           );
 
-         } else {
 
-           session.numErrors++;
 
-           console.log(
 
-             "TEST-UNEXPECTED-FAIL | test failed " +
 
-               id +
 
-               " | in " +
 
-               browser +
 
-               " | page" +
 
-               (page + 1) +
 
-               " round " +
 
-               (round + 1) +
 
-               " | " +
 
-               pageResult.failure
 
-           );
 
-         }
 
-       }
 
-     });
 
-   });
 
-   if (failed) {
 
-     return;
 
-   }
 
-   switch (task.type) {
 
-     case "eq":
 
-     case "text":
 
-       checkEq(task, results, browser, session.masterMode);
 
-       break;
 
-     case "fbf":
 
-       checkFBF(task, results, browser, session.masterMode);
 
-       break;
 
-     case "load":
 
-       checkLoad(task, results, browser);
 
-       break;
 
-     default:
 
-       throw new Error("Unknown test type");
 
-   }
 
-   // clear memory
 
-   results.forEach(function (roundResults, round) {
 
-     roundResults.forEach(function (pageResult, page) {
 
-       pageResult.snapshot = null;
 
-     });
 
-   });
 
- }
 
- function refTestPostHandler(req, res) {
 
-   var parsedUrl = url.parse(req.url, true);
 
-   var pathname = parsedUrl.pathname;
 
-   if (
 
-     pathname !== "/tellMeToQuit" &&
 
-     pathname !== "/info" &&
 
-     pathname !== "/submit_task_results"
 
-   ) {
 
-     return false;
 
-   }
 
-   var body = "";
 
-   req.on("data", function (data) {
 
-     body += data;
 
-   });
 
-   req.on("end", function () {
 
-     res.writeHead(200, { "Content-Type": "text/plain" });
 
-     res.end();
 
-     var session;
 
-     if (pathname === "/tellMeToQuit") {
 
-       session = getSession(parsedUrl.query.browser);
 
-       monitorBrowserTimeout(session, null);
 
-       closeSession(session.name);
 
-       return;
 
-     }
 
-     var data = JSON.parse(body);
 
-     if (pathname === "/info") {
 
-       console.log(data.message);
 
-       return;
 
-     }
 
-     var browser = data.browser;
 
-     var round = data.round;
 
-     var id = data.id;
 
-     var page = data.page - 1;
 
-     var failure = data.failure;
 
-     var snapshot = data.snapshot;
 
-     var lastPageNum = data.lastPageNum;
 
-     session = getSession(browser);
 
-     monitorBrowserTimeout(session, handleSessionTimeout);
 
-     var taskResults = session.taskResults[id];
 
-     if (!taskResults[round]) {
 
-       taskResults[round] = [];
 
-     }
 
-     if (taskResults[round][page]) {
 
-       console.error(
 
-         "Results for " +
 
-           browser +
 
-           ":" +
 
-           id +
 
-           ":" +
 
-           round +
 
-           ":" +
 
-           page +
 
-           " were already submitted"
 
-       );
 
-       // TODO abort testing here?
 
-     }
 
-     taskResults[round][page] = {
 
-       failure,
 
-       snapshot,
 
-       viewportWidth: data.viewportWidth,
 
-       viewportHeight: data.viewportHeight,
 
-       outputScale: data.outputScale,
 
-     };
 
-     if (stats) {
 
-       stats.push({
 
-         browser,
 
-         pdf: id,
 
-         page,
 
-         round,
 
-         stats: data.stats,
 
-       });
 
-     }
 
-     var isDone =
 
-       taskResults[taskResults.length - 1] &&
 
-       taskResults[taskResults.length - 1][lastPageNum - 1];
 
-     if (isDone) {
 
-       checkRefTestResults(browser, id, taskResults);
 
-       session.remaining--;
 
-     }
 
-   });
 
-   return true;
 
- }
 
- function onAllSessionsClosedAfterTests(name) {
 
-   const startTime = Date.now();
 
-   return function () {
 
-     stopServer();
 
-     var numRuns = 0,
 
-       numErrors = 0;
 
-     sessions.forEach(function (session) {
 
-       numRuns += session.numRuns;
 
-       numErrors += session.numErrors;
 
-     });
 
-     console.log();
 
-     console.log("Run " + numRuns + " tests");
 
-     if (numErrors > 0) {
 
-       console.log("OHNOES!  Some " + name + " tests failed!");
 
-       console.log("  " + numErrors + " of " + numRuns + " failed");
 
-     } else {
 
-       console.log("All " + name + " tests passed.");
 
-     }
 
-     var runtime = (Date.now() - startTime) / 1000;
 
-     console.log(name + " tests runtime was " + runtime.toFixed(1) + " seconds");
 
-   };
 
- }
 
- function makeTestUrl(startUrl) {
 
-   return function (browserName) {
 
-     const queryParameters =
 
-       `?browser=${encodeURIComponent(browserName)}` +
 
-       `&manifestFile=${encodeURIComponent("/test/" + options.manifestFile)}` +
 
-       `&testFilter=${JSON.stringify(options.testfilter)}` +
 
-       `&xfaOnly=${options.xfaOnly}` +
 
-       `&delay=${options.statsDelay}` +
 
-       `&masterMode=${options.masterMode}`;
 
-     return startUrl + queryParameters;
 
-   };
 
- }
 
- function startUnitTest(testUrl, name) {
 
-   onAllSessionsClosed = onAllSessionsClosedAfterTests(name);
 
-   startServer();
 
-   server.hooks.POST.push(unitTestPostHandler);
 
-   const startUrl = `http://${host}:${server.port}${testUrl}`;
 
-   startBrowsers(function (session) {
 
-     session.numRuns = 0;
 
-     session.numErrors = 0;
 
-   }, makeTestUrl(startUrl));
 
- }
 
- function startIntegrationTest() {
 
-   onAllSessionsClosed = onAllSessionsClosedAfterTests("integration");
 
-   startServer();
 
-   const { runTests } = require("./integration-boot.js");
 
-   startBrowsers(function (session) {
 
-     session.numRuns = 0;
 
-     session.numErrors = 0;
 
-   });
 
-   global.integrationBaseUrl = `http://${host}:${server.port}/build/generic/web/viewer.html`;
 
-   global.integrationSessions = sessions;
 
-   Promise.all(sessions.map(session => session.browserPromise)).then(
 
-     async () => {
 
-       const results = { runs: 0, failures: 0 };
 
-       await runTests(results);
 
-       sessions[0].numRuns = results.runs;
 
-       sessions[0].numErrors = results.failures;
 
-       await Promise.all(sessions.map(session => closeSession(session.name)));
 
-     }
 
-   );
 
- }
 
- function unitTestPostHandler(req, res) {
 
-   var parsedUrl = url.parse(req.url);
 
-   var pathname = parsedUrl.pathname;
 
-   if (
 
-     pathname !== "/tellMeToQuit" &&
 
-     pathname !== "/info" &&
 
-     pathname !== "/ttx" &&
 
-     pathname !== "/submit_task_results"
 
-   ) {
 
-     return false;
 
-   }
 
-   var body = "";
 
-   req.on("data", function (data) {
 
-     body += data;
 
-   });
 
-   req.on("end", function () {
 
-     if (pathname === "/ttx") {
 
-       var translateFont = require("./font/ttxdriver.js").translateFont;
 
-       var onCancel = null,
 
-         ttxTimeout = 10000;
 
-       var timeoutId = setTimeout(function () {
 
-         onCancel?.("TTX timeout");
 
-       }, ttxTimeout);
 
-       translateFont(
 
-         body,
 
-         function (fn) {
 
-           onCancel = fn;
 
-         },
 
-         function (err, xml) {
 
-           clearTimeout(timeoutId);
 
-           res.writeHead(200, { "Content-Type": "text/xml" });
 
-           res.end(err ? "<error>" + err + "</error>" : xml);
 
-         }
 
-       );
 
-       return;
 
-     }
 
-     res.writeHead(200, { "Content-Type": "text/plain" });
 
-     res.end();
 
-     var data = JSON.parse(body);
 
-     if (pathname === "/tellMeToQuit") {
 
-       closeSession(data.browser);
 
-       return;
 
-     }
 
-     if (pathname === "/info") {
 
-       console.log(data.message);
 
-       return;
 
-     }
 
-     var session = getSession(data.browser);
 
-     session.numRuns++;
 
-     var message =
 
-       data.status + " | " + data.description + " | in " + session.name;
 
-     if (data.status === "TEST-UNEXPECTED-FAIL") {
 
-       session.numErrors++;
 
-     }
 
-     if (data.error) {
 
-       message += " | " + data.error;
 
-     }
 
-     console.log(message);
 
-   });
 
-   return true;
 
- }
 
- async function startBrowser(browserName, startUrl = "") {
 
-   const revisions =
 
-     require("puppeteer-core/lib/cjs/puppeteer/revisions.js").PUPPETEER_REVISIONS;
 
-   const wantedRevision =
 
-     browserName === "chrome" ? revisions.chromium : revisions.firefox;
 
-   // Remove other revisions than the one we want to use. Updating Puppeteer can
 
-   // cause a new revision to be used, and not removing older revisions causes
 
-   // the disk to fill up.
 
-   const browserFetcher = puppeteer.createBrowserFetcher({
 
-     product: browserName,
 
-   });
 
-   const localRevisions = await browserFetcher.localRevisions();
 
-   if (localRevisions.length > 1) {
 
-     for (const localRevision of localRevisions) {
 
-       if (localRevision !== wantedRevision) {
 
-         console.log(`Removing old ${browserName} revision ${localRevision}...`);
 
-         await browserFetcher.remove(localRevision);
 
-       }
 
-     }
 
-   }
 
-   const options = {
 
-     product: browserName,
 
-     headless: false,
 
-     defaultViewport: null,
 
-     ignoreDefaultArgs: ["--disable-extensions"],
 
-   };
 
-   if (!tempDir) {
 
-     tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pdfjs-"));
 
-   }
 
-   const printFile = path.join(tempDir, "print.pdf");
 
-   if (browserName === "chrome") {
 
-     // avoid crash
 
-     options.args = ["--no-sandbox", "--disable-setuid-sandbox"];
 
-     // silent printing in a pdf
 
-     options.args.push("--kiosk-printing");
 
-   }
 
-   if (browserName === "firefox") {
 
-     options.extraPrefsFirefox = {
 
-       // avoid to have a prompt when leaving a page with a form
 
-       "dom.disable_beforeunload": true,
 
-       // Disable dialog when saving a pdf
 
-       "pdfjs.disabled": true,
 
-       "browser.helperApps.neverAsk.saveToDisk": "application/pdf",
 
-       // Avoid popup when saving is done
 
-       "browser.download.always_ask_before_handling_new_types": true,
 
-       "browser.download.panel.shown": true,
 
-       "browser.download.alwaysOpenPanel": false,
 
-       // Save file in output
 
-       "browser.download.folderList": 2,
 
-       "browser.download.dir": tempDir,
 
-       // Print silently in a pdf
 
-       "print.always_print_silent": true,
 
-       "print.show_print_progress": false,
 
-       print_printer: "PDF",
 
-       "print.printer_PDF.print_to_file": true,
 
-       "print.printer_PDF.print_to_filename": printFile,
 
-       // Enable OffscreenCanvas
 
-       "gfx.offscreencanvas.enabled": true,
 
-       // Disable gpu acceleration
 
-       "gfx.canvas.accelerated": false,
 
-     };
 
-   }
 
-   const browser = await puppeteer.launch(options);
 
-   if (startUrl) {
 
-     const pages = await browser.pages();
 
-     const page = pages[0];
 
-     await page.goto(startUrl, { timeout: 0, waitUntil: "domcontentloaded" });
 
-   }
 
-   return browser;
 
- }
 
- function startBrowsers(initSessionCallback, makeStartUrl = null) {
 
-   const browserNames = options.noChrome ? ["firefox"] : ["firefox", "chrome"];
 
-   sessions = [];
 
-   for (const browserName of browserNames) {
 
-     // The session must be pushed first and augmented with the browser once
 
-     // it's initialized. The reason for this is that browser initialization
 
-     // takes more time when the browser is not found locally yet and we don't
 
-     // want `onAllSessionsClosed` to trigger if one of the browsers is done
 
-     // and the other one is still initializing, since that would mean that
 
-     // once the browser is initialized the server would have stopped already.
 
-     // Pushing the session first ensures that `onAllSessionsClosed` will
 
-     // only trigger once all browsers are initialized and done.
 
-     const session = {
 
-       name: browserName,
 
-       browser: undefined,
 
-       closed: false,
 
-     };
 
-     sessions.push(session);
 
-     const startUrl = makeStartUrl ? makeStartUrl(browserName) : "";
 
-     session.browserPromise = startBrowser(browserName, startUrl)
 
-       .then(function (browser) {
 
-         session.browser = browser;
 
-         initSessionCallback?.(session);
 
-       })
 
-       .catch(function (ex) {
 
-         console.log(`Error while starting ${browserName}: ${ex.message}`);
 
-         closeSession(browserName);
 
-       });
 
-   }
 
- }
 
- function startServer() {
 
-   server = new WebServer();
 
-   server.host = host;
 
-   server.port = options.port;
 
-   server.root = "..";
 
-   server.cacheExpirationTime = 3600;
 
-   server.start();
 
- }
 
- function stopServer() {
 
-   server.stop();
 
- }
 
- function getSession(browser) {
 
-   return sessions.find(session => session.name === browser);
 
- }
 
- async function closeSession(browser) {
 
-   for (const session of sessions) {
 
-     if (session.name !== browser) {
 
-       continue;
 
-     }
 
-     if (session.browser !== undefined) {
 
-       for (const page of await session.browser.pages()) {
 
-         await page.close();
 
-       }
 
-       await session.browser.close();
 
-     }
 
-     session.closed = true;
 
-     const allClosed = sessions.every(function (s) {
 
-       return s.closed;
 
-     });
 
-     if (allClosed) {
 
-       if (tempDir) {
 
-         const rimraf = require("rimraf");
 
-         rimraf.sync(tempDir);
 
-       }
 
-       onAllSessionsClosed?.();
 
-     }
 
-   }
 
- }
 
- function ensurePDFsDownloaded(callback) {
 
-   var downloadUtils = require("./downloadutils.js");
 
-   var manifest = getTestManifest();
 
-   downloadUtils.downloadManifestFiles(manifest, function () {
 
-     downloadUtils.verifyManifestFiles(manifest, function (hasErrors) {
 
-       if (hasErrors) {
 
-         console.log(
 
-           "Unable to verify the checksum for the files that are " +
 
-             "used for testing."
 
-         );
 
-         console.log(
 
-           "Please re-download the files, or adjust the MD5 " +
 
-             "checksum in the manifest for the files listed above.\n"
 
-         );
 
-         if (options.strictVerify) {
 
-           process.exit(1);
 
-         }
 
-       }
 
-       callback();
 
-     });
 
-   });
 
- }
 
- function main() {
 
-   if (options.statsFile) {
 
-     stats = [];
 
-   }
 
-   if (options.downloadOnly) {
 
-     ensurePDFsDownloaded(function () {});
 
-   } else if (options.unitTest) {
 
-     // Allows linked PDF files in unit-tests as well.
 
-     ensurePDFsDownloaded(function () {
 
-       startUnitTest("/test/unit/unit_test.html", "unit");
 
-     });
 
-   } else if (options.fontTest) {
 
-     startUnitTest("/test/font/font_test.html", "font");
 
-   } else if (options.integration) {
 
-     // Allows linked PDF files in integration-tests as well.
 
-     ensurePDFsDownloaded(function () {
 
-       startIntegrationTest();
 
-     });
 
-   } else {
 
-     startRefTest(options.masterMode, options.reftest);
 
-   }
 
- }
 
- var server;
 
- var sessions;
 
- var onAllSessionsClosed;
 
- var host = "127.0.0.1";
 
- var options = parseOptions();
 
- var stats;
 
- var tempDir = null;
 
- main();
 
 
  |