044941d406
Settlement alarm (settle-pass THROW pages high; morning zero-settle alarm keyed off the Postgres ledger settle results, once per ET date, never on an empty yesterday), per-sport 3-consecutive-slot failure pager (pure opsWatch.createFailureTracker, pages once per losing streak), odds-api >=80% quota alert (once per day, Redis-deduped), systemHealth (statfs + os mem, disk>85 / mem>90 pages), daily 9 AM ET pulse (ONE notification: ledger rows yesterday via ledgerService.countRowsForDate, settles 24h, quota, disk/mem, desk line), docs/OPS-RUNBOOK.md (Uptime Kuma monitors, Coolify deploy-failure -> ntfy, phone subscription). All copy VOICE v1.1 — deadpan, numbers, no exclamation points (tests lint for it). 2398 -> 2437 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
59 lines
2.4 KiB
JavaScript
59 lines
2.4 KiB
JavaScript
'use strict';
|
|
|
|
// Session 8 (A1 board) — systemHealth: box vitals, pure + injectable.
|
|
|
|
const { getSystemHealth, healthIssues, THRESHOLDS } = require('../../src/services/systemHealth');
|
|
|
|
describe('getSystemHealth', () => {
|
|
test('computes disk_pct from statfs and mem_pct from os', async () => {
|
|
const fsImpl = { statfs: async () => ({ blocks: 1000, bavail: 400 }) }; // 60% used
|
|
const osImpl = { totalmem: () => 100, freemem: () => 25 }; // 75% used
|
|
const h = await getSystemHealth({ fsImpl, osImpl });
|
|
expect(h).toEqual({ disk_pct: 60, mem_pct: 75 });
|
|
});
|
|
|
|
test('a failed statfs degrades disk_pct to null, mem still reports', async () => {
|
|
const fsImpl = { statfs: async () => { throw new Error('EACCES'); } };
|
|
const osImpl = { totalmem: () => 10, freemem: () => 1 };
|
|
const h = await getSystemHealth({ fsImpl, osImpl });
|
|
expect(h.disk_pct).toBeNull();
|
|
expect(h.mem_pct).toBe(90);
|
|
});
|
|
|
|
test('zero/invalid totals degrade to null rather than dividing by zero', async () => {
|
|
const h = await getSystemHealth({
|
|
fsImpl: { statfs: async () => ({ blocks: 0, bavail: 0 }) },
|
|
osImpl: { totalmem: () => 0, freemem: () => 0 },
|
|
});
|
|
expect(h).toEqual({ disk_pct: null, mem_pct: null });
|
|
});
|
|
|
|
test('real (uninjected) call returns numbers on this box', async () => {
|
|
const h = await getSystemHealth();
|
|
expect(h.disk_pct === null || (h.disk_pct >= 0 && h.disk_pct <= 100)).toBe(true);
|
|
expect(h.mem_pct).toBeGreaterThanOrEqual(0);
|
|
expect(h.mem_pct).toBeLessThanOrEqual(100);
|
|
});
|
|
});
|
|
|
|
describe('healthIssues', () => {
|
|
test('thresholds: disk > 85, mem > 90 — strictly greater', () => {
|
|
expect(healthIssues({ disk_pct: 85, mem_pct: 90 })).toEqual([]);
|
|
expect(healthIssues({ disk_pct: 86, mem_pct: 90 })).toEqual(['disk at 86% (threshold 85%)']);
|
|
expect(healthIssues({ disk_pct: 40, mem_pct: 91 })).toEqual(['memory at 91% (threshold 90%)']);
|
|
expect(healthIssues({ disk_pct: 99, mem_pct: 99 })).toHaveLength(2);
|
|
});
|
|
|
|
test('null probes never flag; copy carries no exclamation points', () => {
|
|
expect(healthIssues({ disk_pct: null, mem_pct: null })).toEqual([]);
|
|
expect(healthIssues(null)).toEqual([]);
|
|
for (const line of healthIssues({ disk_pct: 99, mem_pct: 99 })) {
|
|
expect(line).not.toContain('!');
|
|
}
|
|
});
|
|
|
|
test('exported thresholds match the spec', () => {
|
|
expect(THRESHOLDS).toEqual({ disk_pct: 85, mem_pct: 90 });
|
|
});
|
|
});
|