Skip to content

Commit

Permalink
test,tools: update wpt weekly
Browse files Browse the repository at this point in the history
  • Loading branch information
legendecas committed Nov 5, 2023
1 parent a5cd629 commit 96e7850
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 17 deletions.
59 changes: 59 additions & 0 deletions .github/workflows/update-wpt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# This workflow runs every night and tests various releases of Node.js
# (latest nightly, current, and two latest LTS release lines) against the
# `epochs/weekly` branch of WPT.

name: Weekly WPT roller

on:
workflow_dispatch:
schedule:
# This is 20 minutes after `epochs/weekly` branch is triggered to be created
# in WPT repo, every Monday.
# https://github.com/web-platform-tests/wpt/blob/master/.github/workflows/epochs.yml
- cron: 30 0 * * 1

env:
PYTHON_VERSION: '3.11'

permissions:
contents: read

jobs:
update-wpt:
if: github.repository == 'nodejs/node' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Environment Information
run: npx envinfo

- name: Set env.WPT_REVISION
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: echo "WPT_REVISION=$(gh api /repos/web-platform-tests/wpt/branches/epochs/weekly --jq '.commit.sha')" >> $GITHUB_ENV
- name: Rolling update wpt fixtures
run: ./tools/dep_updaters/update-wpt.sh

- name: Build
run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn"
- name: Update wpt status.json
run: make test-wpt-status-update

- uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5
# Creates a PR or update the Action's existing PR, or
# no-op if the base branch is already up-to-date.
env:
GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }}
with:
author: Node.js GitHub Bot <github-bot@iojs.org>
body: This is an automated patch update of wpt to ${{ env.WPT_REVISION }}.
branch: actions/update-wpt # Custom branch *just* for this Action.
labels: test
title: 'deps: update wpt to ${{ env.WPT_REVISION }}'
update-pull-request-title-and-body: true
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,13 @@ test-wpt-report:
-WPT_REPORT=1 $(PYTHON) tools/test.py --shell $(NODE) $(PARALLEL_ARGS) wpt
$(NODE) "$$PWD/tools/merge-wpt-reports.mjs"

.PHONY: test-wpt-status-update
test-wpt-status-update:
$(RM) -r out/wpt
mkdir -p out/wpt
-WPT_UPDATE_STATUS=1 $(PYTHON) tools/test.py --shell $(NODE) $(PARALLEL_ARGS) wpt
$(NODE) "$$PWD/tools/merge-wpt-reports.mjs"

.PHONY: test-internet
test-internet: all
$(PYTHON) tools/test.py $(PARALLEL_ARGS) internet
Expand Down
116 changes: 99 additions & 17 deletions test/common/wpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,16 @@ function codeUnitStr(char) {
}

class ReportResult {
constructor(name) {
/**
* Construct a ReportResult.
* @param {string} name test name shown in wpt.fyi, unique for every variants.
* @param {WPTTestSpec} spec
*/
constructor(name, spec) {
this.test = name;
this.status = 'OK';
this.subtests = [];
this.spec = spec;
}

addSubtest(name, status, message) {
Expand All @@ -82,14 +88,18 @@ class ReportResult {
finish(status) {
this.status = status ?? 'OK';
}

toJSON() {
return {
test: this.test,
status: this.status,
subtests: this.subtests,
};
}
}

// Generates a report that can be uploaded to wpt.fyi.
// Checkout https://github.com/web-platform-tests/wpt.fyi/tree/main/api#results-creation
// for more details.
class WPTReport {
constructor(path) {
this.filename = `report-${path.replaceAll('/', '-')}.json`;
class Report {
constructor() {
/** @type {Map<string, ReportResult>} */
this.results = new Map();
this.time_start = Date.now();
Expand All @@ -104,10 +114,21 @@ class WPTReport {
if (this.results.has(name)) {
return this.results.get(name);
}
const result = new ReportResult(name);
const result = new ReportResult(name, spec);
this.results.set(name, result);
return result;
}
}

// Generates a report that can be uploaded to wpt.fyi.
// Checkout https://github.com/web-platform-tests/wpt.fyi/tree/main/api#results-creation
// for more details.
class WPTReport extends Report {
constructor(path) {
super();
this.filename = `report-${path.replaceAll('/', '-')}.json`;
this.time_start = Date.now();
}

write() {
this.time_end = Date.now();
Expand Down Expand Up @@ -139,6 +160,42 @@ class WPTReport {
}
}

class WPTStatusUpdater extends Report {
constructor(testPath) {
super();
this.filepath = path.join('test/wpt/status', `${testPath}.json`);
this.statusFile = JSON.parse(fs.readFileSync(this.filepath, 'utf8'));
}

write() {
for (const result of this.results.values()) {
if (result.status !== 'OK') {
this.statusFile[result.spec.filename] ??= {
skip: 'WPT test auto rolling',
};
continue;
}
const failedSubtests = result.subtests.filter(it => it.status !== 'PASS');

Check failure on line 178 in test/common/wpt.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Expected parentheses around arrow function argument
if (failedSubtests.length === 0) {
continue;
}
const expectations = new Set(this.statusFile[result.spec.filename]?.fail?.expected);
failedSubtests.forEach((subtest) => {
expectations.add(subtest.name);
});
this.statusFile[result.spec.filename] = {
...(this.statusFile[result.spec.filename] ?? {}),
fail: {
note: this.statusFile[result.spec.filename]?.fail?.note ?? 'WPT test auto rolling',
expected: [...expectations].sort(),
},
};
}

fs.writeFileSync(this.filepath, JSON.stringify(this.statusFile, null, 2) + '\n');
}
}

// https://github.com/web-platform-tests/wpt/blob/HEAD/resources/testharness.js
// TODO: get rid of this half-baked harness in favor of the one
// pulled from WPT
Expand Down Expand Up @@ -513,6 +570,8 @@ class WPTRunner {

if (process.env.WPT_REPORT != null) {
this.report = new WPTReport(path);
} else if (process.env.WPT_UPDATE_STATUS != null) {
this.report = new WPTStatusUpdater(path);
}
}

Expand Down Expand Up @@ -624,6 +683,7 @@ class WPTRunner {
const run = limit(this.concurrency);

for (const spec of queue) {
const reportResult = this.report?.getResult(spec);
const content = spec.getContent();
const meta = spec.getMeta(content);

Expand All @@ -632,14 +692,33 @@ class WPTRunner {
const harnessPath = fixtures.path('wpt', 'resources', 'testharness.js');

// Scripts specified with the `// META: script=` header
const scriptsToRun = meta.script?.map((script) => {
const obj = {
filename: this.resource.toRealFilePath(relativePath, script),
code: this.resource.read(relativePath, script),
};
this.scriptsModifier?.(obj);
return obj;
}) ?? [];
let scriptsToRun

Check failure on line 695 in test/common/wpt.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Missing semicolon
try {
scriptsToRun = meta.script?.map((script) => {
const obj = {
filename: this.resource.toRealFilePath(relativePath, script),
code: this.resource.read(relativePath, script),
};
this.scriptsModifier?.(obj);
return obj;
}) ?? [];
} catch (err) {
// Generate a subtest failure for visibility.
// No need to record this synthetic failure with wpt.fyi.
this.fail(
spec,
{
status: NODE_UNCAUGHT,
name: 'Resource not found',
message: err.message,
stack: inspect(err),
},
kUncaught,
);
// Mark the whole test as failed in wpt.fyi report.
reportResult?.finish('ERROR');
continue;
}
// The actual test
const obj = {
code: content,
Expand Down Expand Up @@ -667,7 +746,6 @@ class WPTRunner {
this.inProgress.add(spec);
this.workers.set(spec, worker);

const reportResult = this.report?.getResult(spec);
worker.on('message', (message) => {
switch (message.type) {
case 'result':
Expand Down Expand Up @@ -776,6 +854,10 @@ class WPTRunner {
`${passed} passed, ${expectedFailures} expected failures,`,
`${failures.length} unexpected failures,`,
`${unexpectedPasses.length} unexpected passes`);
if (process.env.WPT_UPDATE_STATUS) {
// Exit the process normally if we are updating the status file.
return;
}
if (failures.length > 0) {
const file = path.join('test', 'wpt', 'status', `${this.path}.json`);
throw new Error(
Expand Down
9 changes: 9 additions & 0 deletions tools/dep_updaters/update-wpt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
set -e
# Shell script to update wpt test fixtures in the source tree to the most recent version.

BASE_DIR=$(cd "$(dirname "$0")/../.." && pwd)

cd "$BASE_DIR"
jq -r 'keys[]' "$BASE_DIR/test/fixtures/wpt/versions.json" | \
xargs -L 1 git node wpt --commit "$WPT_REVISION"

Check failure on line 9 in tools/dep_updaters/update-wpt.sh

View workflow job for this annotation

GitHub Actions / lint-sh

/home/runner/work/node/node/tools/dep_updaters/update-wpt.sh:9:37: WPT_REVISION is referenced but not assigned.

0 comments on commit 96e7850

Please sign in to comment.