Files
gods-eye-view/src/data/aisLiveVessels.analyst.test.mjs
T
Sameh Khamis 60644c5f5d feat: name live feed routes and sources for what they serve
The flight, military and vessel feeds were named after the providers the
bundled server uses (/api/opensky, /api/adsblol/mil, /api/ais-live and
their track routes; createOpenSkySource, createAdsbLolSource,
createAisStreamSource). Any server should be able to answer a feed from
its own provider, so the feeds are now:

  /api/flights   /api/flights/track?icao24=
  /api/military  /api/military/track?hex=
  /api/vessels   /api/vessels/track?mmsi=

with createFlightSource, createMilitarySource and createVesselSource. The
old routes are removed. Each server names its provider in X-Feed-Source
(the bundled server sends OpenSky Network, adsb.lol and AISStream, so its
attribution is unchanged) and the military feed's cache state and age in
X-Feed-Cache and X-Feed-Age-Ms. Sources report the provider the server
names and fall back to the feed's name.
2026-10-03 23:10:32 -07:00

59 lines
2.0 KiB
JavaScript

// src/data/aisLiveVessels.analyst.test.mjs
// Focused tests for the pure analyst-record mapper (analyst query engine seam).
// Separate file from aisLiveVessels.test.mjs (feed-status helper) by design.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mapAnalystRecord } from './aisLiveVessels.js';
const FULL_RECORD = {
mmsi: '353136000',
name: 'EVER GIVEN',
lat: 29.55,
lon: -94.98,
speed: 12.3,
course: 214.0,
type: 'Cargo',
destination: 'OAKLAND',
};
test('ais analyst record: full record maps every contract field', () => {
const r = mapAnalystRecord(FULL_RECORD);
assert.deepEqual(r, {
id: 'EVER GIVEN',
mmsi: '353136000',
name: 'EVER GIVEN',
lat: 29.55,
lon: -94.98,
speedKts: 12.3,
courseDeg: 214.0,
shipType: 'Cargo',
destination: 'OAKLAND',
navStatus: null, // /api/vessels does not surface NavigationalStatus
});
});
test('ais analyst record: nameless vessel falls back to mmsi id', () => {
const r = mapAnalystRecord({ ...FULL_RECORD, name: ' ' });
assert.equal(r.id, '353136000');
assert.equal(r.name, null);
});
test('ais analyst record: empty strings and NaN become null, never undefined', () => {
const r = mapAnalystRecord({ mmsi: '', name: 'TUG', speed: NaN, type: '', destination: '' });
assert.equal(r.mmsi, null);
assert.equal(r.speedKts, null);
assert.equal(r.shipType, null);
assert.equal(r.destination, null);
for (const [key, value] of Object.entries(r)) {
assert.notEqual(value, undefined, `${key} must not be undefined`);
if (typeof value === 'number') assert.ok(Number.isFinite(value), `${key} must not be NaN`);
}
});
test('ais analyst record: output is JSON-safe (no Cesium types leak from the record)', () => {
// Real records carry Cesium positions/billboards — the mapper must not copy them.
const r = mapAnalystRecord({ ...FULL_RECORD, position: { x: 1 }, billboard: {}, normal: {} });
assert.deepEqual(JSON.parse(JSON.stringify(r)), r);
assert.equal('position' in r, false);
});