collabSupport/tests/dectDiscovery.test.js
jmcqueen 2b8c4e06aa Improve /dectstatus with handset RF context and cleaner base cards.
Surface handset registrations and RSSI, tighten reboot health to 7 days,
and consolidate Base / Handsets & RF / Network & RTP sections.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 09:02:55 -04:00

179 lines
6.5 KiB
JavaScript

// Unit tests for services/dectDiscovery.js. Pure — no network, no fs.
// The interesting cases are all around the 10.x guardrail and the
// dedup/priority logic when Meraki and Webex report different IPs
// for the same base.
import test from 'node:test';
import assert from 'node:assert/strict';
import {
discoverDectBases,
isTenDotIp,
normalizeMac,
} from '../services/dectDiscovery.js';
// ─── Helpers ────────────────────────────────────────────────────────
const fixture = (overrides = {}) => ({
dectBasestations: [],
...overrides,
});
const base = (attrs = {}) => ({
mac: '6c:ab:05:f6:28:19',
name: 'Basestation A',
ipAddress: '—',
meraki: {},
...attrs,
});
// ─── isTenDotIp ─────────────────────────────────────────────────────
test('isTenDotIp: accepts 10.x/8 addresses', () => {
assert.equal(isTenDotIp('10.0.0.1'), true);
assert.equal(isTenDotIp('10.255.255.254'), true);
assert.equal(isTenDotIp('10.4.11.87'), true);
});
test('isTenDotIp: rejects non-10.x addresses', () => {
assert.equal(isTenDotIp('192.168.1.164'), false);
assert.equal(isTenDotIp('172.16.0.1'), false);
assert.equal(isTenDotIp('11.0.0.1'), false);
assert.equal(isTenDotIp('100.0.0.1'), false);
});
test('isTenDotIp: rejects malformed input', () => {
assert.equal(isTenDotIp(null), false);
assert.equal(isTenDotIp(''), false);
assert.equal(isTenDotIp('10.'), false);
assert.equal(isTenDotIp('10.0.0'), false);
assert.equal(isTenDotIp('10.0.0.256'), false);
assert.equal(isTenDotIp('10.0.0.1.5'), false);
assert.equal(isTenDotIp('not-an-ip'), false);
assert.equal(isTenDotIp(10), false);
});
// ─── normalizeMac ───────────────────────────────────────────────────
test('normalizeMac: handles various input formats', () => {
assert.equal(normalizeMac('6cab05f62819'), '6c:ab:05:f6:28:19');
assert.equal(normalizeMac('6C:AB:05:F6:28:19'), '6c:ab:05:f6:28:19');
assert.equal(normalizeMac('6c-ab-05-f6-28-19'), '6c:ab:05:f6:28:19');
assert.equal(normalizeMac('6cab.05f6.2819'), '6c:ab:05:f6:28:19');
});
test('normalizeMac: rejects bad input', () => {
assert.equal(normalizeMac(null), null);
assert.equal(normalizeMac(''), null);
assert.equal(normalizeMac('not-a-mac'), null);
assert.equal(normalizeMac('6cab05f62819aa'), null); // 14 hex chars
});
// ─── discoverDectBases ──────────────────────────────────────────────
test('discoverDectBases: empty input returns empty result (never throws)', () => {
assert.deepEqual(discoverDectBases({}), { bases: [], warnings: [] });
assert.deepEqual(discoverDectBases(null), { bases: [], warnings: [] });
assert.deepEqual(discoverDectBases({ dectBasestations: null }), { bases: [], warnings: [] });
});
test('discoverDectBases: happy path — one Meraki-enriched base on 10.x', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ meraki: { ip: '10.4.11.87' } }),
],
}));
assert.equal(result.bases.length, 1);
assert.equal(result.warnings.length, 0);
assert.deepEqual(result.bases[0], {
mac: '6c:ab:05:f6:28:19',
ip: '10.4.11.87',
name: 'Basestation A',
webexId: null,
source: 'meraki',
});
});
test('discoverDectBases: passes through Webex base id as webexId', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ id: 'webex-base-99', meraki: { ip: '10.4.11.87' } }),
],
}));
assert.equal(result.bases[0].webexId, 'webex-base-99');
});
test('discoverDectBases: prefers Meraki IP over Webex IP', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({
ipAddress: '10.4.11.100', // Webex-reported (potentially stale)
meraki: { ip: '10.4.11.87' }, // Meraki-reported (live)
}),
],
}));
assert.equal(result.bases[0].ip, '10.4.11.87');
assert.equal(result.bases[0].source, 'meraki');
});
test('discoverDectBases: falls back to Webex IP when no Meraki data', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ ipAddress: '10.4.11.87', meraki: {} }),
],
}));
assert.equal(result.bases[0].ip, '10.4.11.87');
assert.equal(result.bases[0].source, 'webex');
});
test('discoverDectBases: 10.x guardrail rejects non-corporate IPs with a warning', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ mac: 'aa:bb:cc:dd:ee:01', meraki: { ip: '192.168.1.164' } }),
base({ mac: 'aa:bb:cc:dd:ee:02', meraki: { ip: '172.16.0.100' } }),
base({ mac: 'aa:bb:cc:dd:ee:03', meraki: { ip: '10.4.11.87' } }),
],
}));
assert.equal(result.bases.length, 1);
assert.equal(result.bases[0].ip, '10.4.11.87');
assert.equal(result.warnings.length, 2);
// Both warnings should reference the offending IPs and the 10.x rule.
assert.match(result.warnings[0].reason, /192\.168\.1\.164/);
assert.match(result.warnings[0].reason, /10\.0\.0\.0\/8/);
assert.match(result.warnings[1].reason, /172\.16\.0\.100/);
});
test('discoverDectBases: rejects bases with no MAC (inventory bug)', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ mac: null, meraki: { ip: '10.4.11.87' } }),
],
}));
assert.equal(result.bases.length, 0);
assert.equal(result.warnings.length, 1);
assert.match(result.warnings[0].reason, /no MAC/i);
});
test('discoverDectBases: rejects bases with no IP anywhere', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ ipAddress: '—', meraki: {} }),
],
}));
assert.equal(result.bases.length, 0);
assert.equal(result.warnings.length, 1);
assert.match(result.warnings[0].reason, /no IP address/i);
});
test('discoverDectBases: dedups by IP and MAC (keeps first)', () => {
const result = discoverDectBases(fixture({
dectBasestations: [
base({ mac: 'aa:bb:cc:dd:ee:01', meraki: { ip: '10.4.11.87' }, name: 'first' }),
base({ mac: 'aa:bb:cc:dd:ee:02', meraki: { ip: '10.4.11.87' }, name: 'duplicate-ip' }),
base({ mac: 'aa:bb:cc:dd:ee:01', meraki: { ip: '10.4.11.88' }, name: 'duplicate-mac' }),
],
}));
assert.equal(result.bases.length, 1);
assert.equal(result.bases[0].name, 'first');
assert.equal(result.warnings.length, 2);
});