mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
182 lines
5.2 KiB
JavaScript
182 lines
5.2 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { createWfigsPerimeterSource } from './source.js';
|
|
import { normalizeFirePerimeterSnapshot } from './records.js';
|
|
import { firePerimetersProxy } from '../../../server/providers/firePerimeters.js';
|
|
|
|
const ring = [
|
|
[-108.1, 35.2],
|
|
[-108.0, 35.2],
|
|
[-108.0, 35.3],
|
|
[-108.1, 35.2],
|
|
];
|
|
const validPayload = {
|
|
features: [
|
|
{
|
|
id: 1,
|
|
geometry: { type: 'Polygon', coordinates: [ring] },
|
|
properties: { attr_UniqueFireIdentifier: '2026-NMGNF-000123' },
|
|
},
|
|
],
|
|
};
|
|
|
|
test('a successful response yields normalized perimeter rows', async () => {
|
|
let requested;
|
|
const source = createWfigsPerimeterSource({
|
|
fetchImpl: async (url) => {
|
|
requested = String(url);
|
|
return Response.json({
|
|
rows: normalizeFirePerimeterSnapshot(validPayload),
|
|
});
|
|
},
|
|
});
|
|
const rows = await source.getSnapshot();
|
|
assert.equal(rows.length, 1);
|
|
assert.equal(rows[0].stableId, '2026-NMGNF-000123');
|
|
assert.equal(requested, '/api/fire-perimeters');
|
|
});
|
|
|
|
test('a truncated response pages until the feed is complete', async () => {
|
|
const pageRing = (id) => ({
|
|
id,
|
|
geometry: { type: 'Polygon', coordinates: [ring] },
|
|
properties: { attr_UniqueFireIdentifier: `fire-${id}` },
|
|
});
|
|
const requests = [];
|
|
let handler;
|
|
const plugin = firePerimetersProxy({
|
|
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),
|
|
['fire-1', 'fire-2', 'fire-3'],
|
|
);
|
|
assert.deepEqual(requests, [null, '1', '2']);
|
|
});
|
|
|
|
test('an upstream failure surfaces its HTTP status', async () => {
|
|
const source = createWfigsPerimeterSource({
|
|
fetchImpl: async () => ({ ok: false, status: 503 }),
|
|
});
|
|
await assert.rejects(source.getSnapshot(), /WFIGS HTTP 503/);
|
|
});
|
|
|
|
test('a malformed successful response is never accepted as an empty snapshot', async () => {
|
|
for (const payload of [{}, { rows: null }, { rows: {} }]) {
|
|
const source = createWfigsPerimeterSource({
|
|
fetchImpl: async () => Response.json(payload),
|
|
});
|
|
await assert.rejects(source.getSnapshot(), /Malformed perimeter snapshot/);
|
|
}
|
|
});
|
|
|
|
test('response-body completion honors cancellation without replacing records', async () => {
|
|
const abort = new AbortController();
|
|
const source = createWfigsPerimeterSource({
|
|
fetchImpl: async () => ({
|
|
ok: true,
|
|
headers: new Headers(),
|
|
text: async () => {
|
|
abort.abort();
|
|
return JSON.stringify({
|
|
rows: normalizeFirePerimeterSnapshot(validPayload),
|
|
});
|
|
},
|
|
}),
|
|
});
|
|
await assert.rejects(source.getSnapshot({ signal: abort.signal }), {
|
|
name: 'AbortError',
|
|
});
|
|
});
|
|
|
|
test('a failed refresh serves the last snapshot marked stale for a day, then refuses', async () => {
|
|
let clock = 1_000_000_000;
|
|
let up = true;
|
|
const plugin = firePerimetersProxy({
|
|
now: () => clock,
|
|
fetchImpl: async () => {
|
|
if (!up) throw new Error('WFIGS unreachable');
|
|
return Response.json(validPayload);
|
|
},
|
|
});
|
|
let handler;
|
|
plugin.configureServer({
|
|
middlewares: { use: (_path, callback) => (handler = callback) },
|
|
});
|
|
const ask = async () => {
|
|
const reply = {};
|
|
await handler(
|
|
{ url: '/', method: 'GET', socket: { remoteAddress: '127.0.0.1' } },
|
|
{
|
|
writeHead(status, headers) {
|
|
reply.status = status;
|
|
reply.staleHeader = headers?.['X-Data-Stale'] === 'true';
|
|
},
|
|
end(body) {
|
|
reply.body = JSON.parse(body);
|
|
},
|
|
},
|
|
);
|
|
return reply;
|
|
};
|
|
const fresh = await ask();
|
|
assert.equal(fresh.status, 200);
|
|
assert.equal(fresh.body.stale, undefined);
|
|
up = false;
|
|
clock += 23 * 60 * 60 * 1000;
|
|
const stale = await ask();
|
|
assert.equal(stale.status, 200);
|
|
assert.equal(stale.staleHeader, true);
|
|
assert.equal(stale.body.stale, true);
|
|
assert.equal(stale.body.fetchedAt, fresh.body.fetchedAt);
|
|
clock += 2 * 60 * 60 * 1000;
|
|
assert.equal((await ask()).status, 502, 'a day-old snapshot is not served');
|
|
});
|
|
|
|
test('the snapshot detail carries the proxy staleness and fetch time', async () => {
|
|
const fetchedAt = Date.UTC(2026, 9, 25, 12);
|
|
const source = createWfigsPerimeterSource({
|
|
fetchImpl: async () => Response.json({ rows: [], stale: true, fetchedAt }),
|
|
});
|
|
assert.deepEqual(await source.getSnapshotDetail(), {
|
|
rows: [],
|
|
stale: true,
|
|
fetchedAt,
|
|
});
|
|
assert.deepEqual(await source.getSnapshot(), []);
|
|
});
|
|
|
|
test('getSnapshot works when taken off its source object', async () => {
|
|
const { getSnapshot } = createWfigsPerimeterSource({
|
|
fetchImpl: async () => Response.json({ rows: [] }),
|
|
});
|
|
assert.deepEqual(await getSnapshot(), []);
|
|
});
|