mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-10 21:32:23 +00:00
merge: integrate ECMWF IFS PR #464 with bounded model switching
This commit is contained in:
commit
26354d5ae1
16 files changed
+444
-182
No files matched your search
@@ -0,0 +1,51 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createWindLayer, formatWindValidTime, windStats } from './index.js';
|
||||
|
||||
const snapshot = (model) => ({ model, grid: { nx: 2, ny: 2 }, cycle: { runIso: '2026-09-14T12:00:00Z', validIso: '2026-09-14T18:00:00Z' } });
|
||||
function harness(feed) {
|
||||
const calls = [];
|
||||
const rendering = Object.fromEntries(['attach','start','stop','clear','destroy','setField'].map(name => [name, (...args) => calls.push([name, ...args])]));
|
||||
const layer = createWindLayer({ feed, createRendering: () => rendering });
|
||||
layer.init({ container: {} }); layer.enable();
|
||||
return { layer, calls };
|
||||
}
|
||||
test('forecast valid time and source age stay distinct', () => {
|
||||
assert.equal(formatWindValidTime('invalid'), null);
|
||||
assert.equal(formatWindValidTime('2026-01-05T06:30:00Z'), '2026-01-05 06:30 UTC');
|
||||
assert.equal(windStats(snapshot('gfs')).lastUpdate, Date.parse('2026-09-14T12:00:00Z'));
|
||||
});
|
||||
test('switching models clears old data and ignores an abort-insensitive late source', async () => {
|
||||
const pending = [];
|
||||
const { layer, calls } = harness({ getSnapshot: args => new Promise(resolve => pending.push({ ...args, resolve })) });
|
||||
const first = layer.update();
|
||||
layer.setParams({ model: 'ifs' });
|
||||
await Promise.resolve();
|
||||
assert.equal(pending.length, 2);
|
||||
assert.equal(pending[0].signal.aborted, true);
|
||||
assert.equal(layer.getStats().count, 0);
|
||||
assert.equal(layer.getStats().model, 'IFS');
|
||||
pending[0].resolve(snapshot('gfs'));
|
||||
await first;
|
||||
assert.equal(calls.filter(([name]) => name === 'setField').length, 0);
|
||||
pending[1].resolve(snapshot('ifs'));
|
||||
await Promise.resolve(); await Promise.resolve();
|
||||
assert.equal(calls.find(([name]) => name === 'setField')[1].model, 'ifs');
|
||||
assert.match(layer.getRowControls().info, /IFS forecast.*Valid: 2026-09-14 18:00 UTC.*Issued: 2026-09-14 12:00 UTC/);
|
||||
layer.destroy();
|
||||
});
|
||||
test('external and owned cancellation both cancel source work; queued switches stop on disable', async () => {
|
||||
let signal;
|
||||
const { layer } = harness({ getSnapshot: args => { signal = args.signal; return new Promise(resolve => signal.addEventListener('abort', () => resolve(snapshot('gfs')), { once: true })); } });
|
||||
const external = new AbortController();
|
||||
const update = layer.update(null, { signal: external.signal });
|
||||
layer.disable();
|
||||
assert.equal(signal.aborted, true); assert.equal(external.signal.aborted, false);
|
||||
assert.equal(await update, false);
|
||||
layer.enable();
|
||||
const other = layer.update(null, { signal: external.signal });
|
||||
external.abort(); assert.equal(signal.aborted, true); await other;
|
||||
layer.setParams({ model: 'ifs' }); layer.disable();
|
||||
await Promise.resolve(); assert.equal(layer.getStats().loading, false);
|
||||
layer.destroy();
|
||||
});
|
||||
Reference in new issue
Block a user