Files
gods-eye-view/src/layers/droneAirspace/source.test.mjs
T
Sameh Khamis 8e63420f06 fix(drone-airspace): show stale FAA snapshots as stale and cap them at a day
The source dropped the proxy's stale flag and fetch time, so the layer row
read nominal and freshly updated through an outage, and the proxy served its
last snapshot indefinitely. Carry stale and fetchedAt through the source as
Fire Perimeters does, date a stale snapshot by its fetch, and stop serving a
snapshot more than 24 hours old.
2026-11-03 14:34:01 -08:00

120 lines
3.2 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { createDroneAirspaceSource } from './source.js';
import { normalizeDroneAirspaceSnapshot } from './records.js';
import { droneAirspaceProxy } from '../../../server/providers/droneAirspace.js';
const ring = [
[-77.04, 38.89],
[-77.03, 38.89],
[-77.03, 38.9],
[-77.04, 38.89],
];
const validPayload = {
features: [
{
id: 310,
geometry: { type: 'Polygon', coordinates: [ring] },
properties: {
NAME: 'P-56',
TYPE_CODE: 'P',
OBJECTID: 310,
},
},
],
};
test('a successful response yields normalized zone rows', async () => {
let requested;
const source = createDroneAirspaceSource({
fetchImpl: async (url) => {
requested = String(url);
return Response.json({
rows: normalizeDroneAirspaceSnapshot(validPayload),
});
},
});
const rows = await source.getSnapshot();
assert.equal(rows.length, 1);
assert.equal(rows[0].stableId, '310');
assert.equal(requested, '/api/drone-airspace');
});
test('a truncated response pages until the feed is complete', async () => {
const pageRing = (id) => ({
id,
geometry: { type: 'Polygon', coordinates: [ring] },
properties: { NAME: `P-${id}`, TYPE_CODE: 'P', OBJECTID: id },
});
const requests = [];
let handler;
const plugin = droneAirspaceProxy({
fetchImpl: async (url) => {
requests.push(new URL(String(url)).searchParams.get('resultOffset'));
const page = requests.length;
return Response.json({
features: [pageRing(page)],
properties: { exceededTransferLimit: page < 3 },
});
},
});
plugin.configureServer({
middlewares: {
use: (_path, callback) => {
handler = callback;
},
},
});
let payload;
await handler(
{ url: '/', method: 'GET' },
{
writeHead(status) {
assert.equal(status, 200);
},
end(body) {
payload = JSON.parse(body);
},
},
);
const rows = payload.rows;
assert.deepEqual(
rows.map((row) => row.stableId),
['1', '2', '3'],
);
assert.deepEqual(requests, [null, '1', '2']);
});
test('an upstream failure surfaces its HTTP status', async () => {
const source = createDroneAirspaceSource({
fetchImpl: async () => ({ ok: false, status: 503 }),
});
await assert.rejects(source.getSnapshot(), /FAA SUA HTTP 503/);
});
test('a malformed successful response is never accepted as an empty snapshot', async () => {
for (const payload of [{}, { rows: null }, { rows: {} }]) {
const source = createDroneAirspaceSource({
fetchImpl: async () => Response.json(payload),
});
await assert.rejects(
source.getSnapshot(),
/Malformed drone airspace snapshot/,
);
}
});
test('the snapshot detail carries the proxy staleness and fetch time', async () => {
const fetchedAt = Date.UTC(2026, 10, 3, 12);
const rows = normalizeDroneAirspaceSnapshot(validPayload);
const source = createDroneAirspaceSource({
fetchImpl: async () => Response.json({ rows, stale: true, fetchedAt }),
});
assert.deepEqual(await source.getSnapshotDetail(), {
rows,
stale: true,
fetchedAt,
});
assert.deepEqual(await source.getSnapshot(), rows);
});