mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
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.
831 lines
24 KiB
JavaScript
831 lines
24 KiB
JavaScript
// src/data/militaryFlights.test.mjs
|
||
// Focused tests for the pure analyst-record mapper (analyst query engine seam).
|
||
// Pure function — no viewer/DOM needed; imported directly.
|
||
import { test } from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import * as Cesium from 'cesium';
|
||
import militaryFlightsLayer, {
|
||
_addMilitaryTrackingCandidateForTest,
|
||
_applyPendingMilitaryTrackingRestoreForTest,
|
||
_pendingMilitaryTrackingRestoreForTest,
|
||
_setMilitaryTrackingRefreshOutcomeForTest,
|
||
_setTrackedMilitaryRefreshStateForTest,
|
||
mapAnalystRecord,
|
||
} from './militaryFlights.js';
|
||
import {
|
||
_setTrackedOverlayHostForTest,
|
||
destroyTrackedReadout,
|
||
initTrackedReadout,
|
||
} from './trackedReadout.js';
|
||
|
||
test('share-Follow absence requires an accepted adsb.lol snapshot', async () => {
|
||
_setMilitaryTrackingRefreshOutcomeForTest({ status: 'source-unavailable' });
|
||
assert.equal(
|
||
(await militaryFlightsLayer.resolveTrackingRestoreTarget('ae1234')).status,
|
||
'source-unavailable',
|
||
);
|
||
_setMilitaryTrackingRefreshOutcomeForTest({
|
||
status: 'accepted',
|
||
ids: ['different'],
|
||
});
|
||
const missing =
|
||
await militaryFlightsLayer.resolveTrackingRestoreTarget('ae1234');
|
||
assert.equal(missing.status, 'missing');
|
||
assert.equal(missing.reason, 'target-absent-from-snapshot');
|
||
});
|
||
|
||
const FULL_INFO = {
|
||
callsign: 'RCH451 ',
|
||
registration: '05-8152',
|
||
rawLat: 31.05,
|
||
rawLon: -97.03,
|
||
altitudeFt: 28000,
|
||
speedMps: 231.5,
|
||
track: 92.1,
|
||
verticalRateMps: 5.08,
|
||
onGround: false,
|
||
klass: 'widebody',
|
||
operator: 'United States Air Force',
|
||
};
|
||
|
||
test('military stats name the feed until the server names its provider, not a fallback', () => {
|
||
const stats = militaryFlightsLayer.getStats();
|
||
assert.equal(stats.source, 'Military aircraft');
|
||
assert.equal(stats.fallback, false);
|
||
});
|
||
|
||
test('military analyst record: full record maps every contract field', () => {
|
||
const r = mapAnalystRecord('ae01ce', FULL_INFO);
|
||
assert.deepEqual(r, {
|
||
id: 'RCH451',
|
||
icao24: 'ae01ce',
|
||
callsign: 'RCH451',
|
||
lat: 31.05,
|
||
lon: -97.03,
|
||
altitudeM: 28000 * 0.3048,
|
||
speedMps: 231.5,
|
||
heading: 92.1,
|
||
verticalRateMps: 5.08,
|
||
onGround: false,
|
||
military: true,
|
||
aircraftClass: 'widebody',
|
||
originCountry: null,
|
||
operator: 'United States Air Force',
|
||
routeOrigin: null,
|
||
routeDestination: null,
|
||
});
|
||
});
|
||
|
||
test('military analyst record: military is ALWAYS true, routes/country always null', () => {
|
||
const r = mapAnalystRecord('ae01ce', undefined);
|
||
assert.equal(r.military, true);
|
||
assert.equal(r.originCountry, null);
|
||
assert.equal(r.routeOrigin, null);
|
||
assert.equal(r.routeDestination, null);
|
||
});
|
||
|
||
test('military analyst record: no callsign falls back to registration, then icao24', () => {
|
||
assert.equal(
|
||
mapAnalystRecord('ae01ce', { ...FULL_INFO, callsign: '' }).id,
|
||
'05-8152',
|
||
);
|
||
assert.equal(
|
||
mapAnalystRecord('ae01ce', { callsign: '', registration: ' ' }).id,
|
||
'ae01ce',
|
||
);
|
||
});
|
||
|
||
test('military analyst record: empty info yields nulls, never NaN/undefined', () => {
|
||
const r = mapAnalystRecord('ae01ce', {});
|
||
assert.equal(r.altitudeM, null);
|
||
assert.equal(r.onGround, false);
|
||
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('military analyst record: output is JSON-safe (no Cesium types)', () => {
|
||
const r = mapAnalystRecord('ae01ce', FULL_INFO);
|
||
assert.deepEqual(JSON.parse(JSON.stringify(r)), r);
|
||
});
|
||
|
||
test('military first update forwards caller cancellation into the feed request', async () => {
|
||
const realFetch = globalThis.fetch;
|
||
let observedSignal = null;
|
||
globalThis.fetch = (_url, options = {}) =>
|
||
new Promise((_resolve, reject) => {
|
||
observedSignal = options.signal;
|
||
options.signal?.addEventListener(
|
||
'abort',
|
||
() => {
|
||
reject(new DOMException('aborted', 'AbortError'));
|
||
},
|
||
{ once: true },
|
||
);
|
||
});
|
||
try {
|
||
const controller = new AbortController();
|
||
const work = militaryFlightsLayer.update({}, { signal: controller.signal });
|
||
await Promise.resolve();
|
||
assert.ok(observedSignal);
|
||
controller.abort();
|
||
await assert.rejects(work, { name: 'AbortError' });
|
||
assert.equal(observedSignal.aborted, true);
|
||
} finally {
|
||
globalThis.fetch = realFetch;
|
||
}
|
||
});
|
||
|
||
test('nonempty adsb.lol payload with zero usable rows cannot prove share target absence', async () => {
|
||
_setTrackedMilitaryRefreshStateForTest({
|
||
icao24: 'ae1234',
|
||
entity: { gevLabelModel: { title: 'WARM', details: [] } },
|
||
billboard: { show: false },
|
||
billboardCollection: { show: true, remove() {} },
|
||
viewer: { camera: { positionCartographic: null }, scene: {} },
|
||
meta: { rawLat: 31, rawLon: -97, onGround: false },
|
||
});
|
||
const realFetch = globalThis.fetch;
|
||
globalThis.fetch = async () => ({
|
||
ok: true,
|
||
status: 200,
|
||
json: async () => ({ ac: [null, {}, { hex: 'ae1234' }] }),
|
||
});
|
||
try {
|
||
await militaryFlightsLayer.update({
|
||
camera: { positionCartographic: null },
|
||
scene: {},
|
||
});
|
||
const resolution =
|
||
await militaryFlightsLayer.resolveTrackingRestoreTarget('ae1234');
|
||
assert.equal(resolution.status, 'source-unavailable');
|
||
assert.match(
|
||
militaryFlightsLayer.getStats().error,
|
||
/Malformed adsb\.lol aircraft rows/,
|
||
);
|
||
assert.equal(
|
||
militaryFlightsLayer.getAnalystRecords().length,
|
||
1,
|
||
'warm aircraft data is preserved',
|
||
);
|
||
} finally {
|
||
globalThis.fetch = realFetch;
|
||
}
|
||
});
|
||
|
||
test('military poll refreshes tracked callsign/altitude/kts and marks a missed poll STALE', async () => {
|
||
const icao24 = 'ae01ce';
|
||
const entity = { gevLabelModel: { title: 'OLD', details: [] } };
|
||
const billboard = {
|
||
position: Cesium.Cartesian3.fromDegrees(-97.0, 31.0, 8_000),
|
||
color: Cesium.Color.WHITE,
|
||
show: false,
|
||
};
|
||
const billboardCollection = { show: false, remove() {} };
|
||
const viewer = { camera: { positionCartographic: null }, scene: {} };
|
||
_setTrackedMilitaryRefreshStateForTest({
|
||
icao24,
|
||
entity,
|
||
billboard,
|
||
billboardCollection,
|
||
viewer,
|
||
meta: {
|
||
callsign: 'OLD2',
|
||
type: 'C17',
|
||
klass: 'widebody',
|
||
registration: '05-8152',
|
||
operator: 'USAF',
|
||
altitudeFt: 25_000,
|
||
renderAltitudeM: 7_650,
|
||
speedMps: 180,
|
||
track: 80,
|
||
onGround: false,
|
||
wasAirborne: true,
|
||
turnRateDps: 0,
|
||
rawLat: 31.0,
|
||
rawLon: -97.0,
|
||
},
|
||
});
|
||
|
||
const realFetch = globalThis.fetch;
|
||
let poll = 0;
|
||
globalThis.fetch = async () => ({
|
||
ok: true,
|
||
status: 200,
|
||
json: async () => ({
|
||
ac:
|
||
poll++ === 0
|
||
? [
|
||
{
|
||
hex: icao24,
|
||
lon: -96.9,
|
||
lat: 31.1,
|
||
alt_baro: 28_000,
|
||
alt_geom: 28_100,
|
||
track: 95,
|
||
gs: 400,
|
||
seen: 0,
|
||
seen_pos: 0,
|
||
flight: 'RCH451 ',
|
||
t: 'C17',
|
||
r: '05-8152',
|
||
ownOp: 'United States Air Force',
|
||
},
|
||
]
|
||
: [],
|
||
}),
|
||
});
|
||
|
||
try {
|
||
await militaryFlightsLayer.update(viewer);
|
||
assert.equal(entity.gevLabelModel.title, 'RCH451');
|
||
assert.match(entity.gevLabelModel.details.join(' · '), /28000 ft/);
|
||
assert.match(entity.gevLabelModel.details.join(' · '), /400 kt/);
|
||
|
||
await militaryFlightsLayer.update(viewer);
|
||
assert.match(entity.gevLabelModel.title, /STALE/);
|
||
} finally {
|
||
globalThis.fetch = realFetch;
|
||
}
|
||
});
|
||
|
||
test('cached military snapshots retain their observation time and expose stale fallback', async (t) => {
|
||
let now = 1_800_000_000_000;
|
||
const receivedAt = now;
|
||
const history = [];
|
||
const viewer = { camera: { positionCartographic: null }, scene: {} };
|
||
_setTrackedMilitaryRefreshStateForTest({
|
||
icao24: 'ae01ce',
|
||
entity: { gevLabelModel: { title: 'RCH451', details: [] } },
|
||
billboard: {
|
||
position: Cesium.Cartesian3.fromDegrees(-97, 31, 8000),
|
||
show: false,
|
||
},
|
||
billboardCollection: { show: false, remove() {} },
|
||
viewer,
|
||
history,
|
||
meta: { rawLat: 31, rawLon: -97, onGround: false },
|
||
});
|
||
let cache = 'MISS';
|
||
t.mock.method(Date, 'now', () => now);
|
||
t.mock.method(globalThis, 'fetch', async () =>
|
||
Response.json(
|
||
{
|
||
ac: [
|
||
{
|
||
hex: 'ae01ce',
|
||
lon: -97,
|
||
lat: 31,
|
||
alt_baro: 28000,
|
||
track: 95,
|
||
gs: 400,
|
||
seen: 1,
|
||
seen_pos: 2,
|
||
flight: 'RCH451',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
headers: {
|
||
'X-Feed-Cache': cache,
|
||
...(cache === 'MISS'
|
||
? {}
|
||
: { 'X-Feed-Age-Ms': String(now - receivedAt) }),
|
||
},
|
||
},
|
||
),
|
||
);
|
||
await militaryFlightsLayer.update(viewer);
|
||
assert.equal(history.length, 1);
|
||
assert.equal(history[0].epochMs, receivedAt - 2000);
|
||
for (const [status, age] of [
|
||
['HIT', 5000],
|
||
['STALE', 45000],
|
||
]) {
|
||
cache = status;
|
||
now = receivedAt + age;
|
||
await militaryFlightsLayer.update(viewer);
|
||
assert.equal(
|
||
history.length,
|
||
1,
|
||
'replayed positions cannot create a new fix',
|
||
);
|
||
assert.equal(militaryFlightsLayer.getStats().lastUpdate, receivedAt);
|
||
assert.equal(militaryFlightsLayer.getStats().stale, status === 'STALE');
|
||
assert.equal(militaryFlightsLayer.getStats().error, null);
|
||
}
|
||
cache = 'MISS';
|
||
now += 15000;
|
||
await militaryFlightsLayer.update(viewer);
|
||
assert.equal(history.length, 2, 'fresh data resumes position updates');
|
||
assert.equal(militaryFlightsLayer.getStats().lastUpdate, now);
|
||
assert.equal(militaryFlightsLayer.getStats().stale, false);
|
||
});
|
||
|
||
test('real military track path creates no native label and publishes every cached host line', () => {
|
||
const icao24 = 'ae01ce';
|
||
const position = Cesium.Cartesian3.fromDegrees(-97.03, 31.05, 8_534.4);
|
||
const now = Cesium.JulianDate.now();
|
||
const entities = new Cesium.EntityCollection();
|
||
const trackedEntityChanged = new Cesium.Event();
|
||
let trackedEntity;
|
||
let cancelledFlights = 0;
|
||
let appliedFrames = 0;
|
||
const viewer = {
|
||
entities,
|
||
trackedEntityChanged,
|
||
clock: { currentTime: now },
|
||
camera: {
|
||
cancelFlight() {
|
||
cancelledFlights += 1;
|
||
},
|
||
position: new Cesium.Cartesian3(0, -10_000, 7_000),
|
||
positionWC: new Cesium.Cartesian3(0, -10_000, 7_000),
|
||
direction: Cesium.Cartesian3.UNIT_Y,
|
||
transform: Cesium.Matrix4.IDENTITY,
|
||
viewMatrix: Cesium.Matrix4.IDENTITY,
|
||
frustum: { projectionMatrix: Cesium.Matrix4.IDENTITY },
|
||
lookAtTransform() {
|
||
appliedFrames += 1;
|
||
},
|
||
},
|
||
scene: {
|
||
canvas: { clientWidth: 1600, clientHeight: 900 },
|
||
frameState: { frameNumber: 61, mode: Cesium.SceneMode.SCENE3D },
|
||
preUpdate: new Cesium.Event(),
|
||
screenSpaceCameraController: null,
|
||
},
|
||
isDestroyed: () => false,
|
||
};
|
||
viewer.scene.camera = viewer.camera;
|
||
Object.defineProperty(viewer, 'trackedEntity', {
|
||
get: () => trackedEntity,
|
||
set(value) {
|
||
trackedEntity = value;
|
||
trackedEntityChanged.raiseEvent(value);
|
||
},
|
||
});
|
||
const billboard = {
|
||
position,
|
||
rotation: 0.4,
|
||
show: true,
|
||
width: 20,
|
||
height: 20,
|
||
color: Cesium.Color.WHITE,
|
||
scale: 1,
|
||
};
|
||
const publications = [];
|
||
const host = {
|
||
setEntries(sourceId, entries, options) {
|
||
publications.push({ sourceId, entries, options });
|
||
},
|
||
setVisible() {},
|
||
clearSource() {},
|
||
};
|
||
const realWindow = globalThis.window;
|
||
const realFetch = globalThis.fetch;
|
||
globalThis.window = new EventTarget();
|
||
const selectionEvents = [];
|
||
globalThis.window.addEventListener(
|
||
'gev:awareness-subject-selected',
|
||
(event) => {
|
||
selectionEvents.push(event.detail);
|
||
},
|
||
);
|
||
globalThis.fetch = async () => ({ ok: false });
|
||
_setTrackedOverlayHostForTest(host);
|
||
try {
|
||
initTrackedReadout(viewer);
|
||
_setTrackedMilitaryRefreshStateForTest({
|
||
icao24,
|
||
entity: null,
|
||
billboard,
|
||
billboardCollection: { show: true, remove() {} },
|
||
viewer,
|
||
tracked: false,
|
||
history: [
|
||
{
|
||
time: now,
|
||
epochMs: Date.now(),
|
||
position,
|
||
velocity: 231.5,
|
||
track: 92.1,
|
||
},
|
||
],
|
||
meta: {
|
||
...FULL_INFO,
|
||
type: 'C17',
|
||
renderAltitudeM: 8_560,
|
||
wasAirborne: true,
|
||
turnRateDps: 0,
|
||
},
|
||
});
|
||
|
||
assert.equal(
|
||
militaryFlightsLayer.trackById(icao24, { origin: 'programmatic' }),
|
||
true,
|
||
);
|
||
const entity = viewer.trackedEntity;
|
||
assert.ok(
|
||
entity instanceof Cesium.Entity,
|
||
'trackById must create the real Cesium entity',
|
||
);
|
||
assert.equal(entity.label, undefined);
|
||
assert.ok(
|
||
entities.values.every((candidate) => candidate.label === undefined),
|
||
);
|
||
assert.deepEqual(entity.gevLabelModel, {
|
||
title: 'RCH451',
|
||
details: ['C17 · 05-8152', 'United States Air Force · 28000 ft · 450 kt'],
|
||
accent: '#ffd166',
|
||
});
|
||
viewer.scene.preUpdate.raiseEvent();
|
||
const initialAppliedFrames = appliedFrames;
|
||
const initialCancelledFlights = cancelledFlights;
|
||
assert.equal(
|
||
militaryFlightsLayer.trackById(icao24, { origin: 'user' }),
|
||
true,
|
||
);
|
||
assert.equal(
|
||
cancelledFlights,
|
||
initialCancelledFlights,
|
||
'ordinary repeated tracking stays camera-idempotent',
|
||
);
|
||
assert.equal(
|
||
selectionEvents.at(-1)?.origin,
|
||
'user',
|
||
'same-target selection upgrades durable authority',
|
||
);
|
||
assert.equal(entity.gevSelectionOrigin, 'user');
|
||
assert.equal(
|
||
militaryFlightsLayer.refocusTrackedById('different-flight'),
|
||
false,
|
||
);
|
||
assert.equal(
|
||
militaryFlightsLayer.refocusTrackedById(icao24, { origin: 'voice' }),
|
||
true,
|
||
);
|
||
assert.equal(
|
||
selectionEvents.at(-1)?.origin,
|
||
'voice',
|
||
'same-target refocus forwards explicit authority',
|
||
);
|
||
assert.equal(militaryFlightsLayer.refocusTrackedById(icao24), true);
|
||
viewer.scene.preUpdate.raiseEvent();
|
||
assert.equal(
|
||
viewer.trackedEntity,
|
||
entity,
|
||
'refocus must retain the exact tracked entity',
|
||
);
|
||
assert.equal(
|
||
appliedFrames,
|
||
initialAppliedFrames + 1,
|
||
'repeated refocus keeps one camera-frame owner',
|
||
);
|
||
assert.equal(
|
||
cancelledFlights,
|
||
initialCancelledFlights + 2,
|
||
'only explicit refocus requests cancel camera flights',
|
||
);
|
||
const publication = publications.at(-1);
|
||
assert.equal(publication.sourceId, 'tracked');
|
||
const entry = publication.entries[0];
|
||
assert.equal(entry.protected, true);
|
||
assert.equal(entry.paintLane, 'tracked');
|
||
assert.equal(entry.title, entity.gevLabelModel.title);
|
||
assert.deepEqual(entry.details, entity.gevLabelModel.details);
|
||
|
||
const display = entity.position.getValue(now);
|
||
assert.ok(display, 'tracked position callback must seed its frame cache');
|
||
assert.equal(
|
||
entry.position(),
|
||
display,
|
||
'host must reuse the exact cached display Cartesian',
|
||
);
|
||
|
||
militaryFlightsLayer.setParams(
|
||
{ selectedMilitaryTrackingId: 'late001' },
|
||
{ origin: 'share-restore' },
|
||
);
|
||
assert.equal(_pendingMilitaryTrackingRestoreForTest(), 'late001');
|
||
assert.equal(
|
||
militaryFlightsLayer.trackById(icao24, { origin: 'user' }),
|
||
true,
|
||
);
|
||
assert.equal(
|
||
_pendingMilitaryTrackingRestoreForTest(),
|
||
null,
|
||
'new user selection cancels stale restore',
|
||
);
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'late001',
|
||
billboard: {
|
||
...billboard,
|
||
position: Cesium.Cartesian3.fromDegrees(-96.9, 31.1, 8_000),
|
||
},
|
||
meta: { ...FULL_INFO, callsign: 'LATE1', rawLat: 31.1, rawLon: -96.9 },
|
||
history: [],
|
||
});
|
||
_applyPendingMilitaryTrackingRestoreForTest();
|
||
assert.equal(
|
||
militaryFlightsLayer.getParams().selectedMilitaryTrackingId,
|
||
icao24,
|
||
);
|
||
|
||
militaryFlightsLayer.stopTracking();
|
||
militaryFlightsLayer.setParams(
|
||
{ selectedMilitaryTrackingId: 'late002' },
|
||
{ origin: 'local-restore' },
|
||
);
|
||
assert.equal(_pendingMilitaryTrackingRestoreForTest(), 'late002');
|
||
militaryFlightsLayer.stopTracking({ origin: 'user' });
|
||
assert.equal(
|
||
_pendingMilitaryTrackingRestoreForTest(),
|
||
null,
|
||
'explicit clear cancels stale restore',
|
||
);
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'late002',
|
||
billboard: {
|
||
...billboard,
|
||
position: Cesium.Cartesian3.fromDegrees(-96.8, 31.2, 7_000),
|
||
},
|
||
meta: { ...FULL_INFO, callsign: 'LATE2', rawLat: 31.2, rawLon: -96.8 },
|
||
history: [],
|
||
});
|
||
_applyPendingMilitaryTrackingRestoreForTest();
|
||
assert.equal(
|
||
militaryFlightsLayer.getParams().selectedMilitaryTrackingId,
|
||
null,
|
||
);
|
||
|
||
militaryFlightsLayer.setParams(
|
||
{ selectedMilitaryTrackingId: 'late003' },
|
||
{ origin: 'local-restore' },
|
||
);
|
||
assert.equal(_pendingMilitaryTrackingRestoreForTest(), 'late003');
|
||
militaryFlightsLayer.setParams({ models3d: false }, { origin: 'voice' });
|
||
assert.equal(
|
||
_pendingMilitaryTrackingRestoreForTest(),
|
||
null,
|
||
'a newer explicit non-selection option cancels stale restore',
|
||
);
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'late003',
|
||
billboard: {
|
||
...billboard,
|
||
position: Cesium.Cartesian3.fromDegrees(-97.3, 30.6, 7_000),
|
||
},
|
||
meta: { ...FULL_INFO, callsign: 'LATE3', rawLat: 30.6, rawLon: -97.3 },
|
||
history: [],
|
||
});
|
||
_applyPendingMilitaryTrackingRestoreForTest();
|
||
assert.equal(
|
||
militaryFlightsLayer.getParams().selectedMilitaryTrackingId,
|
||
null,
|
||
);
|
||
|
||
militaryFlightsLayer.setParams(
|
||
{ selectedMilitaryTrackingId: 'late004' },
|
||
{ origin: 'local-restore' },
|
||
);
|
||
assert.equal(_pendingMilitaryTrackingRestoreForTest(), 'late004');
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'late004',
|
||
billboard: {
|
||
...billboard,
|
||
position: Cesium.Cartesian3.fromDegrees(-97.2, 30.7, 6_000),
|
||
},
|
||
meta: { ...FULL_INFO, callsign: 'LATE4', rawLat: 30.7, rawLon: -97.2 },
|
||
history: [],
|
||
});
|
||
assert.equal(_applyPendingMilitaryTrackingRestoreForTest(), true);
|
||
assert.equal(
|
||
militaryFlightsLayer.getParams().selectedMilitaryTrackingId,
|
||
'late004',
|
||
);
|
||
|
||
militaryFlightsLayer.setParams(
|
||
{ selectedMilitaryTrackingId: 'late005' },
|
||
{ origin: 'local-restore' },
|
||
);
|
||
assert.equal(
|
||
militaryFlightsLayer.trackById(icao24, { origin: 'programmatic' }),
|
||
true,
|
||
);
|
||
assert.equal(
|
||
_pendingMilitaryTrackingRestoreForTest(),
|
||
'late005',
|
||
'passive autofocus cannot revoke the restored target still waiting for its feed row',
|
||
);
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'late005',
|
||
billboard: {
|
||
...billboard,
|
||
position: Cesium.Cartesian3.fromDegrees(-96.6, 31.4, 5_000),
|
||
},
|
||
meta: { ...FULL_INFO, callsign: 'LATE5', rawLat: 31.4, rawLon: -96.6 },
|
||
history: [],
|
||
});
|
||
assert.equal(_applyPendingMilitaryTrackingRestoreForTest(), true);
|
||
assert.equal(
|
||
militaryFlightsLayer.getParams().selectedMilitaryTrackingId,
|
||
'late005',
|
||
);
|
||
} finally {
|
||
militaryFlightsLayer.stopTracking();
|
||
viewer.scene.preUpdate.raiseEvent();
|
||
destroyTrackedReadout();
|
||
_setTrackedOverlayHostForTest();
|
||
globalThis.fetch = realFetch;
|
||
globalThis.window = realWindow;
|
||
}
|
||
});
|
||
|
||
/**
|
||
* The tool instructions tell the model to look a contact up with analyst_query
|
||
* and then hand that identity to track_entity. The analyst's `id` is a DISPLAY
|
||
* label — callsign, else registration, else hex — while the lookup matched
|
||
* callsigns and hex only, so a callsign-less contact came back as its tail
|
||
* number and "Nothing matched" (owner field session 2026-08-21, 23:48: three
|
||
* failed retries before a fallback stuck).
|
||
*/
|
||
test('a callsign-less contact is findable by the tail number the app displays', () => {
|
||
const icao24 = 'ae7f01';
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24,
|
||
meta: {
|
||
callsign: null,
|
||
registration: '6606',
|
||
type: 'UH60',
|
||
operator: 'US Army',
|
||
altitudeFt: 550,
|
||
speedMps: 67,
|
||
track: 210,
|
||
klass: 'helicopter',
|
||
onGround: false,
|
||
rawLat: 40.71,
|
||
rawLon: -74.01,
|
||
},
|
||
billboard: {
|
||
position: Cesium.Cartesian3.fromDegrees(-74.01, 40.71, 167),
|
||
color: Cesium.Color.WHITE,
|
||
show: true,
|
||
},
|
||
});
|
||
|
||
// The identity analyst_query hands back for this contact.
|
||
const analystId = mapAnalystRecord(icao24, {
|
||
callsign: null,
|
||
registration: '6606',
|
||
rawLat: 40.71,
|
||
rawLon: -74.01,
|
||
}).id;
|
||
assert.equal(
|
||
analystId,
|
||
'6606',
|
||
'the analyst names a callsign-less contact by its tail',
|
||
);
|
||
|
||
const found = militaryFlightsLayer.findByQuery(analystId);
|
||
assert.equal(
|
||
found?.icao24,
|
||
icao24,
|
||
'and the tracker must resolve that same identity',
|
||
);
|
||
assert.equal(
|
||
militaryFlightsLayer.findByQuery('660')?.icao24,
|
||
icao24,
|
||
'prefix match too',
|
||
);
|
||
assert.equal(
|
||
militaryFlightsLayer.findByQuery(icao24)?.icao24,
|
||
icao24,
|
||
'hex still wins outright',
|
||
);
|
||
});
|
||
|
||
test('the analyst record carries the hex key the tracker keys on', () => {
|
||
const record = mapAnalystRecord('ae7f01', {
|
||
callsign: null,
|
||
registration: '6606',
|
||
rawLat: 40.71,
|
||
rawLon: -74.01,
|
||
});
|
||
assert.equal(
|
||
record.icao24,
|
||
'ae7f01',
|
||
'a resolvable key must ride along with the display label',
|
||
);
|
||
});
|
||
|
||
test('a registration never outranks another contact’s exact callsign', () => {
|
||
// Feed order used to decide this: both identities landed in the same "exact"
|
||
// bucket, so whichever contact the upstream Map listed first won and the same
|
||
// spoken query could follow a different aircraft between polls.
|
||
const billboardAt = (lon, lat) => ({
|
||
position: Cesium.Cartesian3.fromDegrees(lon, lat, 3000),
|
||
color: Cesium.Color.WHITE,
|
||
show: true,
|
||
});
|
||
const base = {
|
||
type: 'C17',
|
||
operator: 'USAF',
|
||
altitudeFt: 25000,
|
||
speedMps: 180,
|
||
track: 90,
|
||
klass: 'widebody',
|
||
onGround: false,
|
||
};
|
||
// Registered FIRST, so insertion order favours it.
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'ae0aa1',
|
||
meta: {
|
||
...base,
|
||
callsign: null,
|
||
registration: 'ZULU777',
|
||
rawLat: 31.0,
|
||
rawLon: -97.0,
|
||
},
|
||
billboard: billboardAt(-97.0, 31.0),
|
||
});
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'ae0bb2',
|
||
meta: {
|
||
...base,
|
||
callsign: 'ZULU777',
|
||
registration: '05-9999',
|
||
rawLat: 31.2,
|
||
rawLon: -97.2,
|
||
},
|
||
billboard: billboardAt(-97.2, 31.2),
|
||
});
|
||
|
||
assert.equal(
|
||
militaryFlightsLayer.findByQuery('ZULU777')?.icao24,
|
||
'ae0bb2',
|
||
'the contact whose CALLSIGN is ZULU777 wins, not the one listed first',
|
||
);
|
||
assert.equal(
|
||
militaryFlightsLayer.findByQuery('059999')?.icao24,
|
||
'ae0bb2',
|
||
'and a separator-free registration still resolves',
|
||
);
|
||
});
|
||
|
||
test('two contacts matching at the same strength resolve deterministically', () => {
|
||
const billboardAt = (lon, lat) => ({
|
||
position: Cesium.Cartesian3.fromDegrees(lon, lat, 3000),
|
||
color: Cesium.Color.WHITE,
|
||
show: true,
|
||
});
|
||
const base = {
|
||
type: 'C130',
|
||
operator: 'USAF',
|
||
altitudeFt: 21000,
|
||
speedMps: 150,
|
||
track: 45,
|
||
klass: 'turboprop',
|
||
onGround: false,
|
||
};
|
||
// Both registrations begin with QQ7 — a same-tier prefix tie. Registered
|
||
// highest-hex first so insertion order would pick the wrong one.
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'aef002',
|
||
meta: {
|
||
...base,
|
||
callsign: null,
|
||
registration: 'QQ7-222',
|
||
rawLat: 32.0,
|
||
rawLon: -98.0,
|
||
},
|
||
billboard: billboardAt(-98.0, 32.0),
|
||
});
|
||
_addMilitaryTrackingCandidateForTest({
|
||
icao24: 'aef001',
|
||
meta: {
|
||
...base,
|
||
callsign: null,
|
||
registration: 'QQ7-111',
|
||
rawLat: 32.1,
|
||
rawLon: -98.1,
|
||
},
|
||
billboard: billboardAt(-98.1, 32.1),
|
||
});
|
||
|
||
const first = militaryFlightsLayer.findByQuery('QQ7')?.icao24;
|
||
const second = militaryFlightsLayer.findByQuery('qq7')?.icao24;
|
||
assert.equal(
|
||
first,
|
||
'aef001',
|
||
'the stable key (lowest hex) wins, not the feed order',
|
||
);
|
||
assert.equal(
|
||
second,
|
||
first,
|
||
'and the same query resolves the same way every time',
|
||
);
|
||
});
|