// Unit tests for services/enrichment/alarmSemantics.js // // Coverage targets: // - Known codes map to their expected category // - Unknown codes fall through to 'other' (never throw) // - Humanizer returns a friendly string; unknown codes become // Title-Cased words rather than a raw constant // - rollupAlarms collapses (code+severity) tuples, preserves the // newest timestamp, and orders critical → major → minor // - countByCategory sums correctly and defaults missing fields to 0 // - humanizeAge produces the expected "just now / Nm / Nh / Nd" bands // - humanizeWindow formats 15/60/360/1440 minutes as 15m/1h/6h/1d import test from 'node:test'; import assert from 'node:assert/strict'; import { categorizeAlarm, humanizeAlarmCode, rollupAlarms, countByCategory, humanizeAge, humanizeWindow, isVoiceRelevantAlarm, coerceAlarmTsMs, } from '../services/enrichment/alarmSemantics.js'; // ─── categorizeAlarm ───────────────────────────────────────────────── test('categorizeAlarm: overlay codes bucket as overlay', () => { for (const code of [ 'NETWORK_ANYNETLINK_DOWN', 'NETWORK_VPNLINK_DOWN', 'NETWORK_VPNLINK_FLAP', 'NETWORK_SITE_UNREACHABLE', 'NETWORK_STANDBY_LINK_DOWN', 'SITE_CONNECTIVITY_DEGRADED', ]) { assert.equal(categorizeAlarm(code), 'overlay', `${code} → overlay`); } }); test('categorizeAlarm: physical WAN codes bucket as physical', () => { for (const code of [ 'NETWORK_INTERNET_DOWN', 'DEVICE_INTERFACE_DOWN', 'DEVICE_INTERFACE_STATE_CHANGED', 'NETWORK_LTE_LINK_DOWN', ]) { assert.equal(categorizeAlarm(code), 'physical', `${code} → physical`); } }); test('categorizeAlarm: device / ION codes bucket as device', () => { for (const code of [ 'DEVICE_HB_MISSED', 'DEVICE_UNREACHABLE', 'DEVICE_HIGH_CPU', 'DEVICE_REBOOT', ]) { assert.equal(categorizeAlarm(code), 'device'); } }); test('categorizeAlarm: unknown / falsy → other (never throws)', () => { assert.equal(categorizeAlarm('SOMETHING_BRAND_NEW'), 'other'); assert.equal(categorizeAlarm(''), 'other'); assert.equal(categorizeAlarm(null), 'other'); assert.equal(categorizeAlarm(undefined), 'other'); }); test('categorizeAlarm: case-insensitive on input', () => { assert.equal(categorizeAlarm('network_anynetlink_down'), 'overlay'); }); // ─── humanizeAlarmCode ─────────────────────────────────────────────── test('humanizeAlarmCode: known codes → friendly labels', () => { assert.equal(humanizeAlarmCode('NETWORK_ANYNETLINK_DOWN'), 'SD-WAN overlay tunnel down'); assert.equal(humanizeAlarmCode('DEVICE_HB_MISSED'), 'ION heartbeat missed'); assert.equal(humanizeAlarmCode('NETWORK_INTERNET_DOWN'), 'Internet WAN circuit down'); }); test('humanizeAlarmCode: unknown code → Title Cased fallback (not raw constant)', () => { assert.equal(humanizeAlarmCode('SOMETHING_BRAND_NEW_DOWN'), 'Something Brand New Down'); }); test('humanizeAlarmCode: falsy → generic fallback', () => { assert.equal(humanizeAlarmCode(''), 'Unknown alarm'); assert.equal(humanizeAlarmCode(null), 'Unknown alarm'); }); // ─── rollupAlarms ──────────────────────────────────────────────────── test('rollupAlarms: collapses (code + severity) tuples, keeps newest ts', () => { const samples = [ { code: 'X', severity: 'major', ts: '2026-07-09T10:00:00Z' }, { code: 'X', severity: 'major', ts: '2026-07-09T12:00:00Z' }, { code: 'X', severity: 'major', ts: '2026-07-09T09:00:00Z' }, { code: 'Y', severity: 'critical', ts: '2026-07-09T08:00:00Z' }, ]; const rollups = rollupAlarms(samples); assert.equal(rollups.length, 2); // Critical severity floats to the top regardless of count. assert.equal(rollups[0].code, 'Y'); assert.equal(rollups[0].count, 1); assert.equal(rollups[1].code, 'X'); assert.equal(rollups[1].count, 3); // Newest ts survives. assert.equal(rollups[1].newestTs, '2026-07-09T12:00:00Z'); }); test('rollupAlarms: sort — critical > major > minor, ties broken by count desc', () => { const rollups = rollupAlarms([ { code: 'A', severity: 'minor', ts: 't1' }, { code: 'B', severity: 'major', ts: 't2' }, { code: 'C', severity: 'critical', ts: 't3' }, { code: 'D', severity: 'major', ts: 't4' }, { code: 'D', severity: 'major', ts: 't5' }, ]); assert.deepEqual( rollups.map((r) => r.code), ['C', 'D', 'B', 'A'], 'critical (C), then major sorted by count (D×2, B×1), then minor', ); }); test('rollupAlarms: null/empty → []', () => { assert.deepEqual(rollupAlarms(null), []); assert.deepEqual(rollupAlarms([]), []); assert.deepEqual(rollupAlarms(undefined), []); }); // ─── countByCategory ───────────────────────────────────────────────── test('countByCategory: counts overlay/physical/device/other + total', () => { const c = countByCategory([ { code: 'NETWORK_ANYNETLINK_DOWN' }, { code: 'NETWORK_ANYNETLINK_DOWN' }, { code: 'NETWORK_INTERNET_DOWN' }, { code: 'DEVICE_HB_MISSED' }, { code: 'UNRECOGNIZED_FOO' }, ]); assert.deepEqual(c, { overlay: 2, physical: 1, device: 1, other: 1, total: 5, }); }); test('countByCategory: empty → all zeros', () => { assert.deepEqual(countByCategory([]), { overlay: 0, physical: 0, device: 0, other: 0, total: 0, }); }); // ─── humanizeAge ───────────────────────────────────────────────────── test('humanizeAge: coarse buckets', () => { const now = Date.parse('2026-07-09T14:00:00Z'); const at = (offsetSec) => humanizeAge(new Date(now - offsetSec * 1000).toISOString(), now); assert.equal(at(10), 'just now'); assert.equal(at(120), '2m ago'); assert.equal(at(3600 * 2), '2h ago'); assert.equal(at(86400 * 3), '3d ago'); }); test('humanizeAge: missing / invalid ts → empty string', () => { assert.equal(humanizeAge(null), ''); assert.equal(humanizeAge(undefined), ''); assert.equal(humanizeAge('not-a-date'), ''); }); // ─── humanizeWindow ────────────────────────────────────────────────── test('humanizeWindow: canonical values', () => { assert.equal(humanizeWindow(15), '15m'); assert.equal(humanizeWindow(45), '45m'); assert.equal(humanizeWindow(60), '1h'); assert.equal(humanizeWindow(360), '6h'); assert.equal(humanizeWindow(1440), '1d'); assert.equal(humanizeWindow(2880), '2d'); assert.equal(humanizeWindow(10080), '7d', 'the new default WAN window must round-trip cleanly'); }); test('isVoiceRelevantAlarm: overlay/physical/device yes, other no', () => { assert.equal(isVoiceRelevantAlarm('NETWORK_VPNLINK_DOWN'), true); assert.equal(isVoiceRelevantAlarm('NETWORK_INTERNET_DOWN'), true); assert.equal(isVoiceRelevantAlarm('DEVICE_REBOOT'), true); assert.equal(isVoiceRelevantAlarm('DHCP_FAILURE'), false); }); test('coerceAlarmTsMs: ISO and epoch', () => { assert.equal(coerceAlarmTsMs('2025-01-01T00:00:00Z'), Date.parse('2025-01-01T00:00:00Z')); assert.equal(coerceAlarmTsMs(1_700_000_000_000), 1_700_000_000_000); assert.equal(coerceAlarmTsMs(null), null); });