mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
The first formal release. - One-click install via Pinokio; keyless boot lands on a live Esri World Imagery satellite globe with keyless terrain, with automatic OSM fallback and graceful degradation when terrain is unavailable. - Provider Settings (the POWER UP panel): add, replace, or remove API keys inside the app; credential files made owner-only before any secret is written; external keys shown read-only; the panel refuses shared or proxied servers. - Keyless capability responses for the optional HUD summary and place search. - Aircraft-identity voice answers cover operator, type, and route, and say so plainly when enrichment is unavailable. - README rewritten keyless-first; concise 0.1.0 changelog section; CI workflow included. Gates: 2,672 unit tests pass / 0 fail, build clean, tracking regression 108/108, map-source tray QA pass, setup doctor ready.
162 lines
6.3 KiB
JavaScript
162 lines
6.3 KiB
JavaScript
// src/data/fireAnchors.test.mjs — DEM ground anchors for rendered FIRMS
|
|
// detections (owner field finding 2026-07-21: close-zoom fire dots read as
|
|
// buried under high terrain because anchors sat at ellipsoid height 0).
|
|
//
|
|
// Locks the module's two jobs:
|
|
// fireAnchorHeight(lat, lon) — synchronous warm-cache read: shared
|
|
// ground floor + lift, or 0 when the floor isn't warm (the pre-fix anchor).
|
|
// warmFireAnchorFloors(points) — batched, sequential (never concurrent)
|
|
// resolve of the cold floor cells behind a rendered detection set.
|
|
// Resolves true only when at least one requested point actually gained a
|
|
// warm floor — a failed resolve reports false so render → warm → re-render
|
|
// chains terminate instead of looping against a down proxy.
|
|
//
|
|
// `fetch` is injected via `globalThis.fetch` (no real network), same pattern
|
|
// as terrainHeights.test.mjs. The terrainHeights/groundFloor module caches
|
|
// persist across tests in this file, so each test uses distinct coordinates.
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
FIRE_ANCHOR_LIFT_M,
|
|
fireAnchorHeight,
|
|
warmFireAnchorFloors,
|
|
_resetFireAnchorsForTest,
|
|
} from './fireAnchors.js';
|
|
import { reportMeshFloorCell, setMeshFloorPreferred } from './groundFloor.js';
|
|
|
|
/** Installs a fake fetch for the duration of `fn`, restoring the original after. */
|
|
async function withFakeFetch(fakeFetch, fn) {
|
|
const original = globalThis.fetch;
|
|
globalThis.fetch = fakeFetch;
|
|
try {
|
|
return await fn();
|
|
} finally {
|
|
globalThis.fetch = original;
|
|
}
|
|
}
|
|
|
|
/** Parses the `points=lon,lat;…` query of a /api/terrain/heights request URL. */
|
|
function parsePoints(url) {
|
|
const raw = decodeURIComponent(String(url).split('points=')[1] || '');
|
|
return raw.split(';').filter(Boolean).map((pair) => {
|
|
const [lon, lat] = pair.split(',').map(Number);
|
|
return { lon, lat };
|
|
});
|
|
}
|
|
|
|
/** Fake proxy answering ellipsoid = lon + lat per requested point. */
|
|
function echoFetch(log) {
|
|
return async (url) => {
|
|
const points = parsePoints(url);
|
|
log.push(points);
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
json: async () => ({
|
|
results: points.map(({ lon, lat }) => ({ lon, lat, elevation: 0, geoid: 0, ellipsoid: lon + lat })),
|
|
}),
|
|
};
|
|
};
|
|
}
|
|
|
|
test('fireAnchorHeight: unknown floor anchors at 0 (pre-fix behavior preserved)', () => {
|
|
_resetFireAnchorsForTest();
|
|
assert.equal(fireAnchorHeight(10.001, 10.001), 0);
|
|
});
|
|
|
|
test('fireAnchorHeight: warm shared ground floor anchors at floor + lift', () => {
|
|
_resetFireAnchorsForTest();
|
|
setMeshFloorPreferred(true);
|
|
// Seed via the mesh-cell path — proves fires read the SAME choke point
|
|
// (cachedGroundFloor) every other ground-adjacent consumer uses.
|
|
reportMeshFloorCell(51.301, -122.401, 1400);
|
|
assert.equal(fireAnchorHeight(51.3012, -122.4008), 1400 + FIRE_ANCHOR_LIFT_M);
|
|
});
|
|
|
|
test('warmFireAnchorFloors: one batched request, deduped to coarse cells', async () => {
|
|
_resetFireAnchorsForTest();
|
|
const log = [];
|
|
await withFakeFetch(echoFetch(log), async () => {
|
|
const warmed = await warmFireAnchorFloors([
|
|
{ lat: 20.0001, lon: 30.0001 }, // same ~111 m cell as the next point
|
|
{ lat: 20.0004, lon: 30.0004 },
|
|
{ lat: 20.101, lon: 30.101 }, // distinct cell
|
|
]);
|
|
assert.equal(warmed, true);
|
|
assert.equal(log.length, 1, 'one network request for the whole batch');
|
|
assert.equal(log[0].length, 2, 'two unique coarse cells, not three points');
|
|
});
|
|
// The warm floor is immediately readable at full precision…
|
|
assert.equal(fireAnchorHeight(20.0001, 30.0001), 50 + FIRE_ANCHOR_LIFT_M);
|
|
// …and for every other detection sharing the cell.
|
|
assert.equal(fireAnchorHeight(20.0004, 30.0004), 50 + FIRE_ANCHOR_LIFT_M);
|
|
});
|
|
|
|
test('warmFireAnchorFloors: warm cells never refetch (one lookup per fire ever)', async () => {
|
|
_resetFireAnchorsForTest();
|
|
const log = [];
|
|
await withFakeFetch(echoFetch(log), async () => {
|
|
await warmFireAnchorFloors([{ lat: 21.001, lon: 31.001 }]);
|
|
assert.equal(log.length, 1);
|
|
const warmedAgain = await warmFireAnchorFloors([
|
|
{ lat: 21.001, lon: 31.001 },
|
|
{ lat: 21.0012, lon: 31.0011 }, // same cell, different detection
|
|
]);
|
|
assert.equal(warmedAgain, false, 'nothing was cold, so nothing warmed');
|
|
assert.equal(log.length, 1, 'no second network request');
|
|
});
|
|
});
|
|
|
|
test('warmFireAnchorFloors: overlapping calls run sequentially, never concurrently', async () => {
|
|
_resetFireAnchorsForTest();
|
|
let release;
|
|
const gate = new Promise((resolve) => { release = resolve; });
|
|
let concurrent = 0;
|
|
let maxConcurrent = 0;
|
|
const log = [];
|
|
await withFakeFetch(async (url) => {
|
|
concurrent += 1;
|
|
maxConcurrent = Math.max(maxConcurrent, concurrent);
|
|
const points = parsePoints(url);
|
|
log.push(points);
|
|
await gate;
|
|
concurrent -= 1;
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
json: async () => ({
|
|
results: points.map(({ lon, lat }) => ({ lon, lat, elevation: 0, geoid: 0, ellipsoid: lon + lat })),
|
|
}),
|
|
};
|
|
}, async () => {
|
|
const first = warmFireAnchorFloors([{ lat: 40.001, lon: 50.001 }]);
|
|
// Second call arrives while the first is in flight: overlaps the first
|
|
// cell and adds one new one.
|
|
const second = warmFireAnchorFloors([
|
|
{ lat: 40.001, lon: 50.001 },
|
|
{ lat: 41.201, lon: 51.201 },
|
|
]);
|
|
release();
|
|
const [warmedFirst, warmedSecond] = await Promise.all([first, second]);
|
|
assert.equal(warmedFirst, true);
|
|
assert.equal(warmedSecond, true, 'the new cell warmed in the follow-up batch');
|
|
assert.equal(maxConcurrent, 1, 'batches never overlap on the wire');
|
|
assert.equal(log.length, 2);
|
|
assert.equal(log[1].length, 1, 'follow-up batch re-filters: only the still-cold cell goes out');
|
|
});
|
|
});
|
|
|
|
test('warmFireAnchorFloors: proxy failure reports false (re-render chain terminates)', async () => {
|
|
_resetFireAnchorsForTest();
|
|
let calls = 0;
|
|
await withFakeFetch(async () => {
|
|
calls += 1;
|
|
throw new Error('proxy down');
|
|
}, async () => {
|
|
const warmed = await warmFireAnchorFloors([{ lat: 22.501, lon: 32.501 }]);
|
|
assert.equal(warmed, false, 'geoid fallback is NOT a warm floor for anchoring');
|
|
assert.ok(calls >= 1);
|
|
});
|
|
assert.equal(fireAnchorHeight(22.501, 32.501), 0, 'anchor stays at 0 until a real floor lands');
|
|
});
|