mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
Seven contributed CCTV camera packs (Ontario 511, Fintraffic Finland, DriveBC, TxDOT Texas, Estonia Tallinn + Tarktee, Warendorf, Live Traffic NSW) on a fair per-pack catalog cap; semantic camera labels; monitor planes lifted clear of the terrain from a precomputed, bundled ground-height dataset. Default catalog 800 → 3,446 cameras. Full context in PR #433. Co-authored-by: sendmebits <[email protected]> Co-authored-by: avocadoAgent <[email protected]> Co-authored-by: Alex Harvey <[email protected]> Co-authored-by: Jason Meredith <[email protected]> Co-authored-by: Daniel Smith <[email protected]> Co-authored-by: Vladimir Sobolev <[email protected]> Co-authored-by: Matthias Schneider <[email protected]> Co-authored-by: Cyber Knight <[email protected]> Co-authored-by: NovaSoft Australia <[email protected]>
329 lines
10 KiB
JavaScript
329 lines
10 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
loadTxdotSourcesFromOpenData,
|
|
normalizeTxdotDistrictPayload,
|
|
} from '../../server/providers/cctv/sources.js';
|
|
import { fetchTxdotSnapshot } from '../../server/providers/cctv/media.js';
|
|
import { TXDOT_CCTV_STATUS_URL } from '../../server/providers/cctv/constants.js';
|
|
|
|
/** Minimal valid JPEG head: SOI marker plus a byte of payload. */
|
|
const JPEG_BYTES = Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0x00]);
|
|
const JPEG_B64 = JPEG_BYTES.toString('base64');
|
|
|
|
/** One "Device Online" record in the shape GetCctvStatusListByDistrict returns. */
|
|
function cameraRow(overrides = {}) {
|
|
return {
|
|
icd_Id: 'FM-734 @ US-290 EB',
|
|
name: 'FM-734 @ US-290 EB',
|
|
latitude: 30.34396,
|
|
longitude: -97.57988,
|
|
statusDescription: 'Device Online',
|
|
hasSnapshot: true,
|
|
dirDescription: 'North',
|
|
equipLoc: { roadway: 'FM-734', direction: 'North' },
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
const districtPayload = (rows) => ({
|
|
roadwayCctvStatuses: { 'FM-734': rows },
|
|
});
|
|
|
|
function quiet(t) {
|
|
t.mock.method(console, 'log', () => {});
|
|
t.mock.method(console, 'warn', () => {});
|
|
}
|
|
|
|
test('TxDOT catalog keeps only online cameras with finite coordinates', () => {
|
|
const cameras = normalizeTxdotDistrictPayload(
|
|
districtPayload([
|
|
cameraRow({ icd_Id: 'a', name: 'a' }),
|
|
cameraRow({
|
|
icd_Id: 'b',
|
|
name: 'b',
|
|
statusDescription: 'Device Offline',
|
|
}),
|
|
cameraRow({ icd_Id: 'c', name: 'c', statusDescription: 'Device Error' }),
|
|
cameraRow({ icd_Id: 'd', name: 'd', latitude: null }),
|
|
cameraRow({ icd_Id: 'e', name: 'e', longitude: 'not-a-number' }),
|
|
cameraRow({ icd_Id: 'f', name: 'f', latitude: 0, longitude: 0 }),
|
|
cameraRow({
|
|
icd_Id: 'g',
|
|
name: 'g',
|
|
latitude: '30.1',
|
|
longitude: '-97.7',
|
|
}),
|
|
cameraRow({ icd_Id: 'h', name: 'h', hasSnapshot: false }),
|
|
]),
|
|
'AUS',
|
|
);
|
|
|
|
assert.equal(cameras.length, 1);
|
|
assert.equal(cameras[0].name, 'a');
|
|
assert.equal(cameras[0].provider, 'TxDOT');
|
|
assert.equal(cameras[0].feedType, 'image');
|
|
assert.equal(cameras[0].sourceKind, 'txdot-its');
|
|
assert.equal(cameras[0].license, 'Public TxDOT traffic camera data');
|
|
assert.equal(
|
|
cameras[0].url,
|
|
'https://its.txdot.gov/its/DistrictIts/GetCctvSnapshotByIcdId?icdId=a&districtCode=AUS',
|
|
);
|
|
assert.equal(
|
|
cameras[0].id,
|
|
`txdot-aus-${Buffer.from('a').toString('base64url')}`,
|
|
);
|
|
});
|
|
|
|
test('TxDOT ids stay distinct for distinct device keys, whatever they hash or slug to', () => {
|
|
const ids = normalizeTxdotDistrictPayload(
|
|
districtPayload([
|
|
// These two share a 32-bit FNV hash.
|
|
cameraRow({ icd_Id: 'costarring', name: 'costarring' }),
|
|
cameraRow({ icd_Id: 'liquid', name: 'liquid' }),
|
|
// These two share a lowercase slug and a hash.
|
|
cameraRow({ icd_Id: 'abcDEfaBCDEFAbcdEFABCdEfAbcdeFaB', name: 'x' }),
|
|
cameraRow({ icd_Id: 'ABcDeFABCDefaBCDeFAbCdeFabcdefAB', name: 'y' }),
|
|
]),
|
|
'AUS',
|
|
).map((camera) => camera.id);
|
|
assert.equal(new Set(ids).size, 4);
|
|
assert.equal(
|
|
Buffer.from(ids[0].replace(/^txdot-aus-/, ''), 'base64url').toString(
|
|
'utf8',
|
|
),
|
|
'costarring',
|
|
'the device key is recoverable from the id',
|
|
);
|
|
});
|
|
|
|
test('TxDOT catalog dedupes a camera listed under two roadways', () => {
|
|
const cameras = normalizeTxdotDistrictPayload(
|
|
{
|
|
roadwayCctvStatuses: {
|
|
'IH-35': [cameraRow({ icd_Id: 'shared', name: 'IH-35 @ SH-71' })],
|
|
'SH-71': [cameraRow({ icd_Id: 'shared', name: 'IH-35 @ SH-71' })],
|
|
},
|
|
},
|
|
'AUS',
|
|
);
|
|
assert.equal(cameras.length, 1);
|
|
});
|
|
|
|
test('TxDOT heading comes from an explicit travel token, never the roadway direction', () => {
|
|
const [eastbound, westbound, plain] = normalizeTxdotDistrictPayload(
|
|
districtPayload([
|
|
cameraRow({ icd_Id: 'eb', name: 'FM-734 @ US-290 EB' }),
|
|
cameraRow({ icd_Id: 'wb', name: 'FM-734 @ US-290 WB' }),
|
|
cameraRow({ icd_Id: 'plain', name: 'FM-734 @ Bellingham Dr' }),
|
|
]),
|
|
'AUS',
|
|
);
|
|
assert.equal(eastbound.headingDeg, 90);
|
|
assert.equal(eastbound.headingConfidence, 'high');
|
|
assert.equal(westbound.headingDeg, 270);
|
|
assert.equal(westbound.headingConfidence, 'high');
|
|
assert.equal(plain.headingConfidence, 'low');
|
|
assert.ok(Number.isFinite(plain.headingDeg));
|
|
});
|
|
|
|
test('TxDOT heading refuses bare cardinals in Texas route names', () => {
|
|
const cameras = normalizeTxdotDistrictPayload(
|
|
districtPayload([
|
|
cameraRow({ icd_Id: 'lamar', name: 'N Lamar Blvd @ Rundberg Ln' }),
|
|
cameraRow({ icd_Id: 'west', name: 'West Ave @ 6th St' }),
|
|
]),
|
|
'AUS',
|
|
);
|
|
for (const camera of cameras) {
|
|
assert.equal(
|
|
camera.headingConfidence,
|
|
'low',
|
|
`${camera.name} must not claim a heading`,
|
|
);
|
|
}
|
|
});
|
|
|
|
test('TxDOT camera ids are district-scoped and stable across runs', () => {
|
|
const build = (district) =>
|
|
normalizeTxdotDistrictPayload(districtPayload([cameraRow()]), district)[0]
|
|
.id;
|
|
assert.equal(build('AUS'), build('AUS'));
|
|
assert.ok(build('AUS').startsWith('txdot-aus-'));
|
|
assert.ok(build('HOU').startsWith('txdot-hou-'));
|
|
assert.notEqual(build('AUS'), build('HOU'));
|
|
});
|
|
|
|
test('TxDOT ground elevation uses a per-district prior', () => {
|
|
const at = (district) =>
|
|
normalizeTxdotDistrictPayload(districtPayload([cameraRow()]), district)[0]
|
|
.groundElevationM;
|
|
assert.equal(at('HOU'), 15);
|
|
assert.equal(at('ELP'), 1140);
|
|
assert.equal(at('AUS'), 149);
|
|
assert.equal(at('SAT'), 198);
|
|
});
|
|
|
|
test('TxDOT catalog tolerates a malformed payload', () => {
|
|
assert.deepEqual(normalizeTxdotDistrictPayload(null, 'AUS'), []);
|
|
assert.deepEqual(normalizeTxdotDistrictPayload({}, 'AUS'), []);
|
|
assert.deepEqual(
|
|
normalizeTxdotDistrictPayload({ roadwayCctvStatuses: [] }, 'AUS'),
|
|
[],
|
|
);
|
|
assert.deepEqual(
|
|
normalizeTxdotDistrictPayload(
|
|
{ roadwayCctvStatuses: { 'IH-35': null } },
|
|
'AUS',
|
|
),
|
|
[],
|
|
);
|
|
});
|
|
|
|
test('TxDOT loader fetches each configured district and ignores unknown codes', async (t) => {
|
|
quiet(t);
|
|
const saved = process.env.CCTV_TXDOT_DISTRICTS;
|
|
process.env.CCTV_TXDOT_DISTRICTS = 'aus, SAT, NOPE, aus';
|
|
const requested = [];
|
|
t.mock.method(globalThis, 'fetch', async (url) => {
|
|
requested.push(String(url));
|
|
const district = new URL(String(url)).searchParams.get('districtCode');
|
|
return Response.json(
|
|
districtPayload([
|
|
cameraRow({ icd_Id: `${district}-1`, name: `${district}-1` }),
|
|
]),
|
|
);
|
|
});
|
|
try {
|
|
const cameras = await loadTxdotSourcesFromOpenData();
|
|
assert.deepEqual(requested, [
|
|
TXDOT_CCTV_STATUS_URL('AUS'),
|
|
TXDOT_CCTV_STATUS_URL('SAT'),
|
|
]);
|
|
assert.deepEqual(cameras.map((camera) => camera.cityId).sort(), [
|
|
'tx-aus',
|
|
'tx-sat',
|
|
]);
|
|
} finally {
|
|
if (saved === undefined) delete process.env.CCTV_TXDOT_DISTRICTS;
|
|
else process.env.CCTV_TXDOT_DISTRICTS = saved;
|
|
}
|
|
});
|
|
|
|
test('TxDOT snapshot decodes JSON only from the official origin and only as JPEG', async () => {
|
|
const jsonResponse = (body) =>
|
|
new Response(JSON.stringify(body), {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
|
});
|
|
const official =
|
|
'https://its.txdot.gov/its/DistrictIts/GetCctvSnapshotByIcdId?icdId=x&districtCode=AUS';
|
|
|
|
const frame = await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
fetchImpl: async () => jsonResponse({ snippet: JPEG_B64 }),
|
|
});
|
|
assert.equal(frame?.ok, true);
|
|
assert.equal(frame?.contentType, 'image/jpeg');
|
|
assert.deepEqual(frame?.body, JPEG_BYTES);
|
|
|
|
// Off-origin with the right path, and right origin with the wrong path,
|
|
// are each refused on their own.
|
|
for (const bad of [
|
|
'https://evil.example/its/DistrictIts/GetCctvSnapshotByIcdId?icdId=x',
|
|
'https://its.txdot.gov/its/DistrictIts/Other?icdId=x',
|
|
]) {
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(bad, {
|
|
timeoutMs: 100,
|
|
fetchImpl: async () => jsonResponse({ snippet: JPEG_B64 }),
|
|
}),
|
|
null,
|
|
bad,
|
|
);
|
|
}
|
|
// A redirect is never followed, so the pin holds for the request made.
|
|
let calls = 0;
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
fetchImpl: async (_url, init) => {
|
|
calls += 1;
|
|
assert.equal(init.redirect, 'manual');
|
|
return new Response(null, {
|
|
status: 302,
|
|
headers: { location: 'https://evil.example/x.json' },
|
|
});
|
|
},
|
|
}),
|
|
null,
|
|
);
|
|
assert.equal(calls, 1);
|
|
// Junk base64 and oversize bodies are refused before decoding.
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
fetchImpl: async () => jsonResponse({ snippet: '/9!@#j/4AA=' }),
|
|
}),
|
|
null,
|
|
);
|
|
// Malformed padding is refused even though Buffer.from() would decode it.
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
fetchImpl: async () => jsonResponse({ snippet: '/9j/4AA==' }),
|
|
}),
|
|
null,
|
|
);
|
|
// A real JPEG larger than the frame cap is refused after decoding...
|
|
const bigJpeg = Buffer.concat([JPEG_BYTES, Buffer.alloc(59, 0x11)]);
|
|
assert.equal(bigJpeg.length, 64);
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
maxBytes: 8,
|
|
fetchImpl: async () =>
|
|
jsonResponse({ snippet: bigJpeg.toString('base64') }),
|
|
}),
|
|
null,
|
|
);
|
|
assert.equal(
|
|
(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
maxBytes: 64,
|
|
fetchImpl: async () =>
|
|
jsonResponse({ snippet: bigJpeg.toString('base64') }),
|
|
})
|
|
)?.body.length,
|
|
64,
|
|
'the same frame passes when it fits the cap',
|
|
);
|
|
// ...and an envelope that overflows the streaming cap never gets parsed.
|
|
const hugeJpeg = Buffer.concat([JPEG_BYTES, Buffer.alloc(8192, 0x11)]);
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
maxBytes: 8,
|
|
fetchImpl: async () =>
|
|
jsonResponse({ snippet: hugeJpeg.toString('base64') }),
|
|
}),
|
|
null,
|
|
);
|
|
const notJpeg = Buffer.from('<html>nope</html>').toString('base64');
|
|
for (const body of [
|
|
null,
|
|
{ snippet: null },
|
|
{ snippet: '' },
|
|
{ snippet: notJpeg },
|
|
]) {
|
|
assert.equal(
|
|
await fetchTxdotSnapshot(official, {
|
|
timeoutMs: 100,
|
|
fetchImpl: async () => jsonResponse(body),
|
|
}),
|
|
null,
|
|
);
|
|
}
|
|
});
|