import { describe, expect, test } from 'bun:test'; import { DISK_BLOCKED_PERCENT, DISK_DRIFT_PERCENT, type DiskUsageResult, auditDiskSpace, } from './disk-space'; function usage(over: Partial = {}): DiskUsageResult { return { hostname: 'celilo-mgr', ipAddress: '10.0.120.10', usedPercent: 10, availableBytes: 102 * 1024 ** 3, ...over, }; } describe('auditDiskSpace', () => { test('a healthy filesystem produces no finding', () => { expect(auditDiskSpace({ results: [usage({ usedPercent: 10 })] })).toEqual([]); }); test('just below the threshold stays quiet', () => { const findings = auditDiskSpace({ results: [usage({ usedPercent: DISK_DRIFT_PERCENT - 1 })] }); expect(findings).toEqual([]); }); test('at the drift threshold reports drift, naming host and usage', () => { const findings = auditDiskSpace({ results: [usage({ usedPercent: DISK_DRIFT_PERCENT })] }); expect(findings).toHaveLength(1); expect(findings[0]?.severity).toBe('drift'); expect(findings[0]?.code).toBe('disk_low'); expect(findings[0]?.message).toContain('celilo-mgr'); expect(findings[0]?.message).toContain('85%'); }); test('at the blocked threshold escalates to blocked', () => { const findings = auditDiskSpace({ results: [usage({ usedPercent: DISK_BLOCKED_PERCENT })] }); expect(findings[0]?.severity).toBe('blocked'); expect(findings[0]?.code).toBe('disk_critical'); }); // The alert has to name the host to act on, and suppression resolves a // machine's ancestor key from its HOSTNAME (alerting/suppression.ts). A UUID // subject produces a key suppression can never match — that is #596, filed // against machines_reachable. This check must not repeat it. test('subjects the finding on the hostname, never a UUID', () => { const findings = auditDiskSpace({ results: [usage({ hostname: 'iot', usedPercent: 99 })], }); expect(findings[0]?.subject).toBe('iot'); }); test('only the offending host is reported in a mixed fleet', () => { const findings = auditDiskSpace({ results: [ usage({ hostname: 'celilo-mgr', usedPercent: 96 }), usage({ hostname: 'iot', usedPercent: 12 }), usage({ hostname: 'dns-ext', usedPercent: 40 }), ], }); expect(findings).toHaveLength(1); expect(findings[0]?.subject).toBe('celilo-mgr'); }); test('reports free space alongside the percentage', () => { const findings = auditDiskSpace({ results: [usage({ usedPercent: 96, availableBytes: 6 * 1024 ** 3 })], }); expect(findings[0]?.message).toContain('6.0 GB free'); }); // Unmeasurable must not read as healthy — but it must not page either, since // machines_reachable is already alerting for the same dead host. test('an unmeasurable host is recorded as unmeasured, not as healthy', () => { const findings = auditDiskSpace({ results: [usage({ hostname: 'iot', usedPercent: null, message: 'ssh: connect timed out' })], }); expect(findings).toHaveLength(1); // Was `todo`, because that was the only non-paging severity available. // `unmeasured` is what it always meant, and it stops the verdict returning // READY. expect(findings[0]?.severity).toBe('unmeasured'); expect(findings[0]?.code).toBe('disk_unmeasured'); expect(findings[0]?.details).toContain('timed out'); }); test('an unreachable host does not hide a filling one', () => { const findings = auditDiskSpace({ results: [ usage({ hostname: 'iot', usedPercent: null, message: 'unreachable' }), usage({ hostname: 'celilo-mgr', usedPercent: 97 }), ], }); expect(findings.map((f) => f.subject).sort()).toEqual(['celilo-mgr', 'iot']); expect(findings.find((f) => f.subject === 'celilo-mgr')?.severity).toBe('blocked'); }); test('every finding carries the disk_space category', () => { const findings = auditDiskSpace({ results: [usage({ usedPercent: 99 }), usage({ hostname: 'iot', usedPercent: null })], }); expect(findings.every((f) => f.category === 'disk_space')).toBe(true); }); });