Files
connectai/tests/systemSpecs.test.ts
T

91 lines
3.4 KiB
TypeScript

/**
* Unit tests for SystemSpecs + HeuristicModelMemoryEstimator.
*
* Strategy:
* - HeuristicModelMemoryEstimator is pure — directly drive it with model ids.
* - NodeSystemSpecsProvider depends on `os.*` so we test:
* a) caching (same instance returned twice),
* b) shape (all required fields present, sane numbers).
* We don't pin platform-specific values since CI hardware varies.
*/
import {
NodeSystemSpecsProvider,
HeuristicModelMemoryEstimator,
} from '../src/system/specs';
describe('HeuristicModelMemoryEstimator', () => {
const est = new HeuristicModelMemoryEstimator();
test('extracts parameter count from "7B" suffix', () => {
// 7B q4 default: 7 * 0.6 + 1 = 5.2
expect(est.estimate('llama-3.2-7b-q4_K_M')).toBeCloseTo(5.2, 1);
});
test('extracts parameter count from "70B"', () => {
// 70B q4 default: 70 * 0.6 + 1 = 43
expect(est.estimate('llama-3-70b-instruct-q4_0')).toBeCloseTo(43, 0);
});
test('q8 quantization uses higher byte/param', () => {
// 7B q8: 7 * 1.0 + 1 = 8
expect(est.estimate('mistral-7b-q8_0')).toBeCloseTo(8, 1);
});
test('fp16 uses 2 bytes/param', () => {
// 7B fp16: 7 * 2.0 + 1 = 15
expect(est.estimate('mistral-7b-fp16')).toBeCloseTo(15, 1);
});
test('q5 sits between q4 and q6', () => {
const q4 = est.estimate('foo-7b-q4');
const q5 = est.estimate('foo-7b-q5');
const q6 = est.estimate('foo-7b-q6');
expect(q4).toBeLessThan(q5);
expect(q5).toBeLessThan(q6);
});
test('falls back to 7B when parameter count is absent', () => {
// unknown size → 7B q4 default → 5.2
expect(est.estimate('some-model-no-size')).toBeCloseTo(5.2, 1);
});
test('decimal parameter counts like "3.8b"', () => {
// 3.8B q4: 3.8 * 0.6 + 1 = 3.28
expect(est.estimate('phi-3.8b-q4')).toBeCloseTo(3.28, 1);
});
test('handles empty / undefined input gracefully', () => {
expect(est.estimate('')).toBeCloseTo(5.2, 1); // defaults
expect(est.estimate(undefined as any)).toBeCloseTo(5.2, 1);
});
});
describe('NodeSystemSpecsProvider', () => {
test('returns the same cached object on repeated calls', () => {
const provider = new NodeSystemSpecsProvider();
const a = provider.get();
const b = provider.get();
expect(a).toBe(b);
});
test('produces a sane shape', () => {
const specs = new NodeSystemSpecsProvider().get();
expect(specs.totalRamGB).toBeGreaterThan(0);
expect(specs.cpuCount).toBeGreaterThanOrEqual(1);
expect(specs.platform).toMatch(/^(darwin|linux|win32|freebsd|openbsd|sunos|aix)$/);
expect(specs.arch.length).toBeGreaterThan(0);
expect(typeof specs.isAppleSilicon).toBe('boolean');
expect(specs.safeModelBudgetGB).toBeGreaterThanOrEqual(2);
expect(specs.safeModelBudgetGB).toBeLessThanOrEqual(specs.totalRamGB);
expect(specs.summary).toMatch(/RAM/);
});
test('safe budget is at most ~65% of total RAM (Apple Silicon ceiling)', () => {
const specs = new NodeSystemSpecsProvider().get();
// Even on Apple Silicon (most generous ratio) the budget is capped at
// 0.65 of total. Use 0.7 as a soft upper bound for any platform.
expect(specs.safeModelBudgetGB).toBeLessThanOrEqual(specs.totalRamGB * 0.7 + 1);
});
});