Files
potato-mesh/web/public/assets/js/app/__tests__/trace-paths.test.js
T
l5y 844204f64d web: fix traces rendering (#535)
* web: fix traces rendering

* web: remove icon shortcuts

* web: further refine the trace routes
2025-12-08 19:48:33 +01:00

163 lines
5.8 KiB
JavaScript

/*
* Copyright © 2025-26 l5yth & contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import test from 'node:test';
import assert from 'node:assert/strict';
import { buildTraceSegments, __testUtils } from '../trace-paths.js';
const {
coerceFiniteNumber,
findNode,
resolveNodeCoordinates,
canonicalNodeIdFromNumeric,
buildNodeIndex
} = __testUtils;
test('buildTraceSegments connects source, hops, and destination when coordinates exist', () => {
const traces = [
{ id: 9_001, src: 2658361180, hops: [19_088_743], dest: 4_242_424_242, rx_time: 1700 },
];
const nodes = [
{ node_id: '2658361180', latitude: 10.5, longitude: -71.2, role: 'ROUTER' },
{ node_id: '19088743', latitude: 11.1, longitude: -70.9, role: 'CLIENT' },
{ node_id: '4242424242', latitude: 12.3, longitude: -70.2, role: 'CLIENT_HIDDEN' },
];
const segments = buildTraceSegments(traces, nodes, {
colorForNode: node => `color:${node.role}`,
limitDistance: false,
});
assert.equal(segments.length, 2);
assert.deepEqual(segments[0].latlngs, [[10.5, -71.2], [11.1, -70.9]]);
assert.deepEqual(segments[1].latlngs, [[11.1, -70.9], [12.3, -70.2]]);
assert.equal(segments[0].color, 'color:ROUTER');
assert.equal(segments[1].color, 'color:CLIENT');
assert.equal(segments[0].rxTime, 1700);
assert.deepEqual(
segments[0].pathNodes.map(node => node.node_id),
['2658361180', '19088743', '4242424242']
);
});
test('buildTraceSegments links traces to canonical node IDs when numeric references are provided', () => {
const traces = [
{ id: 9_010, src: 0xbead_f00d, hops: [0xcafe_babe], dest: 0xfeed_c0de, rx_time: 1900 },
];
const nodes = [
{ node_id: '!beadf00d', latitude: 0, longitude: 0, role: 'ROUTER' },
{ node_id: '!cafebabe', latitude: 1, longitude: 1, role: 'CLIENT' },
{ node_id: '!feedc0de', latitude: 2, longitude: 2, role: 'CLIENT' },
];
const segments = buildTraceSegments(traces, nodes, { colorForNode: () => '#abcdef' });
assert.equal(segments.length, 2);
assert.deepEqual(segments[0].latlngs, [[0, 0], [1, 1]]);
assert.deepEqual(segments[1].latlngs, [[1, 1], [2, 2]]);
assert.equal(segments[0].color, '#abcdef');
assert.equal(segments[1].color, '#abcdef');
});
test('buildTraceSegments drops paths through hops without locations', () => {
const traces = [
{ id: 9_002, src: 101, hops: [202], dest: 303 },
];
const nodes = [
{ node_id: '101', latitude: 1, longitude: 2, role: 'CLIENT' },
{ node_id: '202' },
{ node_id: '303', latitude: 3, longitude: 4, role: 'CLIENT' },
];
const segments = buildTraceSegments(traces, nodes);
assert.equal(segments.length, 0);
});
test('buildTraceSegments respects distance limits when evaluating coordinates', () => {
const traces = [
{ id: 9_003, src: 1, dest: 2 },
];
const nodes = [
{ node_id: '1', latitude: 0, longitude: 0, distance_km: 51 },
{ node_id: '2', latitude: 1, longitude: 1, distance_km: 3 },
];
const segments = buildTraceSegments(traces, nodes, { limitDistance: true, maxDistanceKm: 50 });
assert.equal(segments.length, 0);
});
test('buildTraceSegments skips invalid inputs and uses numeric lookup fallbacks', () => {
const traces = [
{ id: 9_004, src: '1001', hops: [], dest: '1002' },
];
const nodes = [
{ node_id: ' ', node_num: '1001', latitude: 0, longitude: 0 },
{ node_id: '1002', latitude: 0, longitude: 1 },
];
const segments = buildTraceSegments(traces, nodes, {
limitDistance: false,
maxDistanceKm: null,
colorForNode: () => '#123456',
});
assert.equal(segments.length, 1);
assert.deepEqual(segments[0].latlngs, [[0, 0], [0, 1]]);
assert.equal(segments[0].color, '#123456');
});
test('helper utilities coerce values and locate nodes', () => {
assert.equal(coerceFiniteNumber(null), null);
assert.equal(coerceFiniteNumber(' '), null);
assert.equal(coerceFiniteNumber('7'), 7);
assert.equal(coerceFiniteNumber('!beadf00d'), 0xbeadf00d);
assert.equal(coerceFiniteNumber('0x10'), 16);
const byId = new Map([
['!id', { node_id: '!id', latitude: 1, longitude: 2 }],
['!beadf00d', { node_id: '!beadf00d', latitude: 3, longitude: 4 }]
]);
const byNum = new Map([
[99, { node_id: '!other', latitude: 0, longitude: 0 }],
[0xbeadf00d, { node_id: '!beadf00d', latitude: 3, longitude: 4 }]
]);
assert.equal(findNode(byId, byNum, '!id').node_id, '!id');
assert.equal(findNode(byId, byNum, 99).node_id, '!other');
assert.equal(findNode(byId, new Map(), 0xbeadf00d).node_id, '!beadf00d');
assert.equal(findNode(byId, byNum, 100), null);
assert.equal(canonicalNodeIdFromNumeric(0xbeadf00d), '!beadf00d');
const coords = resolveNodeCoordinates({ latitude: 5, longitude: 6, distance_km: 10 }, { limitDistance: true, maxDistanceKm: 15 });
assert.deepEqual(coords, [5, 6]);
const outOfRange = resolveNodeCoordinates({ latitude: 0, longitude: 0, distance_km: 20 }, { limitDistance: true, maxDistanceKm: 15 });
assert.equal(outOfRange, null);
});
test('buildNodeIndex tolerates non-array inputs and buildTraceSegments short-circuits', () => {
const index = buildNodeIndex(null);
assert.ok(index.byId instanceof Map);
assert.ok(index.byNum instanceof Map);
assert.equal(index.byId.size, 0);
assert.equal(index.byNum.size, 0);
const segments = buildTraceSegments(null, null);
assert.deepEqual(segments, []);
});