mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-08 08:44:37 +08:00
Under ASan, self-hosting-llvm-emitter, three-library, npm-static and npm each take 20 to 40 minutes as one Vitest file, so a sharded run cannot finish before them. - self-hosting-llvm-emitter splits into its emitter-cases-and-programs and fixed-point halves; a shard builds the seed once for the halves it owns. three-library skips the optimization its shard does not own. Both put their tests in a describe block, which skipUnownedTest partitions. - CI runs both in every shard's case-sharded side queue (scripts/ci-test-plan.mjs); pnpm test:sandbox case-shards them with npm and npm-static. - npm.test.ts keeps a skipped placeholder in a shard that owns no program, so an empty shard does not fail the file. The sanitized native-driver bootstrap ran its instrumented compiler with the default 8 MiB stack. Its frontend phase overflows it (SC3004) on main as well, outside CI's ulimit for the emitter phase. The test now raises the soft stack limit to the hard one for every sanitized compiler process it starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { compileLibrary } from "@scriptc/compiler";
|
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
import { skipUnownedTest } from "./shard.js";
|
|
|
|
const fixture = join(import.meta.dirname, "../library-mode/wasm");
|
|
const hasClang = spawnSync("clang", ["--version"]).status === 0;
|
|
// The two optimizations take similar time (about 10 minutes each under ASan):
|
|
// SCRIPTC_TEST_SHARD runs them on different shards (tests/harness/shard.ts).
|
|
// skipUnownedTest partitions a describe block's tests.
|
|
describe("three.js native library", () => {
|
|
beforeEach((context) => skipUnownedTest(context, {}));
|
|
test.skipIf(!hasClang).each(["dev", "release"] as const)(
|
|
"three.js sends animated geometry, materials and resource lifecycle to a native host in %s",
|
|
async (optimization) => {
|
|
const directory = await mkdtemp("/tmp/scriptc-three-library-");
|
|
const sanitize = process.env["SCRIPTC_SAN"] === "1";
|
|
try {
|
|
const profile = JSON.parse(await readFile(join(fixture, "three.json"), "utf8"));
|
|
const profilePath = join(directory, "profile.json");
|
|
await writeFile(
|
|
profilePath,
|
|
JSON.stringify({
|
|
...profile,
|
|
name: "three-native-embedding",
|
|
entry: join(fixture, "three.mjs"),
|
|
optimization,
|
|
}),
|
|
);
|
|
const built = await compileLibrary({ profilePath, outDir: directory, sanitize });
|
|
if (!built.ok)
|
|
throw new Error(
|
|
built.diagnostics
|
|
.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`)
|
|
.join("\n"),
|
|
);
|
|
const binary = join(directory, "host");
|
|
const linked = spawnSync(
|
|
"clang",
|
|
[
|
|
"-std=c11",
|
|
...(sanitize ? ["-fsanitize=address,undefined"] : []),
|
|
join(fixture, "three-native.c"),
|
|
built.archivePath,
|
|
"-lm",
|
|
"-o",
|
|
binary,
|
|
],
|
|
{ encoding: "utf8" },
|
|
);
|
|
expect(linked.status, linked.stderr).toBe(0);
|
|
const actual = spawnSync(binary, [], { encoding: "utf8", timeout: 30_000 });
|
|
expect(actual.status, actual.stderr).toBe(0);
|
|
const reference = spawnSync(
|
|
process.execPath,
|
|
[
|
|
"--no-warnings",
|
|
"--input-type=module",
|
|
"-e",
|
|
`
|
|
const events=[];
|
|
for (const name of ["vertex","surface","resource"]) globalThis[name]=(...values)=>events.push([name,...values.map(value=>Number(value.toFixed(9)))]);
|
|
const {frame,dispose}=await import(${JSON.stringify(join(fixture, "three.mjs"))});
|
|
for (const time of [0,123,2000]) frame(time,1.5);
|
|
dispose();
|
|
console.log(JSON.stringify(events));
|
|
`,
|
|
],
|
|
{ encoding: "utf8" },
|
|
);
|
|
expect(reference.status, reference.stderr).toBe(0);
|
|
const events = JSON.parse(reference.stdout);
|
|
expect(
|
|
actual.stdout
|
|
.trim()
|
|
.split("\n")
|
|
.map((line) => JSON.parse(line)),
|
|
).toEqual([...events, ...events]);
|
|
} finally {
|
|
await rm(directory, { recursive: true, force: true });
|
|
}
|
|
},
|
|
600_000,
|
|
);
|
|
});
|