Build the sanitized three.js nodes fixture in its own CI job (#2210)

This commit is contained in:
Chris Tate
2026-10-25 16:16:34 -05:00
committed by GitHub
4 changed files with 89 additions and 0 deletions
+33
View File
@@ -346,6 +346,37 @@ jobs:
- run: tar -xzf "$RUNNER_TEMP/native-linux-x64-gnu.tar.gz"
- run: pnpm test tests/harness/effect.test.ts tests/harness/effect4.test.ts
# The sanitized three.js nodes build alone: beside the san corpus's other
# workers it took 860 to more than 1200 seconds of its shard
# (SCRIPTC_THREE_SANITIZED_NODES_JOB in scripts/ci-test-plan.mjs). It keeps
# the corpus's LeakSanitizer settings.
three_nodes_san:
needs: [validation_scope, lanes, native_linux]
if: ${{ needs.validation_scope.outputs.full == 'true' && needs.lanes.outputs.linux == 'true' }}
name: test (Linux, san, three.js nodes)
runs-on: ubuntu-24.04
timeout-minutes: 40
env:
SCRIPTC_SAN: "1"
ASAN_OPTIONS: detect_leaks=1
LSAN_OPTIONS: suppressions=${{ github.workspace }}/tests/harness/lsan.supp:print_suppressions=0
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 11.1.3
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: actions/download-artifact@v4
with:
name: native-linux-x64-gnu
path: ${{ runner.temp }}
- run: tar -xzf "$RUNNER_TEMP/native-linux-x64-gnu.tar.gz"
- run: pnpm test tests/harness/three.test.ts -t "'nodes' runs statically through LLVM on 'native'"
# Build each instrumented seed once. Downstream contracts retain the same
# compiler and source artifacts without repeating seed construction.
bootstrap_seed:
@@ -950,6 +981,7 @@ jobs:
tests_macos,
native_linux,
effects,
three_nodes_san,
bootstrap_seed,
bootstrap,
linux_host_clang,
@@ -982,6 +1014,7 @@ jobs:
lane tests_macos "${{ needs.tests_macos.result }}" "${{ needs.lanes.outputs.macos }}"
lane native_linux "${{ needs.native_linux.result }}" "${{ needs.lanes.outputs.linux }}"
lane effects "${{ needs.effects.result }}" "${{ needs.lanes.outputs.effects }}"
lane three_nodes_san "${{ needs.three_nodes_san.result }}" "${{ needs.lanes.outputs.linux }}"
lane bootstrap_seed "${{ needs.bootstrap_seed.result }}" "${{ needs.lanes.outputs.bootstrap }}"
lane bootstrap "${{ needs.bootstrap.result }}" "${{ needs.lanes.outputs.bootstrap }}"
lane linux_host_clang "${{ needs.linux_host_clang.result }}" "${{ needs.lanes.outputs.linux }}"
+10
View File
@@ -134,6 +134,15 @@ export const leakSuppressions = fileURLToPath(
new URL("../tests/harness/lsan.supp", import.meta.url),
);
// The sanitized three.js nodes build runs in its own Linux job
// (three_nodes_san in .github/workflows/ci.yml). Beside the corpus's other
// workers it took 860 to more than 1200 seconds, past its test timeout.
export const sanitizedNodesJobEnv = { SCRIPTC_THREE_SANITIZED_NODES_JOB: "1" };
function corpusThreeEnv(flavor, platform) {
return flavor === "san" && platform === "linux" ? sanitizedNodesJobEnv : {};
}
function corpusLeakEnv(flavor, platform) {
if (flavor !== "san" || platform !== "linux") return {};
return {
@@ -246,6 +255,7 @@ export function ciTestPlan({
env: {
...env,
...corpusLeakEnv(flavor, platform),
...corpusThreeEnv(flavor, platform),
SCRIPTC_TEST_WORKERS: String(workers - sideWorkers),
SCRIPTC_LLVM_TEST_MODE: "dev",
},
+37
View File
@@ -12,6 +12,7 @@ import {
isolatedFiles,
leakSuppressions,
memoryHeavyFiles,
sanitizedNodesJobEnv,
sideOwners,
testCosts,
} from "../../scripts/ci-test-plan.mjs";
@@ -90,6 +91,42 @@ test("LeakSanitizer runs over the sanitized corpus on Linux only", () => {
for (const task of plan("san", "linux").side) expect(task.env.ASAN_OPTIONS).toBeUndefined();
});
test("the sanitized three.js nodes build leaves the Linux corpus for its own job", () => {
const plan = (flavor: "plain" | "san", platform: string) =>
ciTestPlan({ shard: "1/20", flavor, workers: 4, platform });
const [name, value] = Object.entries(sanitizedNodesJobEnv)[0]!;
expect(plan("san", "linux").corpus.env[name]).toBe(value);
for (const env of [plan("plain", "linux").corpus.env, plan("san", "darwin").corpus.env])
expect(env[name]).toBeUndefined();
const three = readFileSync(new URL("./three.test.ts", import.meta.url), "utf8");
expect(three).toContain(`process.env["${name}"] === "${value}"`);
const { jobs } = load(
readFileSync(new URL("../../.github/workflows/ci.yml", import.meta.url), "utf8"),
) as {
jobs: Record<
string,
{ needs: string[]; env: Record<string, string>; steps: { run?: string }[] }
>;
};
const job = jobs["three_nodes_san"]!;
expect(job.needs).toContain("native_linux");
expect(jobs["test"]!.needs).toContain("three_nodes_san");
expect(job.env[name]).toBeUndefined();
expect(job.env["SCRIPTC_SAN"]).toBe("1");
// The same LeakSanitizer settings as the corpus it left.
const corpus = plan("san", "linux").corpus.env;
expect(job.env["ASAN_OPTIONS"]).toBe(corpus.ASAN_OPTIONS);
expect(job.env["LSAN_OPTIONS"]).toBe(
corpus.LSAN_OPTIONS!.replace(
leakSuppressions,
"${{ github.workspace }}/tests/harness/lsan.supp",
),
);
expect(job.steps.at(-1)!.run).toBe(
`pnpm test tests/harness/three.test.ts -t "'nodes' runs statically through LLVM on 'native'"`,
);
});
test("the side queue balances measured files across the twenty Linux shards", () => {
for (const flavor of ["plain", "san"] as const) {
const costs = testCosts[flavor] as Record<string, number>;
+9
View File
@@ -68,6 +68,15 @@ test.for(cases)(
async ({ fixture, target }, context) => {
const entry = join(import.meta.dirname, `../fixtures/three/${fixture}.mjs`);
if (target === "wasm32-wasi" && !hasZig) context.skip();
// CI's Linux sanitized lane builds this one in its own job
// (scripts/ci-test-plan.mjs).
if (
fixture === "nodes" &&
target === "native" &&
process.env["SCRIPTC_SAN"] === "1" &&
process.env["SCRIPTC_THREE_SANITIZED_NODES_JOB"] === "1"
)
context.skip();
const dir = await mkdtemp("/tmp/scriptc-three-");
const previousTarget = process.env["SCRIPTC_TARGET"];
const previousCc = process.env["SCRIPTC_CC"];