71 lines
3.4 KiB
TypeScript
71 lines
3.4 KiB
TypeScript
/**
|
|
* Issue #5238 (Defect C) — `omniroute serve` silently DISCARDED a user-set
|
|
* `NODE_OPTIONS=--max-old-space-size=…`. The serve command spread `process.env`
|
|
* then UNCONDITIONALLY overwrote NODE_OPTIONS with the calibrated default, so a
|
|
* user who exported `NODE_OPTIONS=--max-old-space-size=8192` still ran at the
|
|
* calibrated/old default and OOM'd (reporter: set 8192, crashed at ~505 MB).
|
|
*
|
|
* The fix mirrors the Electron (electron/main.js) and standalone
|
|
* (scripts/dev/run-standalone.mjs) launchers: preserve a user-set heap flag,
|
|
* otherwise APPEND the calibrated value (keeping unrelated flags intact). It
|
|
* also gates the explicit `node --max-old-space-size` CLI arg so it never
|
|
* shadows the user's NODE_OPTIONS value.
|
|
*/
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { buildServerNodeOptions, buildNodeHeapArgs, envHasExplicitHeapFlag } =
|
|
await import("../../scripts/build/runtime-env.mjs");
|
|
|
|
const HEAP_RE = /--max-old-space-size=(\d+)/g;
|
|
function heapValues(nodeOptions: string): string[] {
|
|
return [...nodeOptions.matchAll(HEAP_RE)].map((m) => m[1]);
|
|
}
|
|
|
|
test("#5238 case 1: user-set NODE_OPTIONS heap wins, no second/calibrated flag injected", () => {
|
|
const env = { NODE_OPTIONS: "--max-old-space-size=8192" };
|
|
// memoryLimit here would be the calibrated default the OLD code forced in.
|
|
const result = buildServerNodeOptions(env, 512);
|
|
|
|
const values = heapValues(result);
|
|
assert.deepEqual(values, ["8192"], "exactly one heap flag, the user's 8192");
|
|
assert.ok(!values.includes("512"), "calibrated 512 must NOT be present");
|
|
// CLI arg path must also not re-inject a conflicting/shadowing flag.
|
|
assert.deepEqual(
|
|
buildNodeHeapArgs(env, 512),
|
|
[],
|
|
"no explicit CLI --max-old-space-size when user pinned NODE_OPTIONS"
|
|
);
|
|
});
|
|
|
|
test("#5238 case 2: no NODE_OPTIONS → calibrated value applied", () => {
|
|
const result = buildServerNodeOptions({}, 2048);
|
|
assert.equal(result, "--max-old-space-size=2048");
|
|
assert.deepEqual(heapValues(result), ["2048"]);
|
|
assert.deepEqual(buildNodeHeapArgs({}, 2048), ["--max-old-space-size=2048"]);
|
|
});
|
|
|
|
test("#5238 case 3: unrelated pre-existing flag preserved when heap is appended", () => {
|
|
const env = { NODE_OPTIONS: "--enable-source-maps" };
|
|
const result = buildServerNodeOptions(env, 2048);
|
|
assert.ok(result.includes("--enable-source-maps"), "unrelated flag preserved");
|
|
assert.deepEqual(heapValues(result), ["2048"], "calibrated heap appended once");
|
|
assert.equal(result, "--enable-source-maps --max-old-space-size=2048");
|
|
});
|
|
|
|
test("#5238 case 4: user heap flag + unrelated flag both preserved, no override", () => {
|
|
const env = { NODE_OPTIONS: "--enable-source-maps --max-old-space-size=8192" };
|
|
const result = buildServerNodeOptions(env, 512);
|
|
assert.ok(result.includes("--enable-source-maps"), "unrelated flag preserved");
|
|
assert.deepEqual(heapValues(result), ["8192"], "user heap preserved, calibrated NOT added");
|
|
assert.equal(result, env.NODE_OPTIONS, "returned as-is");
|
|
assert.deepEqual(buildNodeHeapArgs(env, 512), [], "no shadowing CLI arg");
|
|
});
|
|
|
|
test("#5238 envHasExplicitHeapFlag detects a user-pinned heap", () => {
|
|
assert.equal(envHasExplicitHeapFlag({ NODE_OPTIONS: "--max-old-space-size=4096" }), true);
|
|
assert.equal(envHasExplicitHeapFlag({ NODE_OPTIONS: "--enable-source-maps" }), false);
|
|
assert.equal(envHasExplicitHeapFlag({}), false);
|
|
assert.equal(envHasExplicitHeapFlag(undefined), false);
|
|
});
|