2023-01-02 16:00:42 -05:00
|
|
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2022-05-18 16:00:11 -04:00
|
|
|
import { delay, join, ROOT_PATH, TextLineStream, toFileUrl } from "../util.js";
|
2021-06-14 07:48:57 -04:00
|
|
|
import { assert, denoBinary, ManifestTestOptions, runPy } from "./utils.ts";
|
2021-01-27 09:06:18 -05:00
|
|
|
import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.3-alpha2/deno-dom-wasm.ts";
|
|
|
|
|
|
|
|
export async function runWithTestUtil<T>(
|
|
|
|
verbose: boolean,
|
|
|
|
f: () => Promise<T>,
|
|
|
|
): Promise<T> {
|
2021-06-07 13:16:27 -04:00
|
|
|
const proc = runPy([
|
|
|
|
"wpt",
|
|
|
|
"serve",
|
|
|
|
"--config",
|
|
|
|
"../../tools/wpt/config.json",
|
|
|
|
], {
|
2021-01-27 09:06:18 -05:00
|
|
|
stdout: verbose ? "inherit" : "piped",
|
|
|
|
stderr: verbose ? "inherit" : "piped",
|
|
|
|
});
|
|
|
|
|
|
|
|
const start = performance.now();
|
|
|
|
while (true) {
|
|
|
|
await delay(1000);
|
|
|
|
try {
|
|
|
|
const req = await fetch("http://localhost:8000/");
|
|
|
|
await req.body?.cancel();
|
|
|
|
if (req.status == 200) {
|
|
|
|
break;
|
|
|
|
}
|
2021-05-18 11:24:01 -04:00
|
|
|
} catch (_err) {
|
2021-01-27 09:06:18 -05:00
|
|
|
// do nothing if this fails
|
|
|
|
}
|
|
|
|
const passedTime = performance.now() - start;
|
|
|
|
if (passedTime > 15000) {
|
2021-09-06 10:05:33 -04:00
|
|
|
proc.kill("SIGINT");
|
2022-05-18 16:00:11 -04:00
|
|
|
await proc.status;
|
2021-01-27 09:06:18 -05:00
|
|
|
throw new Error("Timed out while trying to start wpt test util.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose) console.log(`Started wpt test util.`);
|
|
|
|
|
|
|
|
try {
|
|
|
|
return await f();
|
|
|
|
} finally {
|
|
|
|
if (verbose) console.log("Killing wpt test util.");
|
2021-09-06 10:05:33 -04:00
|
|
|
proc.kill("SIGINT");
|
2022-05-18 16:00:11 -04:00
|
|
|
await proc.status;
|
2021-01-27 09:06:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface TestResult {
|
|
|
|
cases: TestCaseResult[];
|
2021-06-06 12:08:50 -04:00
|
|
|
harnessStatus: TestHarnessStatus | null;
|
|
|
|
duration: number;
|
2021-01-27 09:06:18 -05:00
|
|
|
status: number;
|
|
|
|
stderr: string;
|
|
|
|
}
|
|
|
|
|
2021-06-06 12:08:50 -04:00
|
|
|
export interface TestHarnessStatus {
|
|
|
|
status: number;
|
|
|
|
message: string | null;
|
|
|
|
stack: string | null;
|
|
|
|
}
|
|
|
|
|
2021-01-27 09:06:18 -05:00
|
|
|
export interface TestCaseResult {
|
|
|
|
name: string;
|
|
|
|
passed: boolean;
|
|
|
|
status: number;
|
|
|
|
message: string | null;
|
|
|
|
stack: string | null;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function runSingleTest(
|
|
|
|
url: URL,
|
2021-05-18 11:24:01 -04:00
|
|
|
_options: ManifestTestOptions,
|
2021-01-27 09:06:18 -05:00
|
|
|
reporter: (result: TestCaseResult) => void,
|
2022-01-06 05:24:37 -05:00
|
|
|
inspectBrk: boolean,
|
2023-03-02 17:05:17 -05:00
|
|
|
timeouts: { long: number; default: number },
|
2021-01-27 09:06:18 -05:00
|
|
|
): Promise<TestResult> {
|
2023-03-02 17:05:17 -05:00
|
|
|
const timeout = _options.timeout === "long"
|
|
|
|
? timeouts.long
|
|
|
|
: timeouts.default;
|
|
|
|
const filename = url.pathname.substring(
|
|
|
|
url.pathname.lastIndexOf("/") + 1,
|
|
|
|
url.pathname.indexOf("."),
|
|
|
|
);
|
|
|
|
const { title } = Object.fromEntries(_options.script_metadata || []);
|
2021-01-27 09:06:18 -05:00
|
|
|
const bundle = await generateBundle(url);
|
|
|
|
const tempFile = await Deno.makeTempFile({
|
|
|
|
prefix: "wpt-bundle-",
|
|
|
|
suffix: ".js",
|
|
|
|
});
|
|
|
|
|
2023-03-02 17:05:17 -05:00
|
|
|
let interval;
|
2021-06-24 15:07:36 -04:00
|
|
|
try {
|
|
|
|
await Deno.writeTextFile(tempFile, bundle);
|
|
|
|
|
|
|
|
const startTime = new Date().getTime();
|
|
|
|
|
2022-05-18 16:00:11 -04:00
|
|
|
const args = [
|
2022-01-06 05:24:37 -05:00
|
|
|
"run",
|
|
|
|
"-A",
|
|
|
|
"--unstable",
|
2022-05-18 16:00:11 -04:00
|
|
|
];
|
2022-01-06 05:24:37 -05:00
|
|
|
|
|
|
|
if (inspectBrk) {
|
2022-05-18 16:00:11 -04:00
|
|
|
args.push("--inspect-brk");
|
2022-01-06 05:24:37 -05:00
|
|
|
}
|
|
|
|
|
2022-05-18 16:00:11 -04:00
|
|
|
args.push(
|
2022-01-06 05:24:37 -05:00
|
|
|
"--enable-testing-features-do-not-use",
|
|
|
|
"--location",
|
|
|
|
url.toString(),
|
|
|
|
"--cert",
|
|
|
|
join(ROOT_PATH, `./tools/wpt/certs/cacert.pem`),
|
|
|
|
tempFile,
|
|
|
|
"[]",
|
|
|
|
);
|
|
|
|
|
2023-03-02 17:05:17 -05:00
|
|
|
const start = performance.now();
|
2022-12-02 08:43:17 -05:00
|
|
|
const proc = new Deno.Command(denoBinary(), {
|
2022-05-18 16:00:11 -04:00
|
|
|
args,
|
2021-06-24 15:07:36 -04:00
|
|
|
env: {
|
|
|
|
NO_COLOR: "1",
|
|
|
|
},
|
|
|
|
stdout: "null",
|
|
|
|
stderr: "piped",
|
2022-12-02 08:43:17 -05:00
|
|
|
}).spawn();
|
2021-06-24 15:07:36 -04:00
|
|
|
|
|
|
|
const cases = [];
|
|
|
|
let stderr = "";
|
|
|
|
|
|
|
|
let harnessStatus = null;
|
|
|
|
|
2022-05-18 16:00:11 -04:00
|
|
|
const lines = proc.stderr.pipeThrough(new TextDecoderStream()).pipeThrough(
|
|
|
|
new TextLineStream(),
|
|
|
|
);
|
2023-03-02 17:05:17 -05:00
|
|
|
interval = setInterval(() => {
|
|
|
|
const passedTime = performance.now() - start;
|
|
|
|
if (passedTime > timeout) {
|
|
|
|
proc.kill("SIGINT");
|
|
|
|
}
|
|
|
|
}, 1000);
|
2021-06-24 15:07:36 -04:00
|
|
|
for await (const line of lines) {
|
|
|
|
if (line.startsWith("{")) {
|
|
|
|
const data = JSON.parse(line);
|
|
|
|
const result = { ...data, passed: data.status == 0 };
|
2023-03-02 17:05:17 -05:00
|
|
|
if (/^Untitled( \d+)?$/.test(result.name)) {
|
|
|
|
result.name = `${title || filename}${result.name.slice(8)}`;
|
|
|
|
}
|
2021-06-24 15:07:36 -04:00
|
|
|
cases.push(result);
|
|
|
|
reporter(result);
|
|
|
|
} else if (line.startsWith("#$#$#{")) {
|
|
|
|
harnessStatus = JSON.parse(line.slice(5));
|
|
|
|
} else {
|
|
|
|
stderr += line + "\n";
|
|
|
|
console.error(line);
|
|
|
|
}
|
2021-01-27 09:06:18 -05:00
|
|
|
}
|
|
|
|
|
2021-06-24 15:07:36 -04:00
|
|
|
const duration = new Date().getTime() - startTime;
|
2021-06-06 12:08:50 -04:00
|
|
|
|
2022-05-18 16:00:11 -04:00
|
|
|
const { code } = await proc.status;
|
2021-06-24 15:07:36 -04:00
|
|
|
return {
|
|
|
|
status: code,
|
|
|
|
harnessStatus,
|
|
|
|
duration,
|
|
|
|
cases,
|
|
|
|
stderr,
|
|
|
|
};
|
|
|
|
} finally {
|
2023-03-02 17:05:17 -05:00
|
|
|
clearInterval(interval);
|
2021-06-24 15:07:36 -04:00
|
|
|
await Deno.remove(tempFile);
|
|
|
|
}
|
2021-01-27 09:06:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
async function generateBundle(location: URL): Promise<string> {
|
|
|
|
const res = await fetch(location);
|
|
|
|
const body = await res.text();
|
|
|
|
const doc = new DOMParser().parseFromString(body, "text/html");
|
|
|
|
assert(doc, "document should have been parsed");
|
|
|
|
const scripts = doc.getElementsByTagName("script");
|
2023-03-15 09:03:07 -04:00
|
|
|
const title = doc.getElementsByTagName("title")[0]?.childNodes[0].nodeValue;
|
2021-01-27 09:06:18 -05:00
|
|
|
const scriptContents = [];
|
2021-06-06 12:32:06 -04:00
|
|
|
let inlineScriptCount = 0;
|
2023-03-15 09:03:07 -04:00
|
|
|
if (title) {
|
|
|
|
const url = new URL(`#${inlineScriptCount}`, location);
|
|
|
|
inlineScriptCount++;
|
|
|
|
scriptContents.push([url.href, `globalThis.META_TITLE="${title}"`]);
|
|
|
|
}
|
2021-01-27 09:06:18 -05:00
|
|
|
for (const script of scripts) {
|
|
|
|
const src = script.getAttribute("src");
|
|
|
|
if (src === "/resources/testharnessreport.js") {
|
2021-06-06 12:32:06 -04:00
|
|
|
const url = toFileUrl(
|
|
|
|
join(ROOT_PATH, "./tools/wpt/testharnessreport.js"),
|
2021-01-27 09:06:18 -05:00
|
|
|
);
|
2021-06-06 12:32:06 -04:00
|
|
|
const contents = await Deno.readTextFile(url);
|
|
|
|
scriptContents.push([url.href, contents]);
|
2021-01-27 09:06:18 -05:00
|
|
|
} else if (src) {
|
2021-06-06 12:32:06 -04:00
|
|
|
const url = new URL(src, location);
|
|
|
|
const res = await fetch(url);
|
|
|
|
if (res.ok) {
|
|
|
|
const contents = await res.text();
|
|
|
|
scriptContents.push([url.href, contents]);
|
|
|
|
}
|
2021-01-27 09:06:18 -05:00
|
|
|
} else {
|
2021-06-06 12:32:06 -04:00
|
|
|
const url = new URL(`#${inlineScriptCount}`, location);
|
|
|
|
inlineScriptCount++;
|
|
|
|
scriptContents.push([url.href, script.textContent]);
|
2021-01-27 09:06:18 -05:00
|
|
|
}
|
|
|
|
}
|
2021-06-06 12:32:06 -04:00
|
|
|
|
2021-06-11 15:31:53 -04:00
|
|
|
return scriptContents.map(([url, contents]) => `
|
|
|
|
(function() {
|
2023-01-24 12:54:10 -05:00
|
|
|
const [_,err] = Deno[Deno.internal].core.evalContext(${
|
|
|
|
JSON.stringify(contents)
|
|
|
|
}, ${JSON.stringify(url)});
|
2021-06-11 15:31:53 -04:00
|
|
|
if (err !== null) {
|
|
|
|
throw err?.thrown;
|
|
|
|
}
|
|
|
|
})();`).join("\n");
|
2021-01-27 09:06:18 -05:00
|
|
|
}
|