import assert from 'node:assert/strict'; import test from 'node:test'; import { createTrafficHistoryRoute } from '../../dist/server/http/routes/trafficHistoryRoute.js'; import { emptyTrafficHistory, parseTrafficHistoryQuery } from '../../dist/shared/trafficHistory.js'; function response() { return { writeHead(status) { this.status = status; }, end(body) { this.payload = JSON.parse(body); } }; } test('history API reads only its local source, enriches labels and returns explicit unavailable coverage', async () => { const route = createTrafficHistoryRoute({ readHistory: async (query) => ({ ...emptyTrafficHistory(query, 'live'), origins: [{ id: 'dev-a', label: 'IP' }] }), deviceInventory: { snapshot: () => ({ devices: [{ id: 'dev-a', alias: 'Ноутбук' }] }) }, }); const res = response(); assert.equal(await route.handle({ method: 'GET', url: '/api/traffic/history?range=90d&search=yandex' }, res), true); assert.equal(res.status, 200); assert.equal(res.payload.query.search, 'yandex'); assert.equal(res.payload.period.retentionDays, 90); assert.equal(res.payload.origins[0].label, 'Ноутбук'); const failed = createTrafficHistoryRoute({ readHistory: async () => { throw Error('disk'); } }); await failed.handle({ method: 'GET', url: '/api/traffic/history' }, res); assert.equal(res.payload.storage.status, 'error'); assert.equal(res.payload.coverage.partial, true); await createTrafficHistoryRoute({ readHistory: null }).handle({ method: 'GET', url: '/api/traffic/history' }, res); assert.equal(res.payload.source, 'disabled'); }); test('history API rejects invalid queries and mutation methods before reading storage', async () => { let reads = 0; const route = createTrafficHistoryRoute({ readHistory: async (query) => { reads++; return emptyTrafficHistory(query); } }); for (const params of ['range=forever', 'level=ip%3BDROP', 'route=no', 'offset=-1', 'until=Infinity', 'search=%00', `search=${'x'.repeat(201)}`]) { await assert.rejects(route.handle({ method: 'GET', url: `/api/traffic/history?${params}` }, response()), (error) => error.code === 'REQUEST_INVALID'); } await assert.rejects(route.handle({ method: 'DELETE', url: '/api/traffic/history' }, response()), (error) => error.code === 'ENDPOINT_NOT_FOUND'); assert.equal(await route.handle({ method: 'GET', url: '/api/state' }, response()), false); assert.equal(reads, 0); assert.equal(parseTrafficHistoryQuery(new URLSearchParams('range=90d')).range, '90d'); });