import test from 'node:test'; import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; import { weatherProxy, parseWeatherCapabilities, weatherImageBbox, weatherTileBounds, } from '../../server/providers/weather.js'; const NOW = Date.UTC(2026, 8, 16, 2, 12); const TIME = '2026-09-16T02:08:00.000Z'; const NAMES = [ 'conus_base_reflectivity_mosaic', 'global_longwave_imagery_mosaic', 'goes_longwave_imagery', 'ldn_lightning_strike_density', ]; function leaf( name, times = [TIME], { west = -130, east = -60, south = 20, north = 55 } = {}, ) { return `${name}Unused feed title${west}${east}${south}${north}${times.join(',')}`; } function xml(times = [TIME]) { return `Parent${NAMES.map((name) => leaf(name, times)).join('')}`; } // Header fixture only: the provider checks PNG signature/IHDR dimensions, not decompression. function png(width = 256, height = 256, length = 33) { const bytes = Buffer.alloc(length); Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]).copy(bytes); bytes.writeUInt32BE(13, 8); bytes.write('IHDR', 12); bytes.writeUInt32BE(width, 16); bytes.writeUInt32BE(height, 20); return bytes; } const image = (bytes = png()) => new Response(bytes, { headers: { 'Content-Type': 'image/png' } }); const tile = ({ product = 'radar', time = TIME, z = 0, x = 0, y = 0 } = {}) => `/tile?product=${product}&time=${encodeURIComponent(time)}&z=${z}&x=${x}&y=${y}`; const wholeImage = (time = TIME, product = 'clouds') => `/image?product=${product}&time=${encodeURIComponent(time)}`; function install(options = {}, preview = false) { let handler; const plugin = weatherProxy({ now: () => NOW, ...options }); plugin[preview ? 'configurePreviewServer' : 'configureServer']({ middlewares: { use(path, callback) { assert.equal(path, '/api/weather'); handler = callback; }, }, }); const begin = (url, method = 'GET') => { const res = new EventEmitter(); res.headers = {}; res.writeHead = (status, headers) => { res.statusCode = status; res.headers = headers; }; res.end = (body) => { res.body = body; }; const done = handler({ url, method }, res).then(() => res); return { res, done }; }; return { begin, request: (url, method) => begin(url, method).done }; } function fakeFetch(calls = []) { return async (url, options) => { calls.push({ url: new URL(url), options }); return url.includes('GetCapabilities') ? new Response(xml()) : image(); }; } const body = (res) => JSON.parse(res.body); const nextTurn = () => new Promise((resolve) => setImmediate(resolve)); test('lightning density uses a fixed observed WMS product with attribution and ten-minute metadata TTL', async () => { let clock = NOW; const calls = []; const { request } = install({ now: () => clock, fetchImpl: fakeFetch(calls), }); const manifest = body(await request('/manifest?product=lightning')); assert.equal(manifest.product, 'lightning'); assert.match(manifest.title, /density/); assert.match(manifest.description, /not individual GLM flashes/); assert.match(manifest.coverage, /not global/); assert.match(manifest.attribution, /Vaisala/); assert.equal(manifest.observedAt, TIME); assert.equal( manifest.imageUrl, `/api/weather${wholeImage(TIME, 'lightning')}`, ); assert.deepEqual(manifest.imageSize, { width: 4096, height: 2048 }); assert.equal((await request(tile({ product: 'lightning' }))).statusCode, 200); const map = calls[1].url; assert.equal(map.origin, 'https://nowcoast.noaa.gov'); assert.equal(map.pathname, '/geoserver/observations/lightning_detection/ows'); assert.equal(map.searchParams.get('layers'), NAMES[3]); assert.equal(map.searchParams.get('styles'), 'lightning_density'); assert.equal(map.searchParams.get('time'), TIME); assert.equal(map.searchParams.get('width'), '256'); clock += 599_000; await request('/manifest?product=lightning'); assert.equal(calls.length, 2); clock += 2000; await request('/manifest?product=lightning'); assert.equal(calls.length, 3); }); test('capabilities select exact leaves and preserve irregular observation times', () => { const older = '2026-09-16T02:04:14.000Z'; const text = `${leaf(NAMES[1], ['2026-09-16T01:00:00.000Z'])}${leaf(NAMES[0], [TIME, older, older])}`; const result = parseWeatherCapabilities(text, 'radar', NOW); assert.deepEqual(result.times, [older, TIME]); assert.deepEqual(result.bounds, { west: -130, east: -60, south: 20, north: 55, }); assert.deepEqual(parseWeatherCapabilities(text, 'clouds', NOW).times, [ '2026-09-16T01:00:00.000Z', ]); }); test('metadata caps advertised frames without fabricating interval timestamps', () => { const times = Array.from({ length: 40 }, (_, index) => new Date(NOW - (40 - index) * 60_000).toISOString(), ); const parsed = parseWeatherCapabilities(xml(times), 'radar', NOW); assert.deepEqual(parsed.times, times.slice(-13)); assert.deepEqual(parsed.allowedTimes, times.slice(-26)); for (const text of [ xml(['2026-09-16T01:00:00Z/2026-09-16T02:00:00Z/PT5M']), xml(['2026-02-30T00:00:00Z']), xml(['2026-09-17T00:00:00Z']), xml(['2026-09-14T00:00:00Z']), xml().replace('default="' + TIME, 'default="2026-09-16T02:00:00.000Z'), ']>' + xml(), xml().replace('-130', '-999'), xml().replace(NAMES[0], 'some_other_product'), xml() + leaf(NAMES[0]), 'x'.repeat(512 * 1024 + 1), ]) assert.throws(() => parseWeatherCapabilities(text, 'radar', NOW)); }); test('geographic tile coordinates use a 2x1 root and reject wrapping/out-of-range input', () => { assert.deepEqual(weatherTileBounds(0, 0, 0), [-180, -90, 0, 90]); assert.deepEqual(weatherTileBounds(0, 1, 0), [0, -90, 180, 90]); assert.deepEqual(weatherTileBounds(1, 2, 1), [0, -90, 90, 0]); assert.deepEqual( weatherTileBounds(6, 127, 63), [177.1875, -90, 180, -87.1875], ); for (const coords of [ [7, 0, 0], [0, 2, 0], [0, 0, 1], [-1, 0, 0], [0, -1, 0], [1.5, 0, 0], ]) assert.throws(() => weatherTileBounds(...coords)); }); test('manifest provides honest coverage, actual frame times and a same-origin tile template', async () => { const calls = []; const { request } = install({ fetchImpl: fakeFetch(calls) }, true); for (const product of ['radar', 'clouds', 'clouds-regional']) { const value = body(await request(`/manifest?product=${product}`)); assert.equal(value.product, product); assert.equal(value.latest, TIME); assert.equal(value.time, TIME); assert.equal(value.observedAt, TIME); assert.equal(value.fetchedAt, NOW); assert.equal(value.unavailable, false); assert.equal(value.stale, false); assert.deepEqual(value.times, [TIME]); assert.equal(value.tileSize, 256); assert.equal(value.maxLevel, 6); assert.equal(value.tilingScheme, 'geographic'); assert.equal( value.tileTemplate, `/api/weather/tile?product=${product}&time=${encodeURIComponent(TIME)}&z={z}&x={x}&y={y}`, ); assert.match( value.description, product === 'radar' ? /not a rainfall forecast/ : /Not a cloud-only mask/, ); if (product === 'clouds') assert.match(value.description, /2–3 hour/); assert.equal(value.imageUrl, `/api/weather${wholeImage(TIME, product)}`); assert.deepEqual( value.imageSize, product === 'clouds' ? { width: 2048, height: 1024 } : { width: 4096, height: 2048 }, ); } for (const call of calls) { assert.equal(call.url.hostname, 'nowcoast.noaa.gov'); assert.equal(call.options.redirect, 'error'); } }); test('invalid enums, arbitrary destinations and malformed tile inputs never fetch upstream', async () => { let calls = 0; const { request } = install({ fetchImpl: async () => { calls++; throw new Error('should not fetch'); }, }); for (const url of [ '/manifest', '/manifest?product=constructor', '/manifest?product=radar&product=clouds', '/manifest?product=radar&url=https://127.0.0.1', tile() + '&host=169.254.169.254', tile() + '&bbox=0,0,1,1', tile() + '&layers=other', tile({ z: 7 }), tile({ x: 2 }), tile({ y: 1 }), tile({ z: '00' }), tile({ x: '-1' }), tile({ time: 'latest' }), tile({ time: '2026-09-16T02:08:00Z' }), ]) assert.equal((await request(url)).statusCode, 400, url); assert.equal( (await request('/manifest?product=radar', 'POST')).statusCode, 405, ); assert.equal((await request('/unknown?product=radar')).statusCode, 404); assert.equal(calls, 0); }); test('tile fixes upstream host/layer/style/size/projection/time and caches exact frame bytes', async () => { const calls = []; const { request } = install({ fetchImpl: fakeFetch(calls) }); const response = await request(tile({ z: 1, x: 2, y: 1 })); assert.equal(response.statusCode, 200); assert.equal(response.headers['Content-Type'], 'image/png'); const map = calls.find( (call) => call.url.searchParams.get('request') === 'GetMap', ); assert.equal(map.url.origin, 'https://nowcoast.noaa.gov'); assert.equal(map.url.pathname, '/geoserver/observations/weather_radar/ows'); assert.deepEqual(Object.fromEntries(map.url.searchParams), { service: 'WMS', version: '1.1.1', request: 'GetMap', layers: NAMES[0], styles: 'weather_radar_base_reflectivity', srs: 'EPSG:4326', bbox: '0,-90,90,0', width: '256', height: '256', format: 'image/png', transparent: 'true', time: TIME, }); assert.equal(map.options.redirect, 'error'); assert.deepEqual( (await request(tile({ z: 1, x: 2, y: 1 }))).body, response.body, ); assert.equal(calls.length, 2); const unknown = await request(tile({ time: '2026-09-16T02:07:00.000Z' })); assert.equal(unknown.statusCode, 400); assert.equal( calls.length, 2, 'unadvertised observation cannot trigger a GetMap', ); }); test('capabilities TTL and bounded last-good state keep observed time distinct from fetch time', async () => { let clock = NOW; let fail = false; let calls = 0; const { request } = install({ now: () => clock, fetchImpl: async () => { calls++; if (fail) throw new Error('secret upstream details'); return new Response(xml()); }, }); const first = body(await request('/manifest?product=radar')); clock += 119_000; assert.deepEqual(body(await request('/manifest?product=radar')), first); assert.equal(calls, 1); fail = true; clock += 2000; const stale = body(await request('/manifest?product=radar')); assert.equal(stale.stale, true); assert.equal(stale.unavailable, false); assert.equal(stale.observedAt, TIME); assert.equal(stale.fetchedAt, NOW); assert.doesNotMatch(JSON.stringify(stale), /secret/); await request('/manifest?product=radar'); assert.equal(calls, 2, 'failed metadata retries are throttled'); clock = NOW + 3600_001; const unavailable = body(await request('/manifest?product=radar')); assert.equal(unavailable.unavailable, true); assert.deepEqual(unavailable.times, []); assert.equal(unavailable.observedAt, null); }); test('stale metadata serves only already-cached exact tiles, never nearest-frame substitution', async () => { let clock = NOW; let fail = false; let mapCalls = 0; const { request } = install({ now: () => clock, fetchImpl: async (url) => { if (url.includes('GetCapabilities')) { if (fail) throw new Error('down'); return new Response(xml()); } mapCalls++; return image(); }, }); assert.equal((await request(tile())).statusCode, 200); clock += 120_001; fail = true; assert.equal((await request(tile())).statusCode, 200); assert.equal((await request(tile({ x: 1 }))).statusCode, 503); assert.equal(mapCalls, 1); }); test('new metadata revokes removed times before any WMS nearestValue request', async () => { let clock = NOW; let times = [TIME]; let maps = 0; const { request } = install({ now: () => clock, fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml(times)) : (maps++, image()), }); await request(tile()); clock += 120_001; times = ['2026-09-16T02:10:00.000Z']; assert.equal((await request(tile({ x: 1 }))).statusCode, 400); assert.equal(maps, 1); assert.equal(body(await request('/manifest?product=radar')).latest, times[0]); }); test('simultaneous metadata coalesces service acquisition without mixing product metadata', async () => { let release; let calls = 0; const gate = new Promise((resolve) => { release = resolve; }); const { request } = install({ fetchImpl: async () => { calls++; await gate; return new Response(xml()); }, }); const a = request('/manifest?product=clouds'); const b = request('/manifest?product=clouds-regional'); await nextTurn(); release(); const [one, two] = await Promise.all([a, b]); assert.equal(calls, 1); assert.equal(body(one).product, 'clouds'); assert.equal(body(two).product, 'clouds-regional'); assert.notEqual(body(one).title, body(two).title); }); test('shared tile survives one disconnected consumer but aborts when all leave', async () => { let release; let activeSignal; const { begin, request } = install({ fetchImpl: async (url, { signal }) => { if (url.includes('GetCapabilities')) return new Response(xml()); activeSignal = signal; await new Promise((resolve, reject) => { release = resolve; signal.addEventListener('abort', () => reject(new Error('aborted')), { once: true, }); }); return image(); }, }); await request('/manifest?product=radar'); const a = begin(tile()); const b = begin(tile()); await nextTurn(); a.res.emit('close'); assert.equal(activeSignal.aborted, false); release(); assert.equal((await b.done).statusCode, 200); assert.equal((await a.done).body, undefined); const c = begin(tile({ x: 1 })); await nextTurn(); c.res.emit('close'); await c.done; assert.equal(activeSignal.aborted, true); assert.equal(c.res.body, undefined); }); test('metadata deadline cancels stalled bodies and returns a sanitized unavailable manifest', async () => { let cancelled = false; const { request } = install({ timeoutMs: 15, fetchImpl: async () => new Response( new ReadableStream({ start(controller) { controller.enqueue(new TextEncoder().encode('')); }, cancel() { cancelled = true; }, }), ), }); const response = await request('/manifest?product=radar'); assert.equal(body(response).unavailable, true); assert.equal(cancelled, true); }); test('disconnecting the last metadata consumer permits an immediate new acquisition', async () => { let calls = 0; let firstSignal; const { begin, request } = install({ fetchImpl: async (_url, { signal }) => { calls++; if (calls > 1) return new Response(xml()); firstSignal = signal; return await new Promise((_resolve, reject) => signal.addEventListener('abort', () => reject(new Error('aborted')), { once: true, }), ); }, }); const first = begin('/manifest?product=radar'); await nextTurn(); first.res.emit('close'); await first.done; assert.equal(firstSignal.aborted, true); assert.equal(first.res.body, undefined); const second = body(await request('/manifest?product=radar')); assert.equal(second.unavailable, false); assert.equal( calls, 2, 'consumer cancellation must not start a failure cooldown', ); }); test('streamed metadata cap cancels oversized capabilities before parsing', async () => { let cancelled = false; const { request } = install({ fetchImpl: async () => new Response( new ReadableStream({ pull(controller) { controller.enqueue(new Uint8Array(300_000)); }, cancel() { cancelled = true; }, }), ), }); assert.equal( body(await request('/manifest?product=radar')).unavailable, true, ); assert.equal(cancelled, true); }); test('tile rejects invalid MIME/signature/dimensions, redirects/status errors and oversized bodies', async () => { const cases = [ () => new Response('', { headers: { 'Content-Type': 'text/xml' }, }), () => image(Buffer.alloc(33)), () => image(png(512, 256)), () => new Response(png(), { status: 302, headers: { Location: 'http://127.0.0.1/', 'Content-Type': 'image/png' }, }), () => new Response(png(), { status: 503, headers: { 'Content-Type': 'image/png' }, }), () => image(png(256, 256, 1024 * 1024 + 1)), () => new Response(png(), { headers: { 'Content-Type': 'image/png', 'Content-Length': String(1024 * 1024 + 1), }, }), ]; for (const invalid of cases) { const { request } = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : invalid(), }); const response = await request(tile()); assert.equal(response.statusCode, 503); assert.deepEqual(body(response), { error: 'weather_upstream_unavailable' }); } }); test('tile body deadline cancels a stream after valid headers and PNG prefix', async () => { let cancelled = false; const { request } = install({ timeoutMs: 15, fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : new Response( new ReadableStream({ start(controller) { controller.enqueue(png()); }, cancel() { cancelled = true; }, }), { headers: { 'Content-Type': 'image/png' } }, ), }); assert.equal((await request(tile())).statusCode, 503); assert.equal(cancelled, true); }); test('failed tile retries use a bounded cooldown without caching an error as an image', async () => { let clock = NOW; let maps = 0; const { request } = install({ now: () => clock, fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); maps++; return maps === 1 ? new Response('private upstream detail', { status: 503 }) : image(); }, }); assert.equal((await request(tile())).statusCode, 503); assert.equal((await request(tile())).statusCode, 503); assert.equal(maps, 1); clock += 30_001; assert.equal((await request(tile())).statusCode, 200); assert.equal(maps, 2); }); test('tile LRU enforces both 128 entries and a 16 MiB byte budget', async () => { for (const [length, entries] of [ [33, 129], [600_000, 29], ]) { let mapCalls = 0; const { request } = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : (mapCalls++, image(png(256, 256, length))), }); for (let i = 0; i < entries; i++) assert.equal( (await request(tile({ z: 6, x: i % 128, y: Math.floor(i / 128) }))) .statusCode, 200, ); assert.equal(mapCalls, entries); await request(tile({ z: 6, x: 0, y: 0 })); assert.equal(mapCalls, entries + 1, 'oldest exact frame tile was evicted'); } }); test('eight upstream slots and a 96-entry queue bound concurrent unique tile work', async () => { const waiting = []; let active = 0; let peak = 0; const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); active++; peak = Math.max(active, peak); await new Promise((resolve) => waiting.push(resolve)); active--; return image(); }, }); await request('/manifest?product=radar'); const requests = Array.from({ length: 104 }, (_, x) => request(tile({ z: 6, x })), ); await nextTurn(); assert.equal(active, 8); const overflow = await request(tile({ z: 6, x: 104 })); assert.equal(overflow.statusCode, 429); assert.equal(overflow.headers['Retry-After'], '2'); for (let batch = 0; batch < 13; batch++) { waiting.splice(0).forEach((resolve) => resolve()); await nextTurn(); } assert.ok( (await Promise.all(requests)).every((result) => result.statusCode === 200), ); assert.equal(peak, 8); }); test('global infrared image uses one fixed advertised extent and exact 2048x1024 shape', async () => { const calls = []; const bounds = { west: -179.99, south: -72.74, east: 179.95, north: 72.73 }; const { request } = install({ fetchImpl: async (url, options) => { calls.push({ url: new URL(url), options }); return url.includes('GetCapabilities') ? new Response( `${leaf(NAMES[1], [TIME], bounds)}`, ) : image(png(2048, 1024)); }, }); const manifest = body(await request('/manifest?product=clouds')); assert.deepEqual(manifest.bounds, bounds); const response = await request(manifest.imageUrl.replace('/api/weather', '')); assert.equal(response.statusCode, 200); assert.equal(response.headers['Content-Type'], 'image/png'); const map = calls[1]; assert.equal(map.url.origin, 'https://nowcoast.noaa.gov'); assert.equal(map.url.pathname, '/geoserver/observations/satellite/ows'); assert.deepEqual(Object.fromEntries(map.url.searchParams), { service: 'WMS', version: '1.1.1', request: 'GetMap', layers: NAMES[1], styles: 'reflectance', srs: 'EPSG:4326', bbox: '-179.99,-72.74,179.95,72.73', width: '2048', height: '1024', format: 'image/png', transparent: 'true', time: TIME, }); assert.equal(map.options.redirect, 'error'); assert.deepEqual((await request(wholeImage())).body, response.body); assert.equal( calls.length, 2, 'whole-image cache avoids another NOAA request', ); }); test('whole-image route rejects unknown products, sizes above each product limit, coordinates and arbitrary destinations', async () => { let calls = 0; const { request } = install({ fetchImpl: async () => { calls++; throw new Error('unexpected fetch'); }, }); for (const url of [ wholeImage(TIME, 'other'), wholeImage() + '&size=4096x2048', wholeImage(TIME, 'lightning') + '&size=8192x4096', wholeImage(TIME, 'radar') + '&size=8192x4096', wholeImage(TIME, 'radar') + '&size=2048x2048', wholeImage(TIME, 'radar') + '&size=512x256', wholeImage(TIME, 'radar') + '&size=2048X1024', wholeImage(TIME, 'radar') + '&size=02048x1024', wholeImage(TIME, 'radar') + '&size=2048', wholeImage(TIME, 'radar') + '&size=1024x512&size=2048x1024', wholeImage() + '&width=4096', wholeImage() + '&height=2048', wholeImage() + '&z=0', wholeImage() + '&bbox=-180,-90,180', wholeImage() + '&host=http://127.0.0.1', wholeImage() + '&layers=other', wholeImage() + '&time=' + encodeURIComponent(TIME), wholeImage('latest'), '/image?product=clouds', ]) assert.equal((await request(url)).statusCode, 400, url); assert.equal(calls, 0); }); test('whole-image observations must be advertised and unavailable manifests expose no image URL', async () => { let maps = 0; const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); maps++; return image(png(2048, 1024)); }, }); assert.equal( (await request(wholeImage('2026-09-16T02:07:00.000Z'))).statusCode, 400, ); assert.equal(maps, 0); const failed = install({ fetchImpl: async () => { throw new Error('unavailable'); }, }); const manifest = body(await failed.request('/manifest?product=clouds')); assert.equal(manifest.unavailable, true); assert.equal(manifest.imageUrl, null); }); test('whole-image PNG bounds reject wrong dimensions and cap declared or streamed bytes at 16 MiB', async () => { for (const bytes of [ png(256, 256), png(2048, 2048), png(2048, 1024, 16 * 1024 * 1024 + 1), ]) { const { request } = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : image(bytes), }); assert.equal((await request(wholeImage())).statusCode, 503); } let cancelled = false; const declared = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : new Response( new ReadableStream({ cancel() { cancelled = true; }, }), { headers: { 'Content-Type': 'image/png', 'Content-Length': String(16 * 1024 * 1024 + 1), }, }, ), }); assert.equal((await declared.request(wholeImage())).statusCode, 503); assert.equal(cancelled, true); const valid = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : image(png(4096, 2048, 6 * 1024 * 1024)), }); assert.equal( (await valid.request(wholeImage(TIME, 'clouds-regional'))).statusCode, 200, 'a whole regional frame may exceed the 4 MiB tile cap', ); }); test('every product serves one whole-extent image at its advertised bounds, sized up to its limit', async () => { const maps = []; const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); const params = new URL(url).searchParams; maps.push(params); return image( png(Number(params.get('width')), Number(params.get('height'))), ); }, }); for (const [product, name, width] of [ ['radar', NAMES[0], 4096], ['clouds-regional', NAMES[2], 4096], ['lightning', NAMES[3], 4096], ['clouds', NAMES[1], 2048], ]) { maps.length = 0; const response = await request(wholeImage(TIME, product)); assert.equal(response.statusCode, 200, product); assert.equal( response.headers['Cache-Control'], 'public, max-age=86400, immutable', ); assert.equal(response.body.readUInt32BE(16), width); assert.equal(response.body.readUInt32BE(20), width / 2); assert.equal(maps.length, 1, 'one upstream request, no composition'); assert.equal(maps[0].get('layers'), name); assert.equal(maps[0].get('bbox'), '-130,20,-60,55'); assert.equal(maps[0].get('width'), String(width)); assert.equal(maps[0].get('height'), String(width / 2)); const smaller = `${wholeImage(TIME, product)}&size=1024x512`; assert.equal((await request(smaller)).statusCode, 200); assert.equal(maps.length, 2, 'size is part of the cache identity'); assert.equal(maps[1].get('width'), '1024'); assert.deepEqual((await request(smaller)).body.readUInt32BE(16), 1024); assert.equal( (await request(`${wholeImage(TIME, product)}&size=${width}x${width / 2}`)) .statusCode, 200, ); assert.equal(maps.length, 2, 'the explicit default shares the cache entry'); } }); test('detail windows take a rounded 2:1 bbox inside the product bounds, cached by product, time, size and bbox', async () => { const maps = []; const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); const params = new URL(url).searchParams; maps.push(params); return image( png(Number(params.get('width')), Number(params.get('height'))), ); }, }); const detail = (product, bbox, extra = '') => `${wholeImage(TIME, product)}&bbox=${bbox}${extra}`; for (const [product, name] of [ ['radar', NAMES[0]], ['clouds-regional', NAMES[2]], ['lightning', NAMES[3]], ['clouds', NAMES[1]], ]) { maps.length = 0; const response = await request(detail(product, '-102,34,-96,37')); assert.equal(response.statusCode, 200, product); assert.equal( response.headers['Cache-Control'], 'public, max-age=86400, immutable', ); assert.equal(response.body.readUInt32BE(16), 4096, 'every product'); assert.equal(response.body.readUInt32BE(20), 2048); assert.equal(maps[0].get('layers'), name); assert.equal(maps[0].get('time'), TIME); assert.deepEqual( ['bbox', 'width', 'height'].map((key) => maps[0].get(key)), ['-102,34,-96,37', '4096', '2048'], ); assert.deepEqual( (await request(detail(product, '-102.1,34.05,-95.9,37.1'))).body, response.body, 'values round to 0.25° so nearby requests repeat', ); assert.equal( (await request(detail(product, '-102,34,-96,37', '&size=4096x2048'))) .statusCode, 200, ); assert.equal(maps.length, 1, 'rounded and explicit-default requests hit'); const smaller = detail(product, '-102,34,-96,37', '&size=2048x1024'); assert.equal((await request(smaller)).statusCode, 200); assert.equal(maps.length, 2, 'size is part of the cache identity'); assert.equal(maps[1].get('width'), '2048'); assert.equal( (await request(detail(product, '-97,34,-91,37'))).statusCode, 200, ); assert.equal(maps.length, 3, 'bbox is part of the cache identity'); assert.equal((await request(wholeImage(TIME, product))).statusCode, 200); assert.equal(maps.length, 4, 'the full extent keeps its own entry'); assert.equal(maps[3].get('bbox'), '-130,20,-60,55'); } maps.length = 0; assert.equal( (await request(detail('radar', '-120,25,-70,50.25'))).statusCode, 200, 'within 1 % of 2:1', ); assert.equal(maps[0].get('bbox'), '-120,25,-70,50.25'); for (const bbox of [ '-120,25,-70,50.5', '-134,30,-122,36', '-70,40,-58,46', '-100,17,-94,20', '-100,53,-94,56', ]) { const response = await request(detail('radar', bbox)); assert.equal(response.statusCode, 400, bbox); assert.equal(response.headers['Cache-Control'], 'no-store'); assert.deepEqual(body(response), { error: 'invalid_weather_bbox' }); } assert.equal(maps.length, 1, 'rejected windows never reach NOAA'); }); test('malformed detail windows fail before any upstream request', async () => { let calls = 0; const { request } = install({ fetchImpl: async () => { calls++; throw new Error('unexpected fetch'); }, }); for (const bbox of [ '', '-102,34,-96', '-102,34,-96,37,1', 'a,b,c,d', '-102,34,-96,3e1', '-102,34,-96,+37', '-102,%2034,-96,37', '-1020,34,-96,37', '-102.1234567,34,-96,37', '-96,34,-102,37', '-102,37,-96,34', '-102,34,-96,40', '-102,34,-90,37', '-190,34,-178,40', '-102,85,-94,91', '-100,34,-100,34', ]) { const response = await request(`${wholeImage(TIME, 'radar')}&bbox=${bbox}`); assert.equal(response.statusCode, 400, bbox); assert.deepEqual(body(response), { error: 'invalid_weather_bbox' }); } for (const url of [ `${wholeImage(TIME, 'radar')}&bbox=-102,34,-96,37&size=8192x4096`, `${wholeImage(TIME, 'radar')}&bbox=-102,34,-96,37&bbox=-102,34,-96,37`, `${tile()}&bbox=-102,34,-96,37`, '/manifest?product=radar&bbox=-102,34,-96,37', ]) assert.equal((await request(url)).statusCode, 400, url); assert.equal(calls, 0); assert.equal(weatherImageBbox(null), null); const rounded = weatherImageBbox('-0.1,-0.05,5.9,2.95'); assert.deepEqual(rounded, [0, 0, 6, 3]); assert.ok(Object.is(rounded[0], 0), 'no negative zero in cache keys'); }); test('global whole images and tiles share a byte budget without sharing cache identities', async () => { const times = Array.from({ length: 5 }, (_, index) => new Date(NOW - (5 - index) * 60_000).toISOString(), ); let maps = 0; const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml(times)); maps++; const width = Number(new URL(url).searchParams.get('width')); return image(width === 2048 ? png(2048, 1024, 4 * 1024 * 1024) : png()); }, }); for (const time of times.slice(0, 4)) assert.equal((await request(wholeImage(time))).statusCode, 200); assert.equal(maps, 4); assert.equal( (await request(tile({ product: 'clouds', time: times[3] }))).statusCode, 200, ); assert.equal( maps, 5, 'same product/time tile does not receive a whole image', ); assert.equal((await request(wholeImage(times[0]))).statusCode, 200); assert.equal( maps, 6, 'adding a tile evicts the oldest image from the shared 16 MiB budget', ); assert.equal((await request(wholeImage(times[0]))).statusCode, 200); assert.equal(maps, 6); }); test('whole-image cache identity includes metadata bounds and shares cancellation/deadlines', async () => { let clock = NOW; let bounds = { west: -180, south: -60, east: 180, north: 60 }; let maps = 0; const { request } = install({ now: () => clock, fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response( `${leaf(NAMES[1], [TIME], bounds)}`, ); maps++; return image(png(2048, 1024)); }, }); await request(wholeImage()); clock += 120_001; bounds = { ...bounds, south: -72 }; await request(wholeImage()); assert.equal( maps, 2, 'new extent must not reuse previously normalized imagery', ); let cancelled = false; const stalled = install({ timeoutMs: 15, fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : new Response( new ReadableStream({ start(controller) { controller.enqueue(png(2048, 1024)); }, cancel() { cancelled = true; }, }), { headers: { 'Content-Type': 'image/png' } }, ), }); assert.equal((await stalled.request(wholeImage())).statusCode, 503); assert.equal(cancelled, true); }); test('exact frame tiles and images are immutable for a day; manifests and errors are uncached', async () => { const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); const width = Number(new URL(url).searchParams.get('width')); return image(width === 2048 ? png(2048, 1024) : png()); }, }); for (const url of [tile(), wholeImage()]) { for (let repeat = 0; repeat < 2; repeat++) { const response = await request(url); assert.equal(response.statusCode, 200); assert.equal( response.headers['Cache-Control'], 'public, max-age=86400, immutable', ); } } for (const product of ['radar', 'clouds', 'clouds-regional', 'lightning']) { const response = await request(`/manifest?product=${product}`); assert.equal(response.statusCode, 200); assert.equal(response.headers['Cache-Control'], 'no-store'); } for (const url of [ tile({ time: 'latest' }), wholeImage('latest'), '/tile?product=radar&z=0&x=0&y=0', '/image?product=clouds', ]) { const response = await request(url); assert.equal(response.statusCode, 400); assert.equal(response.headers['Cache-Control'], 'no-store'); } const failed = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); throw new Error('offline'); }, }); for (const url of [tile(), wholeImage()]) { const response = await failed.request(url); assert.equal(response.statusCode, 503); assert.equal(response.headers['Cache-Control'], 'no-store'); } }); for (const product of ['radar', 'clouds-regional', 'lightning']) { test(`${product} sizes select WMS dimensions and distinct immutable cache entries`, async () => { const maps = []; const { request } = install({ fetchImpl: async (url) => { if (url.includes('GetCapabilities')) return new Response(xml()); const params = new URL(url).searchParams; maps.push(params); return image( png(Number(params.get('width')), Number(params.get('height'))), ); }, }); const base = tile({ product, z: 3, x: 4, y: 2 }); for (const size of [256, 512, 1024]) { const url = `${base}&size=${size}`; const first = await request(url); assert.equal(first.statusCode, 200); assert.equal( first.headers['Cache-Control'], 'public, max-age=86400, immutable', ); assert.equal(first.body.readUInt32BE(16), size); assert.equal(first.body.readUInt32BE(20), size); assert.deepEqual((await request(url)).body, first.body); } assert.equal((await request(base)).statusCode, 200); assert.deepEqual( maps.map((p) => [p.get('width'), p.get('height')]), [ ['256', '256'], ['512', '512'], ['1024', '1024'], ], ); assert.equal(new Set(maps.map((p) => p.get('bbox'))).size, 1); const manifest = body(await request(`/manifest?product=${product}`)); assert.equal(manifest.tileSize, 256); assert.equal(manifest.maxLevel, 6); }); } test('unsupported or duplicate sizes fail before upstream acquisition', async () => { let calls = 0; const { request } = install({ fetchImpl: async () => { calls++; throw new Error(); }, }); for (const size of [ '', '0', '257', '2048', '-256', '0256', '256.0', '1e3', '512&size=1024', ]) { const response = await request(`${tile()}&size=${size}`); assert.equal(response.statusCode, 400, size); assert.equal(response.headers['Cache-Control'], 'no-store'); } assert.equal(calls, 0); }); test('large tile validation checks requested dimensions and bounded compressed bytes', async () => { for (const bytes of [ png(256, 256), png(1024, 512), png(1024, 1024, 4 * 1024 * 1024 + 65_537), ]) { const { request } = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : image(bytes), }); assert.equal((await request(`${tile()}&size=1024`)).statusCode, 503); } const { request } = install({ fetchImpl: async (url) => url.includes('GetCapabilities') ? new Response(xml()) : image(png(1024, 1024, 2 * 1024 * 1024)), }); assert.equal((await request(`${tile()}&size=1024`)).statusCode, 200); });