import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
loadTallinnSourcesFromCatalog,
loadTarkteeSourcesFromDatex,
parseTarkteeDatexImages,
parseTarkteeDatexLocations,
} from '../../server/providers/cctv/sources.js';
const SAMPLE_LOCATIONS_XML = `
Test Site
59.4370
24.7530
`;
const SAMPLE_IMAGES_XML = `
https://tarktee.transpordiamet.ee/images/42/42_202608251542.jpg
image
`;
test('Tallinn catalog loads curated ristmikud stills only', () => {
const cameras = loadTallinnSourcesFromCatalog();
assert.ok(
cameras.length >= 200,
`expected a full Tallinn pack, got ${cameras.length}`,
);
for (const camera of cameras.slice(0, 25)) {
assert.match(camera.id, /^tln-/);
assert.equal(camera.cityId, 'tallinn');
assert.equal(camera.feedType, 'image');
assert.equal(camera.sourceKind, 'tallinn-ristmikud');
assert.ok(camera.url.startsWith('https://ristmikud.tallinn.ee/'));
assert.equal(camera.url, camera.snapshotUrl);
assert.ok(Number.isFinite(camera.lat) && Number.isFinite(camera.lon));
}
});
test('Tarktee DATEX parsers join location UUIDs to image URLs', () => {
const locations = parseTarkteeDatexLocations(SAMPLE_LOCATIONS_XML);
const images = parseTarkteeDatexImages(SAMPLE_IMAGES_XML);
assert.equal(locations.size, 1);
assert.equal(images.size, 1);
const id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';
assert.equal(locations.get(id)?.name, 'Test Site');
assert.equal(locations.get(id)?.lat, 59.437);
assert.equal(locations.get(id)?.lon, 24.753);
assert.equal(
images.get(id),
'https://tarktee.transpordiamet.ee/images/42/42_202608251542.jpg',
);
});
test('Tarktee DATEX image parser rejects non-official hosts', () => {
const xml = SAMPLE_IMAGES_XML.replace(
'https://tarktee.transpordiamet.ee/images/42/42_202608251542.jpg',
'https://evil.example/images/42/42.jpg',
);
const images = parseTarkteeDatexImages(xml);
assert.equal(images.size, 0);
});
test('Tarktee DATEX requests wait 30 s, past the slow answers measured live', async (t) => {
const timeouts = [];
const timeout = AbortSignal.timeout;
t.mock.method(AbortSignal, 'timeout', (ms) => {
timeouts.push(ms);
return timeout.call(AbortSignal, ms);
});
t.mock.method(console, 'log', () => {});
t.mock.method(
globalThis,
'fetch',
async (url) =>
new Response(
String(url).includes('roadCameraLocations')
? SAMPLE_LOCATIONS_XML
: SAMPLE_IMAGES_XML,
),
);
const cameras = await loadTarkteeSourcesFromDatex();
assert.deepEqual(timeouts, [30_000, 30_000]);
assert.equal(cameras.length, 1);
});