Files
Alta-Proxy-Tool/test/device-projection.test.js
T

110 lines
4.6 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const {
MAX_PROJECTED_PAYLOAD_BYTES,
projectDeviceHierarchy,
} = require('../src/device-projection');
function uuid(index) {
return `00000000-0000-4000-8000-${index.toString(16).padStart(12, '0')}`;
}
function rawDevice(index, overrides = {}) {
return {
guid: uuid(index),
name: `Camera ${index}`,
type: 'camera',
model: 'Synthetic',
address: `10.0.${Math.floor(index / 255)}.${index % 255}`,
server_group_id: 'site-1',
device_group_id: 'group-1',
capabilities: { localStorage: index % 2 === 0, secretCapability: 'drop-me' },
live: { display_status: 'online', private: 'drop-me' },
cookie: 'must-not-cross-ipc',
...overrides,
};
}
test('projects only allowlisted fields and honestly diagnoses ineligible devices', () => {
const payload = projectDeviceHierarchy({
devices: [rawDevice(1), rawDevice(2, { guid: 'not-a-uuid' })],
sites: [{ id: 'site-1', name: 'HQ', pending_deletion_start: null, secret: 'drop-me' }],
groups: [{ id: 'group-1', name: 'Lobby', parent_id: null, pending_deletion_start: null, secret: 'drop-me' }],
});
assert.deepEqual(payload.devices, [{
id: uuid(1), name: 'Camera 1', type: 'camera', model: 'Synthetic', address: '10.0.0.1',
siteId: 'site-1', deviceGroupId: 'group-1', displayStatus: 'online', localStorage: false,
}]);
assert.deepEqual(payload.sites, [{ id: 'site-1', name: 'HQ', pendingDeletionStart: null }]);
assert.deepEqual(payload.groups, [{ id: 'group-1', name: 'Lobby', parentId: null, pendingDeletionStart: null }]);
assert.deepEqual(payload.diagnostics.devices, { received: 2, eligible: 1, invalid: 1 });
assert.doesNotMatch(JSON.stringify(payload), /drop-me|cookie|secretCapability|private/);
});
test('projects synthetic 1,500 and 10,000 camera deployments below the 8 MiB IPC cap', () => {
for (const count of [1_500, 10_000]) {
const payload = projectDeviceHierarchy({
devices: Array.from({ length: count }, (_, index) => rawDevice(index)),
sites: [],
groups: [],
});
assert.equal(payload.devices.length, count);
assert.equal(payload.diagnostics.devices.received, count);
assert.ok(Buffer.byteLength(JSON.stringify(payload)) <= MAX_PROJECTED_PAYLOAD_BYTES);
}
});
test('malformed hierarchy metadata does not hide valid cameras', () => {
const payload = projectDeviceHierarchy({
devices: [rawDevice(7)],
sites: [null, { id: {}, name: 'bad' }],
groups: ['bad'],
metadataErrors: { sites: 'Unavailable', groups: 'Unavailable' },
});
assert.equal(payload.devices.length, 1);
assert.deepEqual(payload.sites, []);
assert.deepEqual(payload.groups, []);
assert.equal(payload.diagnostics.sites.invalid, 2);
assert.equal(payload.diagnostics.groups.invalid, 1);
assert.equal(payload.diagnostics.sites.error, 'Unavailable');
});
test('repairs lone UTF-16 surrogates without changing valid Unicode or hiding cameras', () => {
const payload = projectDeviceHierarchy({
devices: [rawDevice(8, {
name: 'Front \ud800 camera',
model: 'Model \udc00',
address: 'Hall \ud800\udc00 / \udc00',
server_group_id: 'site-\ud800',
device_group_id: 'group-\udc00',
})],
sites: [{ id: 'site-\ud800', name: 'Valid \ud83d\udcf7 \udc00', pending_deletion_start: '\ud800' }],
groups: [{ id: 'group-\udc00', name: 'Group \ud83d\udcf7 \ud800', parent_id: 'site-\ud800' }],
metadataErrors: { sites: 'warning \ud800', groups: 'warning \udc00' },
});
assert.equal(payload.devices.length, 1);
assert.equal(payload.devices[0].name, 'Front \ufffd camera');
assert.equal(payload.devices[0].model, 'Model \ufffd');
assert.equal(payload.devices[0].address, 'Hall \ud800\udc00 / \ufffd');
assert.equal(payload.devices[0].siteId, 'site-\ufffd');
assert.equal(payload.devices[0].deviceGroupId, 'group-\ufffd');
assert.deepEqual(payload.sites, [{ id: 'site-\ufffd', name: 'Valid \ud83d\udcf7 \ufffd', pendingDeletionStart: '\ufffd' }]);
assert.deepEqual(payload.groups, [{ id: 'group-\ufffd', name: 'Group \ud83d\udcf7 \ufffd', parentId: 'site-\ufffd', pendingDeletionStart: null }]);
assert.equal(payload.diagnostics.sites.error, 'warning \ufffd');
assert.doesNotMatch(JSON.stringify(payload), /[\ud800-\udfff]/u);
});
test('rejects a projected hierarchy payload above 8 MiB', () => {
const devices = Array.from({ length: 10_000 }, (_, index) => rawDevice(index, {
name: `Camera ${index} ${'x'.repeat(900)}`,
}));
assert.throws(
() => projectDeviceHierarchy({ devices, sites: [], groups: [] }),
{ code: 'PROJECTED_PAYLOAD_TOO_LARGE' },
);
});