mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
87 lines
3.4 KiB
TypeScript
87 lines
3.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
// Pin physical RAM to 32GB so the remedy branch (auto cap = 24GB) resolves
|
|
// deterministically regardless of the host machine.
|
|
vi.mock('os', async () => {
|
|
const actual = await vi.importActual<typeof import('os')>('os');
|
|
const mocked = { ...actual, totalmem: () => 32 * 1024 * 1024 * 1024 };
|
|
return { ...mocked, default: mocked };
|
|
});
|
|
|
|
import {
|
|
heapPressureRemedy,
|
|
projectParseHeapNeedBytes,
|
|
shouldAbortForHeapPressure,
|
|
} from '../../src/core/ingestion/pipeline-phases/parse-impl.js';
|
|
|
|
const GB = 1024 * 1024 * 1024;
|
|
|
|
const setConstrainedMemory = (value: number): (() => void) => {
|
|
const desc = Object.getOwnPropertyDescriptor(process, 'constrainedMemory');
|
|
Object.defineProperty(process, 'constrainedMemory', { configurable: true, value: () => value });
|
|
return () => {
|
|
if (desc) Object.defineProperty(process, 'constrainedMemory', desc);
|
|
else delete (process as { constrainedMemory?: unknown }).constrainedMemory;
|
|
};
|
|
};
|
|
|
|
describe('#2649 parse-phase heap guardrails', () => {
|
|
let initialGuard: string | undefined;
|
|
let restoreConstrained: (() => void) | undefined;
|
|
|
|
beforeEach(() => {
|
|
initialGuard = process.env.GITNEXUS_MEMORY;
|
|
delete process.env.GITNEXUS_MEMORY;
|
|
// Unconstrained by default so the mocked 32GB totalmem governs.
|
|
restoreConstrained = setConstrainedMemory(0);
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (initialGuard === undefined) delete process.env.GITNEXUS_MEMORY;
|
|
else process.env.GITNEXUS_MEMORY = initialGuard;
|
|
restoreConstrained?.();
|
|
restoreConstrained = undefined;
|
|
});
|
|
|
|
it('projects kernel-scale repos far past the 4GB default heap and small repos well under it', () => {
|
|
// 94,773 files x 55 nodes x 2250 bytes ≈ 11.7GB (the measured #2649 case);
|
|
// 2,000 files ≈ 236MB.
|
|
expect({
|
|
kernelExceeds4Gb: projectParseHeapNeedBytes(94773) > 4 * GB,
|
|
smallRepoUnder1Gb: projectParseHeapNeedBytes(2000) < 1 * GB,
|
|
}).toEqual({ kernelExceeds4Gb: true, smallRepoUnder1Gb: true });
|
|
});
|
|
|
|
it('aborts above 92% of the heap limit and not below it', () => {
|
|
const limit = 4 * GB;
|
|
expect([0.91, 0.93].map((f) => shouldAbortForHeapPressure(limit * f, limit))).toEqual([
|
|
false,
|
|
true,
|
|
]);
|
|
});
|
|
|
|
it('GITNEXUS_MEMORY=0 disables the abort entirely', () => {
|
|
process.env.GITNEXUS_MEMORY = 'off';
|
|
const limit = 4 * GB;
|
|
expect(shouldAbortForHeapPressure(limit * 0.99, limit)).toBe(false);
|
|
});
|
|
|
|
it('points at the NODE_OPTIONS pin when the machine has more memory to give', () => {
|
|
// 4GB limit on a 32GB machine (auto cap 24GB): the pin is the problem.
|
|
expect(heapPressureRemedy(4 * GB)).toContain('re-run without the --max-old-space-size');
|
|
});
|
|
|
|
it('points at scope or hardware when the machine is the ceiling', () => {
|
|
// 23GB limit on a 32GB machine (~auto cap): nothing more to unlock locally.
|
|
expect(heapPressureRemedy(23 * GB)).toContain('.gitnexusignore');
|
|
});
|
|
|
|
it('remedy respects a real cgroup limit: a memory-limited container is never told to "drop the pin" (#2649 review)', () => {
|
|
// 8GB cgroup limit on the mocked 32GB host, heap already sized to the
|
|
// container (~6.5GB): raw totalmem would claim "more memory available";
|
|
// the container is actually at its ceiling.
|
|
restoreConstrained?.();
|
|
restoreConstrained = setConstrainedMemory(8 * GB);
|
|
expect(heapPressureRemedy(6.5 * GB)).toContain('.gitnexusignore');
|
|
});
|
|
});
|