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>
179 lines
6.5 KiB
JavaScript
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);
|
|
});
|