mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 22:02:21 +00:00
fix(wind): scope grid ids and URLs to the model
The grid id and URL omitted the model, so two models sharing a cycle produced the same `/api/wind/grid/<id>.bin`. Because the grid route defaults to `gfs`, an IFS grid request resolved against the GFS cache: when both cycles matched it silently served the GFS field as IFS, and when they differed it 404'd and the client parsed the error body as float data. Include the model in both the id and the URL, and reject a resampled grid that contains non-finite values instead of caching it. Verified against live data: the IFS grid now decodes to 65,160 finite values (u -20.2..27.6 m/s) and renders a field distinct from GFS.
This commit is contained in:
1 parent
a2d38391e6
commit
8db53063a9
2 files changed
+162
-17
No files matched your search
@@ -53,6 +53,9 @@ const DECODED_U = {
|
||||
};
|
||||
const DECODED_V = { ...DECODED_U, values: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] };
|
||||
|
||||
/** Resampled-grid metadata shared by the injected model fakes. */
|
||||
const GRID = { nx: 4, ny: 3, lo1: 0, la1: 90, dx: 90, dy: 90 };
|
||||
|
||||
/** Fetch double: `.idx` text, and range bodies of the requested length. */
|
||||
function makeFetch({ fail = false, counter } = {}) {
|
||||
return async (url, options = {}) => {
|
||||
@@ -87,7 +90,7 @@ test('wind manifest describes the GFS cycle and resampled grid', async () => {
|
||||
assert.equal(body.cycle.date, '20260914');
|
||||
assert.equal(body.units, 'm/s');
|
||||
assert.deepEqual(body.grid, { nx: 4, ny: 3, lo1: 0, la1: 90, dx: 90, dy: 90 });
|
||||
assert.match(body.gridUrl, /^\/api\/wind\/grid\/20260914-6-90\.bin$/);
|
||||
assert.match(body.gridUrl, /^\/api\/wind\/grid\/gfs-20260914-6-90\.bin\?model=gfs$/);
|
||||
assert.equal(body.stale, false);
|
||||
});
|
||||
|
||||
@@ -168,3 +171,36 @@ test('wind returns a JSON 404 for an unknown grid', async () => {
|
||||
assert.equal(res.statusCode, 404);
|
||||
assert.deepEqual(JSON.parse(res.body), { error: 'unknown_grid' });
|
||||
});
|
||||
|
||||
test('wind grid ids and URLs are model-scoped', async () => {
|
||||
const request = install(
|
||||
proxy({
|
||||
models: {
|
||||
gfs: async () => ({ cycle: { date: '20260914', hour: 6 }, level: 'x', units: 'm/s', grid: { ...GRID, u: new Float32Array(12), v: new Float32Array(12) } }),
|
||||
ifs: async () => ({ cycle: { date: '20260914', hour: 0 }, level: 'x', units: 'm/s', grid: { ...GRID, u: new Float32Array(12), v: new Float32Array(12) } }),
|
||||
},
|
||||
}),
|
||||
);
|
||||
const gfs = JSON.parse((await request('/')).body);
|
||||
const ifs = JSON.parse((await request('/?model=ifs')).body);
|
||||
assert.match(gfs.gridUrl, /gfs-20260914-6-90\.bin\?model=gfs$/);
|
||||
assert.match(ifs.gridUrl, /ifs-20260914-0-90\.bin\?model=ifs$/);
|
||||
// Each model's grid resolves through its own model parameter.
|
||||
assert.equal((await request(gfs.gridUrl.replace('/api/wind', ''))).statusCode, 200);
|
||||
assert.equal((await request(ifs.gridUrl.replace('/api/wind', ''))).statusCode, 200);
|
||||
});
|
||||
|
||||
test('wind rejects a non-finite grid instead of caching it', async () => {
|
||||
const bad = new Float32Array(12);
|
||||
bad[3] = Number.POSITIVE_INFINITY;
|
||||
const request = install(
|
||||
proxy({
|
||||
models: {
|
||||
gfs: async () => ({ cycle: { date: '20260914', hour: 6 }, level: 'x', units: 'm/s', grid: { ...GRID, u: bad, v: new Float32Array(12) } }),
|
||||
},
|
||||
}),
|
||||
);
|
||||
const body = JSON.parse((await request('/')).body);
|
||||
assert.equal(body.unavailable, true);
|
||||
assert.match(body.reason, /non-finite/);
|
||||
});
|
||||
Reference in new issue
Block a user