mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 15:52:21 +00:00
Main's work since the last merge runs on the globe contract where this branch draws through it: - Satellites take main's classes, sensors, ground-track bearings and world time through contract points and rings; launches take the world timeline. The satellite's cockpit subject dims, copies positions and refocuses through the contract. - Flights, military and vessels keep main's photos, retry cool-downs, world-clock motion and the ship bridge. Trail seeding in the shared aircraft tracking reads each layer's clock. - Traffic's flow lines and single build draw as ground sets; transit keeps dated credits and the new cities; CCTV opens the nearest camera, and the Quebec overlay projects and tests the horizon through the contract. Bikeshare's manager cleanup moved into its current lifecycle. - Draw keeps main's mark actions across engine switches. - The world clock in src/time is plain numbers again: Julian dates come from src/geo, the frame loop is injected, and the binding to Cesium's viewer clock lives in src/globe/cesium/worldTime.js. Navara's sky and sun follow the world time; live feeds keep the real time. - The cockpit's orbital view, with its sensor zoom, ground focus and satellite switching, stays Cesium-only for now: Navara hides its entry. Its Cesium calls live in src/globe/cesium/orbital.js. The ship bridge's finest-detail waterline sampling is Cesium-only too; Navara samples loaded geometry and detailed terrain. Both are in KNOWN-ISSUES. - Main's tests that built a Cesium scene by hand run on the fake engine. - The boundary manifest is regenerated, the coupling baseline records the orbital and bridge code, and the main-chunk baseline is raised to the merged size: main itself grew its main chunk by 93,959 bytes (gzip -9) since the previous merge base.
123 lines
4.8 KiB
JavaScript
123 lines
4.8 KiB
JavaScript
import { existsSync, readdirSync } from 'node:fs';
|
|
import { spawnSync } from 'node:child_process';
|
|
import path from 'node:path';
|
|
import { pathToFileURL } from 'node:url';
|
|
|
|
export const ALLOCATION_TEST_FILES = Object.freeze([
|
|
'src/data/focusAllocations.test.mjs',
|
|
'src/overlays/worldOverlayAllocation.test.mjs',
|
|
]);
|
|
|
|
/** Whether this runtime matches a supported major the allocation budgets are calibrated on. */
|
|
export function isCalibratedAllocationRuntime(version = process.versions.node) {
|
|
const major = Number.parseInt(String(version).split('.')[0], 10);
|
|
return major === 24 || major === 26;
|
|
}
|
|
|
|
/** Require a runtime on which allocation budgets are calibrated. */
|
|
export function assertCalibratedAllocationRuntime(version = process.versions.node) {
|
|
if (!isCalibratedAllocationRuntime(version)) {
|
|
throw new Error(`Allocation budgets require calibrated Node 24 or 26; received ${version}`);
|
|
}
|
|
return version;
|
|
}
|
|
|
|
/**
|
|
* Directories this runner searches for `*.test.mjs`, in stable order.
|
|
*
|
|
* `server/` belongs here because provider modules own tests of their own: a
|
|
* suite placed beside the module it covers must run, and CI's unit-test job runs
|
|
* `npm test`, so a directory missing from this list is a suite that never runs
|
|
* there. `unitTestRunner.test.mjs` asserts the list covers every `*.test.mjs`
|
|
* outside dependencies, build output and dot-directories, so adding a tree
|
|
* without adding it here fails.
|
|
*/
|
|
export const UNIT_TEST_ROOTS = Object.freeze(['src', 'server', 'scripts']);
|
|
|
|
/** Discover repository unit tests in stable path order. */
|
|
export function discoverUnitTestFiles(root = process.cwd()) {
|
|
const files = [];
|
|
const visit = (directory) => {
|
|
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
const absolute = path.join(directory, entry.name);
|
|
if (entry.isDirectory()) visit(absolute);
|
|
else if (entry.isFile() && entry.name.endsWith('.test.mjs')) {
|
|
files.push(path.relative(root, absolute).split(path.sep).join('/'));
|
|
}
|
|
}
|
|
};
|
|
// A checkout without one of the roots (a test fixture) has no tests there.
|
|
for (const testRoot of UNIT_TEST_ROOTS)
|
|
if (existsSync(path.join(root, testRoot)))
|
|
visit(path.join(root, testRoot));
|
|
return files.sort();
|
|
}
|
|
|
|
/** Partition ordinary parallel tests from the two GC-bracketed probes. */
|
|
export function buildUnitTestPlan(files) {
|
|
const known = new Set(files);
|
|
const missingAllocationTests = ALLOCATION_TEST_FILES.filter((file) => !known.has(file));
|
|
if (missingAllocationTests.length) {
|
|
throw new Error(`Missing allocation microbenchmarks: ${missingAllocationTests.join(', ')}`);
|
|
}
|
|
const allocationSet = new Set(ALLOCATION_TEST_FILES);
|
|
return {
|
|
parallel: files.filter((file) => !allocationSet.has(file)).sort(),
|
|
serializedAllocations: [...ALLOCATION_TEST_FILES],
|
|
};
|
|
}
|
|
|
|
/** Build the isolated Node invocation for one GC-bracketed allocation probe. */
|
|
export function allocationTestArgs(file) {
|
|
if (!ALLOCATION_TEST_FILES.includes(file)) {
|
|
throw new Error(`Not an allocation microbenchmark: ${file}`);
|
|
}
|
|
return ['--expose-gc', '--test', '--test-concurrency=1', file];
|
|
}
|
|
|
|
/** Node flags every unit-test process receives. */
|
|
export const UNIT_TEST_NODE_FLAGS = Object.freeze([
|
|
// Single-file components compile on import.
|
|
'--import=./build/registerVue.js',
|
|
]);
|
|
|
|
function runTests(args) {
|
|
const result = spawnSync(process.execPath, [...UNIT_TEST_NODE_FLAGS, ...args], {
|
|
cwd: process.cwd(),
|
|
stdio: 'inherit',
|
|
env: process.env,
|
|
});
|
|
if (result.error) throw result.error;
|
|
return result.status ?? 1;
|
|
}
|
|
|
|
export function runUnitTests() {
|
|
const plan = buildUnitTestPlan(discoverUnitTestFiles());
|
|
const parallelStatus = runTests(['--test', ...plan.parallel]);
|
|
if (parallelStatus !== 0) return parallelStatus;
|
|
|
|
// The GC-bracketed budgets are calibrated on every supported Node major.
|
|
// Unsupported runtimes may still run ordinary tests, so uncalibrated runtimes skip the
|
|
// probes with a warning. Set GEV_REQUIRE_ALLOCATION_GATE=1 (pinned CI /
|
|
// release batteries) to make an uncalibrated runtime a hard failure.
|
|
if (!isCalibratedAllocationRuntime()) {
|
|
if (process.env.GEV_REQUIRE_ALLOCATION_GATE === '1') {
|
|
assertCalibratedAllocationRuntime();
|
|
}
|
|
console.warn(
|
|
`[unit] SKIPPED ${ALLOCATION_TEST_FILES.length} allocation microbenchmarks: `
|
|
+ `budgets are calibrated for Node 24 and 26, running ${process.versions.node}. `
|
|
+ 'Run under Node 24 or 26 (or set GEV_REQUIRE_ALLOCATION_GATE=1 to fail instead).',
|
|
);
|
|
return 0;
|
|
}
|
|
for (const file of plan.serializedAllocations) {
|
|
const status = runTests(allocationTestArgs(file));
|
|
if (status !== 0) return status;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const invokedPath = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : '';
|
|
if (import.meta.url === invokedPath) process.exitCode = runUnitTests();
|