Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/jtreg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,14 @@ jobs:
read -ra filters <<< "$FILTERS"
node scripts/jtreg/run.ts build/ref/jdk25u --only-passing --jobs 4 --timeout 600 \
--shard ${{ matrix.shard }}/${{ strategy.job-total }} "${filters[@]}"

# one check for branch protection, whatever the number of shards
result:
needs: [plan, run]
if: always()
runs-on: ubuntu-latest
steps:
- env:
PLAN: ${{ needs.plan.result }}
RUN: ${{ needs.run.result }}
run: test "$PLAN" = success && { test "$RUN" = success || test "$RUN" = skipped; }
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: Node entry on the built dist/
run: node --expose-gc --test test/image.test.ts

# master only takes up-to-date pull requests, so this already ran on the merged code
jtreg:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/jtreg.yml
with:
full: ${{ github.event_name == 'push' }}
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ Node, which is how the tests run.
needs inputs first (see docs/development.md)
- `JW_JIT_STATS=1` prints what the JIT compiled, fell back on and entered
through the run loop; `JW_JIT_DUMP=<method>` prints a method's generated JS
- Pull requests run the OpenJDK tests in `test/jtreg/passing.txt` that their
changes need (`scripts/jtreg/select.ts`); releases run all of them. A test
that fails without a code change is fixed or taken out of `passing.txt`, so
a green pull request stays green on `master` and at release
- `project516-review-bot` reviews every PR. Merge only once its review of the
head commit has every finding fixed or answered on its thread. When it
cannot read the whole diff, a subagent reviews the files it skipped
Expand Down
10 changes: 9 additions & 1 deletion scripts/jtreg/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ console.log(`${selected.length} tests, ${queue.length} to run, ${jobs} at a time

const counts: Record<string, number> = {};
const regressions: string[] = [];
// java-web's time per test, to spot tests that run close to the timeout
const times: [string, number][] = [];
let finished = 0;
async function coolDown() {
const zone = "/sys/class/thermal/thermal_zone0/temp";
Expand All @@ -464,7 +466,10 @@ async function worker() {
const r: Record<string, any> = { id: tc.id, ...(await runCase(tc)) };
counts[r.status as string] = (counts[r.status as string] ?? 0) + 1;
finished++;
if (onlyPassing) { if (r.status !== "pass") regressions.push(`${tc.id}: ${r.status} ${r.why ?? ""}`); }
if (onlyPassing) {
if (r.status !== "pass") regressions.push(`${tc.id}: ${r.status} ${r.why ?? ""}`);
if (typeof r.ms === "number") times.push([tc.id, r.ms]);
}
else appendFileSync(resultsFile, JSON.stringify(r) + "\n");
if (r.status !== "skip") console.log(`[${finished}] ${r.status.toString().padEnd(7)} ${tc.id}${r.why ? " " + r.why : ""}`);
}
Expand All @@ -474,6 +479,9 @@ await Promise.all(Array.from({ length: jobs }, worker));
console.log(counts);

if (onlyPassing) {
times.sort((a, b) => b[1] - a[1]);
writeFileSync(join(out, "times.tsv"), times.map(([id, ms]) => `${ms}\t${id}`).join("\n") + "\n");
console.log("slowest:\n" + times.slice(0, 15).map(([id, ms]) => `${Math.round(ms / 1000)}s ${id}`).join("\n"));
if (regressions.length) {
console.log("regressions:\n" + regressions.join("\n"));
process.exit(1);
Expand Down
43 changes: 25 additions & 18 deletions scripts/jtreg/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,35 @@
//
// node scripts/jtreg/select.ts [<base> | --full]
//
// Prints GitHub Actions outputs: `filters`, the test areas to pass to run.ts
// (empty for all of them), and `shards`, a JSON list of shard numbers ([] when
// no test is needed). A changed file this does not know runs every test.
// Prints GitHub Actions outputs: `filters`, the tests to pass to run.ts (empty
// for all of them), and `shards`, a JSON list of shard numbers ([] when no test
// is needed). Tests added to passing.txt run alone; a change to anything the
// tests load runs them all.

import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";

const root = join(import.meta.dirname, "..", "..");
const passingFile = "test/jtreg/passing.txt";

// first match wins; null runs no test
const areas: [RegExp, string[] | null][] = [
[/\.md$|^docs\/|^LICENSE|^renovate\.json$|^\.coderabbit/, null],
[/^src\/browser\/|^src\/(bridge|library|image|http-proxy)\.ts$|^types\/|^scripts\/(build-web|serve)\.ts$/, null],
[/^test\/(?!jtreg\/)/, null],
[/^src\/natives\/zip\.ts$|^src\/inflate\.ts$/, ["java/util/zip", "java/util/jar"]],
[/^src\/natives\/(io|nio)\.ts$|^src\/fs\.ts$/, ["java/io", "java/nio", "java/util/zip", "java/util/jar"]],
[/^src\/natives\/(net|sockets)\.ts$|^src\/(sockets|net-node)\.ts$|^scripts\/tls\//, ["java/net", "java/nio/channels"]],
[/^src\/natives\/(font|java2d)[\w-]*\.ts$/, ["java/awt", "java/beans"]],
[/^src\/natives\/management\.ts$/, ["java/lang/management"]],
];
// TypeScript the tests load: everything src/node.ts (the VM each test runs on),
// the runner and this selection import, followed through their imports. Other .ts files under
// src/ and scripts/ (the page API, the web build) cannot change a test's result.
function loaded(): Set<string> {
const seen = new Set<string>();
const visit = (file: string) => {
if (seen.has(file)) return;
seen.add(file);
const text = readFileSync(join(root, file), "utf8");
for (const m of text.matchAll(/(?:from|import)\s*\(?\s*["'](\.{1,2}\/[^"']+\.ts)["']/g)) visit(join(dirname(file), m[1]));
};
visit("src/node.ts");
visit("scripts/jtreg/run.ts");
visit("scripts/jtreg/select.ts");
return seen;
}
const notLoaded = /\.md$|^docs\/|^LICENSE|^renovate\.json$|^\.coderabbit|^types\/|^test\/(?!jtreg\/)/;
Comment thread
project516-review-bot[bot] marked this conversation as resolved.
Resolved

const shardsFor = (n: number) => Array.from({ length: Math.min(4, Math.ceil(n / 400)) }, (_, i) => i + 1);
const listed = readFileSync(join(root, passingFile), "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
Expand All @@ -33,6 +40,7 @@ function select(base: string | undefined): string[] | "all" {
if (!base) return "all";
const git = (...args: string[]) => execFileSync("git", args, { cwd: root, encoding: "utf8" });
const filters = new Set<string>();
let graph: Set<string> | undefined;
for (const file of git("diff", "--name-only", "--no-renames", `${base}...HEAD`).split("\n").filter(Boolean)) {
if (file === passingFile) {
// the tests it adds
Expand All @@ -41,9 +49,8 @@ function select(base: string | undefined): string[] | "all" {
}
continue;
}
const hit = areas.find(([re]) => re.test(file));
if (!hit) return "all";
for (const f of hit[1] ?? []) filters.add(f);
const ts = /^(src|scripts)\/.*\.ts$/.test(file);
if (ts ? (graph ??= loaded()).has(file) : !notLoaded.test(file)) return "all";
}
return [...filters];
}
Expand Down
2 changes: 0 additions & 2 deletions test/jtreg/passing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1658,7 +1658,6 @@ java/security/KeyAgreement/NegativeTest.java
java/security/KeyFactory/Failover.java
java/security/KeyFactory/GenerateRSAPrivateCrtKey.java
java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java
java/security/KeyPairGenerator/Failover.java
java/security/KeyPairGenerator/GenerateKeypair.java
java/security/KeyPairGenerator/GenerateRSAKeyPair.java
java/security/KeyRep/Serial.java
Expand Down Expand Up @@ -1711,7 +1710,6 @@ java/security/SecureRandom/GetAlgorithm.java
java/security/SecureRandom/GetInstanceTest.java
java/security/SecureRandom/MultiThreadTest.java
java/security/SecureRandom/NextBytesNull.java
java/security/SecureRandom/NoSync.java
java/security/SecureRandom/Serialize.java
java/security/SecureRandom/SerializedSeedTest.java
java/security/SecureRandom/TestStrong.java
Expand Down
Loading