t
This commit is contained in:
parent
0990b98436
commit
1a3ba56d9a
123 changed files with 16018 additions and 9153 deletions
142
tests/test-all.mjs
Normal file
142
tests/test-all.mjs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import { performance } from "node:perf_hooks";
|
||||
import { spawn } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const suites = [
|
||||
"core",
|
||||
"terrain",
|
||||
"admin",
|
||||
"determinism-114514",
|
||||
"determinism-12345",
|
||||
"determinism-54321",
|
||||
"determinism-777",
|
||||
"determinism-999",
|
||||
];
|
||||
const concurrency = Math.max(1, Math.min(2, Number(process.env.TEST_CONCURRENCY) || 1));
|
||||
const timeoutMs = 180_000;
|
||||
const maxOutputBytes = 32 * 1024 * 1024;
|
||||
const cwd = fileURLToPath(new URL(".", import.meta.url));
|
||||
const testFile = fileURLToPath(new URL("./test.js", import.meta.url));
|
||||
|
||||
function runSuite(suite) {
|
||||
return new Promise((resolve) => {
|
||||
const started = performance.now();
|
||||
console.error(`[test-all] start ${suite}`);
|
||||
const child = spawn(process.execPath, [testFile, `--suite=${suite}`], {
|
||||
cwd,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
let outputOverflow = false;
|
||||
let timedOut = false;
|
||||
let forceKillTimer = null;
|
||||
|
||||
const append = (current, chunk) => {
|
||||
if (outputOverflow) return current;
|
||||
const next = current + chunk.toString("utf8");
|
||||
if (Buffer.byteLength(next, "utf8") > maxOutputBytes) {
|
||||
outputOverflow = true;
|
||||
child.kill("SIGTERM");
|
||||
return current;
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
child.stdout.on("data", (chunk) => { stdout = append(stdout, chunk); });
|
||||
child.stderr.on("data", (chunk) => { stderr = append(stderr, chunk); });
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
timedOut = true;
|
||||
child.kill("SIGTERM");
|
||||
forceKillTimer = setTimeout(() => child.kill("SIGKILL"), 2_000);
|
||||
forceKillTimer.unref?.();
|
||||
}, timeoutMs);
|
||||
timeout.unref?.();
|
||||
|
||||
child.on("error", (error) => {
|
||||
clearTimeout(timeout);
|
||||
if (forceKillTimer) clearTimeout(forceKillTimer);
|
||||
const seconds = Math.round((performance.now() - started) / 10) / 100;
|
||||
console.error(`[test-all] error ${suite}: ${error.message}`);
|
||||
resolve({
|
||||
suite,
|
||||
seconds,
|
||||
fullMapGenerations: null,
|
||||
failedAssertions: null,
|
||||
status: null,
|
||||
signal: null,
|
||||
timedOut,
|
||||
outputOverflow,
|
||||
infrastructureError: error.message,
|
||||
});
|
||||
});
|
||||
|
||||
child.on("close", (status, signal) => {
|
||||
clearTimeout(timeout);
|
||||
if (forceKillTimer) clearTimeout(forceKillTimer);
|
||||
const seconds = Math.round((performance.now() - started) / 10) / 100;
|
||||
const output = `${stdout}\n${stderr}`;
|
||||
const ng = (output.match(/^NG:/gm) || []).length;
|
||||
const info = output.match(/INFO: suite=([^;]+); fullMapGenerations=(\d+); elapsedMs=(\d+)/);
|
||||
const infrastructureError = outputOverflow
|
||||
? `Output exceeded ${maxOutputBytes} bytes`
|
||||
: null;
|
||||
console.error(
|
||||
`[test-all] end ${suite}: status=${status} signal=${signal || "none"} ` +
|
||||
`failures=${ng} seconds=${seconds}`,
|
||||
);
|
||||
resolve({
|
||||
suite,
|
||||
seconds,
|
||||
fullMapGenerations: info ? Number(info[2]) : null,
|
||||
elapsedMsReported: info ? Number(info[3]) : null,
|
||||
failedAssertions: ng,
|
||||
status,
|
||||
signal: signal || null,
|
||||
timedOut,
|
||||
outputOverflow,
|
||||
infrastructureError,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const started = performance.now();
|
||||
const queue = [...suites];
|
||||
const completed = [];
|
||||
|
||||
async function worker() {
|
||||
while (queue.length > 0) {
|
||||
const suite = queue.shift();
|
||||
if (!suite) return;
|
||||
completed.push(await runSuite(suite));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(Array.from({ length: concurrency }, () => worker()));
|
||||
completed.sort((a, b) => suites.indexOf(a.suite) - suites.indexOf(b.suite));
|
||||
|
||||
const wallSeconds = Math.round((performance.now() - started) / 10) / 100;
|
||||
const failures = completed.reduce(
|
||||
(sum, row) => sum + (Number.isFinite(row.failedAssertions) ? row.failedAssertions : 0),
|
||||
0,
|
||||
);
|
||||
const infrastructureFailure = completed.some(
|
||||
(row) => row.status !== 0 || row.signal || row.timedOut || row.outputOverflow || row.infrastructureError,
|
||||
);
|
||||
const underThreeMinutes = wallSeconds < 180 && completed.every(
|
||||
(row) => row.seconds < 180 && !row.timedOut,
|
||||
);
|
||||
|
||||
const result = {
|
||||
underThreeMinutes,
|
||||
wallSeconds,
|
||||
concurrency,
|
||||
failures,
|
||||
infrastructureFailure,
|
||||
suites: completed,
|
||||
};
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
if (!underThreeMinutes || infrastructureFailure || failures > 0) process.exitCode = 1;
|
||||
10
tests/test-determinism-worker.mjs
Normal file
10
tests/test-determinism-worker.mjs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { generateMap } from "../src/mapPipeline.js";
|
||||
const seed = Number(process.argv[2]);
|
||||
if (!Number.isFinite(seed)) throw new Error("seed is required");
|
||||
const a = generateMap(seed, { onProgress() {} });
|
||||
const b = generateMap(seed, { onProgress() {} });
|
||||
console.log(JSON.stringify({
|
||||
seed,
|
||||
adminIdEqual: Buffer.from(a.adminId.buffer, a.adminId.byteOffset, a.adminId.byteLength).equals(Buffer.from(b.adminId.buffer, b.adminId.byteOffset, b.adminId.byteLength)),
|
||||
adminDebugEqual: JSON.stringify(a.adminDebug) === JSON.stringify(b.adminDebug),
|
||||
}));
|
||||
18
tests/test.html
Normal file
18
tests/test.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Prefecture Map Generator v17 Tests</title>
|
||||
<style>
|
||||
body { font-family: ui-sans-serif, system-ui, sans-serif; background: #111; color: #eee; padding: 24px; }
|
||||
pre { background: #222; border-radius: 8px; padding: 16px; white-space: pre-wrap; }
|
||||
.ok { color: #9fdf9f; }
|
||||
.ng { color: #ff9f9f; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tests</h1>
|
||||
<pre id="result">Running...</pre>
|
||||
<script type="module" src="./test.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1206
tests/test.js
Normal file
1206
tests/test.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue