import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import test from 'node:test'; import { createLiveTrafficRoute, enrichLiveTrafficDeviceLabels, } from '../../dist/server/http/routes/liveTrafficRoute.js'; function response() { return { writeHead(status, headers) { this.status = status; this.headers = headers; }, end(payload) { this.rawPayload = payload; this.payload = JSON.parse(payload); }, }; } const snapshot = { apiVersion: 1, epoch: 'sing-box-1700000000000', sequence: 7, observedAt: '2026-08-31T10:00:00.000Z', capabilities: { lifecycle: true, deviceAttribution: false, applicationAttribution: false, }, source: { transport: 'native', state: 'live', completeness: 'lifecycle', singBoxVersion: '1.14.0-rc.5', singBoxApiVersion: 4, error: null, unattributedUploadBytes: '0', unattributedDownloadBytes: '0', }, summary: { active: 0, recent: 0, visible: 0, recognized: 0, unresolved: 0, unresolvedOrigin: 0, truncated: false, }, connections: [], }; test('split Gateway control reads the cached socket while combined Gateway keeps no collector', () => { const index = readFileSync(new URL('../../src/server/index.ts', import.meta.url), 'utf8'); assert.match(index, /const liveTraffic = clientLiveTraffic \|\| \(remoteDataplane \? \{[\s\S]*observeLiveTraffic\(\)[\s\S]*\} : null\)/); assert.match(index, /createLiveTrafficRoute\(\{[\s\S]*traffic: liveTraffic,[\s\S]*deviceInventory: remoteDataplane \? deviceInventory : null/); assert.match(index, /clientLiveTraffic\?\.start\(\)/); assert.doesNotMatch(index, /liveTraffic\?\.start\(\)/); }); test('GET returns the injected cached snapshot without another data-source operation', async () => { let snapshots = 0; const route = createLiveTrafficRoute({ traffic: { snapshot() { snapshots += 1; return snapshot; }, }, }); const res = response(); assert.equal(await route.handle({ method: 'GET', url: '/api/traffic/live?ignored=1' }, res), true); assert.equal(snapshots, 1); assert.equal(res.status, 200); assert.deepEqual(res.headers, { 'content-type': 'application/json; charset=utf-8' }); assert.deepEqual(res.payload, snapshot); }); test('async Gateway snapshots are validated and known dev labels are enriched without changing summary', async () => { const gatewaySnapshot = { ...snapshot, capabilities: { ...snapshot.capabilities, deviceAttribution: true }, summary: { active: 300, recent: 0, visible: 256, recognized: 300, unresolved: 0, unresolvedOrigin: 299, truncated: true, }, connections: Array.from({ length: 256 }, (_, index) => ({ id: `connection-${String(index).padStart(3, '0')}`, startedAt: new Date(Date.parse(snapshot.observedAt) - index * 1000).toISOString(), closedAt: null, inbound: { tag: 'tproxy-in', type: 'tproxy' }, network: 'tcp', protocol: 'tls', source: { ip: index === 0 ? '192.168.50.7' : '192.168.50.8', port: 50_000 + index }, destination: { domain: 'example.com', ip: '203.0.113.1', port: 443, provenance: 'sing-box' }, origin: index === 0 ? { kind: 'device', id: 'dev_0011223344556677', label: '192.168.50.7', provenance: 'source-ip' } : { kind: 'unknown', id: null, label: 'Неизвестное устройство', provenance: 'unknown' }, route: { kind: 'vpn', scope: 'local-sing-box', outbound: 'proxy', outboundType: 'selector', chain: ['proxy'], rule: 'default', }, traffic: { uploadBytes: '10', downloadBytes: '20', uploadBytesPerSecond: '1', downloadBytesPerSecond: '2', }, })), }; const original = structuredClone(gatewaySnapshot); const route = createLiveTrafficRoute({ traffic: { snapshot: async () => gatewaySnapshot }, deviceInventory: { snapshot: () => ({ devices: [{ id: 'dev_0011223344556677', alias: 'Гостиная', hostname: 'tv.local', ip: '192.168.50.7', }], }), }, }); const res = response(); assert.equal(await route.handle({ method: 'GET', url: '/api/traffic/live' }, res), true); assert.equal(res.payload.connections[0].origin.label, 'Гостиная'); assert.equal(res.payload.connections[1].origin.kind, 'unknown'); assert.deepEqual(res.payload.summary, gatewaySnapshot.summary); assert.deepEqual(gatewaySnapshot, original); }); test('device label enrichment follows alias, hostname and IP without identifying unknown origins', () => { const connection = { id: 'connection-1', startedAt: snapshot.observedAt, closedAt: null, inbound: { tag: 'tproxy-in', type: 'tproxy' }, network: 'tcp', protocol: 'tls', source: { ip: '192.168.50.7', port: 50_000 }, destination: { domain: 'example.com', ip: '203.0.113.1', port: 443, provenance: 'sing-box' }, origin: { kind: 'device', id: 'dev_0011223344556677', label: '192.168.50.7', provenance: 'source-ip' }, route: { kind: 'vpn', scope: 'local-sing-box', outbound: 'proxy', outboundType: 'selector', chain: ['proxy'], rule: 'default' }, traffic: { uploadBytes: '1', downloadBytes: '2', uploadBytesPerSecond: '0', downloadBytesPerSecond: '0' }, }; const source = { ...snapshot, capabilities: { ...snapshot.capabilities, deviceAttribution: true }, summary: { ...snapshot.summary, active: 1, visible: 1, recognized: 1 }, connections: [connection], }; const labels = (device) => enrichLiveTrafficDeviceLabels(source, { devices: [device] }) .connections[0].origin.label; assert.equal(labels({ id: connection.origin.id, alias: ' ТВ ', hostname: 'tv.local', ip: '192.168.50.7' }), 'ТВ'); assert.equal(labels({ id: connection.origin.id, alias: '', hostname: 'tv.local', ip: '192.168.50.7' }), 'tv.local'); assert.equal(labels({ id: connection.origin.id, alias: '', hostname: null, ip: '192.168.50.7' }), '192.168.50.7'); assert.equal(labels({ id: 'dev_ffffffffffffffff', alias: 'Чужой', ip: connection.source.ip }), connection.origin.label); const unknown = { ...source, connections: [{ ...connection, origin: { kind: 'unknown', id: null, label: 'Неизвестно', provenance: 'unknown' } }] }; assert.equal(enrichLiveTrafficDeviceLabels(unknown, { devices: [{ ...connection.origin, id: 'dev_0011223344556677', alias: 'Не угадывать' }] }).connections[0].origin.label, 'Неизвестно'); }); test('route rejects malformed cached snapshots before responding', async () => { const route = createLiveTrafficRoute({ traffic: { snapshot: async () => ({ ...snapshot, apiVersion: 2 }) }, }); await assert.rejects( route.handle({ method: 'GET', url: '/api/traffic/live' }, response()), /apiVersion 1/, ); }); test('route ignores other paths and rejects mutation methods without reading the cache', async () => { let snapshots = 0; const route = createLiveTrafficRoute({ traffic: { snapshot: () => { snapshots += 1; return snapshot; } }, }); assert.equal(await route.handle({ method: 'GET', url: '/api/traffic/history' }, response()), false); await assert.rejects( route.handle({ method: 'POST', url: '/api/traffic/live' }, response()), (error) => error.code === 'ENDPOINT_NOT_FOUND', ); assert.equal(snapshots, 0); }); test('route is unavailable when no traffic collector exists', async () => { const route = createLiveTrafficRoute({ traffic: null }); await assert.rejects( route.handle({ method: 'GET', url: '/api/traffic/live' }, response()), (error) => error.code === 'ENDPOINT_NOT_FOUND', ); });