// OVERPASS PROXY — which upstream answers count as an answer. // // One predicate governs cache reads, writes, and stale fallback. A mirror's // refusal must neither end the search for healthy alternatives nor persist as // data under the week/month-long cache TTLs. These cases use no live providers. // // Run with: npm test import { test } from 'node:test'; import assert from 'node:assert/strict'; import { mkdir, readFile, writeFile, unlink } from 'node:fs/promises'; import { createHash, randomUUID } from 'node:crypto'; import path from 'node:path'; import { Readable } from 'node:stream'; import createViteConfig, { fetchOsmMapRoadPayload, fetchOverpassPayload, overpassPayloadIsData, parseOsmMapRoads, readOverpassDisk, } from '../vite.config.js'; const ENDPOINTS = ['https://a.example/api', 'https://b.example/api', 'https://c.example/api']; /** Answer each endpoint from a map of url → {status, body}; record the order. */ function mirrors(byUrl) { const tried = []; const fetchImpl = async (url) => { tried.push(url); const answer = byUrl[url]; if (answer instanceof Error) throw answer; return { status: answer.status, headers: { get: () => answer.contentType || 'application/json' } }; }; return { fetchImpl, tried, readBody: async (_, __) => byUrl[tried[tried.length - 1]]?.body ?? '' }; } const run = (byUrl) => { const m = mirrors(byUrl); return fetchOverpassPayload('data=x', 1e6, { endpoints: ENDPOINTS, fetchImpl: m.fetchImpl, readBody: m.readBody, simplify: (body) => body, }).then((payload) => ({ payload, tried: m.tried }), (error) => ({ error, tried: m.tried })); }; const DATA = { status: 200, body: '{"elements":[]}' }; const OSM_ROAD_XML = ` `; test('OSM map XML converts referenced nodes into traffic road geometry', () => { const payload = parseOsmMapRoads(OSM_ROAD_XML, new Set(['primary'])); assert.equal(payload.elements.length, 1); assert.equal(payload.elements[0].id, '101'); assert.equal(payload.elements[0].tags.highway, 'primary'); assert.equal(payload.elements[0].tags.oneway, 'yes'); assert.deepEqual(payload.elements[0].geometry, [ { lat: -3.76, lon: -38.49 }, { lat: -3.759, lon: -38.489 }, { lat: -3.758, lon: -38.488 }, ]); }); test('OSM map road fallback requests the traffic bbox and returns Overpass-shaped JSON', async () => { let requestedUrl = null; const query = '[out:json][timeout:12];(way["highway"~"^(motorway|trunk|primary|secondary)$"](-3.7609,-38.4967,-3.7540,-38.4827););out geom qt;'; const payload = await fetchOsmMapRoadPayload(`data=${encodeURIComponent(query)}`, 1e6, { fetchImpl: async (url) => { requestedUrl = String(url); return new Response(OSM_ROAD_XML, { status: 200, headers: { 'content-type': 'application/xml' } }); }, }); assert.equal(payload.status, 200); assert.equal(payload.endpoint, 'https://api.openstreetmap.org/api/0.6/map'); assert.match(requestedUrl, /bbox=-38\.4967%2C-3\.7609%2C-38\.4827%2C-3\.754/); assert.equal(JSON.parse(payload.body).elements.length, 1); }); test('disk cache rejects old refusals for fresh and stale reads but preserves last-good data', async () => { const key = `overpass-cache-regression-${randomUUID()}`; const directory = path.join(process.cwd(), '.gev-cache', 'overpass'); const file = path.join(directory, `${createHash('sha1').update(key).digest('hex')}.json`); await mkdir(directory, { recursive: true }); try { for (const refusal of [ { status: 406 }, { status: 429 }, { status: 503 }, { status: 200, rateLimited: true }, { status: 200, runtimeError: true }, ]) { await writeFile(file, JSON.stringify({ ...DATA, cachedAt: Date.now(), ...refusal })); assert.equal(await readOverpassDisk(key, 60000), null, `fresh ${JSON.stringify(refusal)}`); assert.equal(await readOverpassDisk(key, Infinity), null, `stale ${JSON.stringify(refusal)}`); } const good = { ...DATA, cachedAt: Date.now() - 120000 }; await writeFile(file, JSON.stringify(good)); assert.equal(await readOverpassDisk(key, 60000), null, 'expired good data misses normal TTL'); assert.deepEqual(await readOverpassDisk(key, Infinity), good, 'last-good data survives an outage'); await writeFile(file, '{invalid'); assert.equal(await readOverpassDisk(key, Infinity), null, 'corrupt cache is ignored'); } finally { await unlink(file); } }); // ── The predicate ──────────────────────────────────────────────────────────── test('only a 2xx that is neither rate-limited nor a runtime error is data', () => { assert.equal(overpassPayloadIsData({ status: 200 }), true); assert.equal(overpassPayloadIsData({ status: 204 }), true); // The measured refusal, and its neighbours. `< 500` admitted every one. for (const status of [400, 403, 406, 410, 429]) { assert.equal(overpassPayloadIsData({ status }), false, `${status} is not data`); } assert.equal(overpassPayloadIsData({ status: 502 }), false); // A 200 can still not be data: Overpass reports runtime failures in the body. assert.equal(overpassPayloadIsData({ status: 200, runtimeError: true }), false); assert.equal(overpassPayloadIsData({ status: 200, rateLimited: true }), false); assert.equal(overpassPayloadIsData({}), false); assert.equal(overpassPayloadIsData(null), false); }); // ── The fan-out ────────────────────────────────────────────────────────────── test('a refusal moves to the next mirror instead of ending the fan-out', async () => { // The exact shape measured against the live mirrors. const { payload, tried } = await run({ [ENDPOINTS[0]]: { status: 406, contentType: 'text/html', body: '406' }, [ENDPOINTS[1]]: DATA, [ENDPOINTS[2]]: DATA, }); assert.equal(payload.status, 200); assert.equal(payload.endpoint, ENDPOINTS[1]); assert.deepEqual(tried, ENDPOINTS.slice(0, 2), 'the healthy mirror must be reached, and no further'); }); test('the first mirror to answer wins, and the rest are left alone', async () => { const { payload, tried } = await run({ [ENDPOINTS[0]]: DATA, [ENDPOINTS[1]]: DATA, [ENDPOINTS[2]]: DATA, }); assert.equal(payload.endpoint, ENDPOINTS[0]); assert.deepEqual(tried, [ENDPOINTS[0]]); }); test('a refusal every mirror agrees on is reported, not swallowed', async () => { // A genuinely bad query must still say what upstream said — but only after // every mirror has had its chance to answer it. const refusal = { status: 400, body: 'line 1: parse error' }; const { payload, tried } = await run({ [ENDPOINTS[0]]: refusal, [ENDPOINTS[1]]: refusal, [ENDPOINTS[2]]: refusal, }); assert.equal(payload.status, 400); assert.equal(payload.endpoint, ENDPOINTS[0], 'the FIRST refusal is the one reported'); assert.deepEqual(tried, ENDPOINTS); assert.equal(overpassPayloadIsData(payload), false, 'so it is neither cached nor served as data'); }); test('a mirror that throws is no different from one that refuses', async () => { const { payload, tried } = await run({ [ENDPOINTS[0]]: new Error('ECONNRESET'), [ENDPOINTS[1]]: { status: 503, body: 'busy' }, [ENDPOINTS[2]]: DATA, }); assert.equal(payload.endpoint, ENDPOINTS[2]); assert.deepEqual(tried, ENDPOINTS); }); test('when every mirror is unreachable the caller gets a throw, not a payload', async () => { const { error, payload } = await run({ [ENDPOINTS[0]]: new Error('ECONNRESET'), [ENDPOINTS[1]]: new Error('ETIMEDOUT'), [ENDPOINTS[2]]: new Error('ENOTFOUND'), }); assert.equal(payload, undefined); assert.match(error.message, /ENOTFOUND/); }); test('production reader rotates past oversized, runtime-error and rate-limited bodies', async () => { for (const [status, body] of [ [200, 'x'.repeat(200)], [200, '{"remark":"runtime error: timed out","elements":[]}'], [200, 'rate_limited'], [429, 'busy'], [403, 'forbidden'], ]) { const tried = []; const payload = await fetchOverpassPayload('data=x', 100, { endpoints: ENDPOINTS, fetchImpl: async (url) => { tried.push(url); return new Response(tried.length === 1 ? body : DATA.body, { status: tried.length === 1 ? status : 200, headers: { 'content-type': 'application/json' }, }); }, }); assert.equal(payload.body, DATA.body); assert.deepEqual(tried, ENDPOINTS.slice(0, 2)); } }); function proxyHandler() { const plugin = createViteConfig({ mode: 'test' }).plugins.find(p => p.name === 'overpass-proxy'); const routes = new Map(); plugin.configureServer({ middlewares: { use: (route, handler) => routes.set(route, handler) } }); return routes.get('/api/overpass'); } function invoke(handler, body) { const req = Readable.from([Buffer.from(body)]); Object.assign(req, { method: 'POST', headers: {}, socket: { remoteAddress: '127.0.0.1' } }); return new Promise((resolve, reject) => { const res = { writeHead(status, headers) { this.status = status; this.headers = headers; }, end(body) { resolve({ status: this.status, headers: this.headers, body }); }, }; Promise.resolve(handler(req, res)).catch(reject); }); } test('coalesced outage callers both receive last-good data, never a cached refusal', async (t) => { const handler = proxyHandler(); for (const status of [406, 503, 429]) { const query = `[out:json][timeout:12];node(around:10,30.27,-97.74)["name"="${randomUUID()}"];out;`; const body = `data=${encodeURIComponent(query)}`; const directory = path.join(process.cwd(), '.gev-cache', 'overpass'); const file = path.join(directory, `${createHash('sha1').update(body).digest('hex')}.json`); await mkdir(directory, { recursive: true }); const stale = { ...DATA, cachedAt: Date.now() - 40 * 86400000 }; await writeFile(file, JSON.stringify(stale)); const entered = Promise.withResolvers(); const release = Promise.withResolvers(); let fetches = 0; const mock = t.mock.method(globalThis, 'fetch', async () => { fetches++; entered.resolve(); await release.promise; return new Response('upstream unavailable', { status }); }); try { const first = invoke(handler, body); await entered.promise; const second = invoke(handler, body); // The second request consumes its in-memory stream and joins the pending // promise before releasing upstream. No network or elapsed-time sleep. await new Promise(resolve => setImmediate(resolve)); release.resolve(); for (const response of await Promise.all([first, second])) { assert.equal(response.status, 200, `${status}: both callers use last-good data`); assert.equal(response.body, DATA.body); assert.equal(response.headers['X-Overpass-Cache'], 'STALE'); } assert.equal(fetches, 4, 'one shared, bounded mirror sequence'); assert.deepEqual(JSON.parse(await readFile(file, 'utf8')), stale); } finally { release.resolve(); mock.mock.restore(); await unlink(file); } } });