mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-09 04:44:01 +00:00
Merge branch 'pr-1578-new' into review/pr-1578
# Conflicts: # changelog.d/1578-space-missions-failed-entry.md # docs/CURRENT-STATE.md # src/layers/launches/controls.js
This commit is contained in:
commit
5dd7f41436
3 files changed
+46
-71
No files matched your search
@@ -1,8 +1,7 @@
|
||||
// The real manager, Context coordinator and launches ingestion run against a
|
||||
// local /api/launches, so a failed first load takes the browser's path.
|
||||
// stubbed /api/launches, so a failed first load takes the browser's path.
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import http from 'node:http';
|
||||
import * as Cesium from 'cesium';
|
||||
import { DataLayerManager } from '../../data/manager.js';
|
||||
import { ContextControls } from '../../ui/contextControls.js';
|
||||
@@ -93,24 +92,15 @@ function fakeCamera() {
|
||||
|
||||
async function fixture(t) {
|
||||
const upstream = { status: 429, results: [launchRecord] };
|
||||
const server = http.createServer(async (req, res) => {
|
||||
if (req.url === '/api/celestrak/active') {
|
||||
res.end('');
|
||||
return;
|
||||
}
|
||||
if (upstream.hold) await upstream.hold;
|
||||
if (upstream.status !== 200) {
|
||||
res.writeHead(upstream.status, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: 'Launch Library 2 unavailable' }));
|
||||
return;
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ results: upstream.results }));
|
||||
});
|
||||
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
||||
const origin = `http://127.0.0.1:${server.address().port}`;
|
||||
const source = createLaunchSource({
|
||||
fetchImpl: (url, options) => fetch(new URL(url, origin), options),
|
||||
async fetchImpl(url) {
|
||||
if (url === '/api/celestrak/active') return new Response('');
|
||||
if (upstream.hold) await upstream.hold;
|
||||
return Response.json(
|
||||
upstream.status === 200 ? { results: upstream.results } : {},
|
||||
{ status: upstream.status },
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const services = {
|
||||
@@ -201,14 +191,13 @@ async function fixture(t) {
|
||||
manager.register(missions);
|
||||
missions.attachDataManager(manager);
|
||||
|
||||
const toasts = [];
|
||||
const controls = new ContextControls({
|
||||
elements: {},
|
||||
installations: {},
|
||||
actions: {
|
||||
getCockpit: () => null,
|
||||
claimVisualAuthority: noop,
|
||||
showToast: (message) => toasts.push(message),
|
||||
showToast: noop,
|
||||
setClearBusy: noop,
|
||||
syncDetection: noop,
|
||||
scheduleLayout: noop,
|
||||
@@ -224,8 +213,6 @@ async function fixture(t) {
|
||||
for (const id of ['rocket-launches', 'satellites', 'earthquakes', 'wind'])
|
||||
await manager.setEnabled(id, false);
|
||||
await missions.destroy(viewer);
|
||||
server.closeAllConnections();
|
||||
await new Promise((resolve) => server.close(resolve));
|
||||
});
|
||||
|
||||
const enabledIds = () => [...manager.getEnabledLayerIds()].sort();
|
||||
@@ -250,56 +237,46 @@ async function fixture(t) {
|
||||
state,
|
||||
camera,
|
||||
rosters,
|
||||
toasts,
|
||||
enabledIds,
|
||||
view,
|
||||
settle,
|
||||
};
|
||||
}
|
||||
|
||||
test('a direct Space Missions entry that gets HTTP 429 rolls back instead of isolating', async (t) => {
|
||||
const f = await fixture(t);
|
||||
assert.equal(
|
||||
await f.manager.setEnabled('earthquakes', true, { origin: 'user' }),
|
||||
true,
|
||||
);
|
||||
const before = f.view();
|
||||
const entries = {
|
||||
direct: (f) =>
|
||||
f.manager.setEnabled('rocket-launches', true, { origin: 'user' }),
|
||||
'Context-panel': async (f) =>
|
||||
(
|
||||
await f.controls.setContextMode('space-missions', {
|
||||
claimVisualAuthority: false,
|
||||
})
|
||||
).ok,
|
||||
};
|
||||
|
||||
const entered = await f.manager.setEnabled('rocket-launches', true, {
|
||||
origin: 'user',
|
||||
for (const [path, enter] of Object.entries(entries))
|
||||
test(`a ${path} Space Missions entry that gets HTTP 429 rolls back instead of isolating`, async (t) => {
|
||||
const f = await fixture(t);
|
||||
await f.manager.setEnabled('earthquakes', true, { origin: 'user' });
|
||||
const before = f.view();
|
||||
|
||||
const entered = await enter(f);
|
||||
await f.settle();
|
||||
|
||||
assert.equal(entered, false, 'a failed mission index fails the enable');
|
||||
assert.deepEqual(f.enabledIds(), ['earthquakes']);
|
||||
assert.equal(f.controls.getContextModeState().mode, null);
|
||||
assert.equal(f.controls.getContextModeState().active, false);
|
||||
assert.equal(f.missions.getStats().error, 'HTTP 429');
|
||||
assert.deepEqual(f.view(), before, 'the pre-entry view comes back');
|
||||
assert.ok(f.camera.cancelled > 0, 'the full-globe flight is cancelled');
|
||||
|
||||
assert.equal(
|
||||
await f.manager.setEnabled('wind', true, { origin: 'user' }),
|
||||
true,
|
||||
'an unrelated layer is not blocked after the failed entry',
|
||||
);
|
||||
});
|
||||
await f.settle();
|
||||
|
||||
assert.equal(entered, false, 'a failed mission index fails the enable');
|
||||
assert.deepEqual(f.enabledIds(), ['earthquakes']);
|
||||
assert.equal(f.controls.getContextModeState().mode, null);
|
||||
assert.equal(f.controls.getContextModeState().active, false);
|
||||
assert.equal(f.missions.getStats().error, 'HTTP 429');
|
||||
assert.deepEqual(f.view(), before, 'the pre-entry view comes back');
|
||||
assert.ok(f.camera.cancelled > 0, 'the full-globe flight is cancelled');
|
||||
|
||||
assert.equal(
|
||||
await f.manager.setEnabled('wind', true, { origin: 'user' }),
|
||||
true,
|
||||
'an unrelated layer is not blocked after the failed entry',
|
||||
);
|
||||
});
|
||||
|
||||
test('a Context-panel Space Missions entry that gets HTTP 429 restores the previous layers', async (t) => {
|
||||
const f = await fixture(t);
|
||||
await f.manager.setEnabled('earthquakes', true, { origin: 'user' });
|
||||
const before = f.view();
|
||||
|
||||
const result = await f.controls.setContextMode('space-missions', {
|
||||
claimVisualAuthority: false,
|
||||
});
|
||||
await f.settle();
|
||||
|
||||
assert.equal(result.ok, false);
|
||||
assert.deepEqual(f.enabledIds(), ['earthquakes']);
|
||||
assert.equal(f.controls.getContextModeState().mode, null);
|
||||
assert.deepEqual(f.view(), before);
|
||||
});
|
||||
|
||||
// Holds the /api/launches reply until the returned release is called.
|
||||
function holdReply(f) {
|
||||
|
||||
@@ -236,7 +236,6 @@ export function createIngestion({
|
||||
parts.panel.renderMissionRoster();
|
||||
throw error;
|
||||
}
|
||||
layerState._entryCameraView = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,12 +241,12 @@ export function createLifecycle({
|
||||
// A new attempt at an index that never loaded starts from loading.
|
||||
layerState._lastError = null;
|
||||
parts.panel.renderMissionRoster();
|
||||
// Kept until the mission index loads, so an entry that never does
|
||||
// gives the view back. A newer flight takes the camera and drops it.
|
||||
layerState._entryCameraView = captureCameraView(layerState._viewer);
|
||||
layerState._entryLandedView = null;
|
||||
}
|
||||
// Kept until the mission index loads, so an entry that never does
|
||||
// gives the view back. A newer flight takes the camera and drops it.
|
||||
const token = layerState._lifecycleToken;
|
||||
layerState._entryCameraView = captureCameraView(layerState._viewer);
|
||||
layerState._entryLandedView = null;
|
||||
const flying = parts.selection.focusFullGlobe(layerState._viewer, {
|
||||
complete: () => {
|
||||
if (token === layerState._lifecycleToken)
|
||||
@@ -305,7 +305,6 @@ export function createLifecycle({
|
||||
layerState._sourceController.abort();
|
||||
releaseContinuousRender('rocket-launches'); // direct-destroy path (perf wave 2 fix)
|
||||
layerState._enabled = false;
|
||||
layerState._entryCameraView = null;
|
||||
layerState._lifecycleToken++;
|
||||
layerState._updateDirty = false;
|
||||
await parts.ingestion.restoreSatelliteDependency();
|
||||
|
||||
Reference in new issue
Block a user