Keep the strict scenarios in step with main's photos and satellite groups

Main's flight photos ask Planespotters for every tracked aircraft, which
the strict network policy counted as a violation; the harness now answers
those lookups with no photos, as the other QA scripts already do. Main
also reads five more TLE groups (resource, weather, planet, SAR and
science): the satellite fixture serves them, and the space switch expects
all twelve groups and derives its catalog sizes from the fixture.
This commit is contained in:
German Khokhlov committed 2026-11-10 15:01:39 +04:00
1 parent 9c2a2d6951
commit bd4f9eaee4
4 files changed
+51 -10

No files matched your search

+26 -10
View File
@@ -31,8 +31,20 @@ await strict.run({}, async (b) => {
'galileo', 'galileo',
'geo', 'geo',
'starlink', 'starlink',
'resource',
'weather',
'planet',
'sar',
'science',
].map((g) => [g, satelliteFixture(g)]), ].map((g) => [g, satelliteFixture(g)]),
); );
// The core catalog is every group but Starlink, which only the dense
// catalog adds; each fixture satellite is three lines.
const satellitesIn = (g) => groups[g].trim().split('\n').length / 3;
const coreCount = Object.keys(groups)
.filter((g) => g !== 'starlink')
.reduce((sum, g) => sum + satellitesIn(g), 0);
const denseCount = coreCount + satellitesIn('starlink');
await p.evaluateOnNewDocument( await p.evaluateOnNewDocument(
(groups, launches, epoch) => { (groups, launches, epoch) => {
const fetch = window.fetch.bind(window); const fetch = window.fetch.bind(window);
@@ -76,14 +88,18 @@ await strict.run({}, async (b) => {
} else await dataManager.setEnabled('satellites', true, { origin: 'user' }); } else await dataManager.setEnabled('satellites', true, { origin: 'user' });
}, missions); }, missions);
if (!missions) { if (!missions) {
await p.waitForFunction(() => window.sa.getStats().count === 839, { await p.waitForFunction(
timeout: 40000, (count) => window.sa.getStats().count === count,
}); { timeout: 40000 },
coreCount,
);
console.log('core catalog ready'); console.log('core catalog ready');
await p.evaluate(() => window.sa.setParams({ catalog: 'dense' })); await p.evaluate(() => window.sa.setParams({ catalog: 'dense' }));
await p.waitForFunction(() => window.sa.getStats().count === 6839, { await p.waitForFunction(
timeout: 60000, (count) => window.sa.getStats().count === count,
}); { timeout: 60000 },
denseCount,
);
console.log('dense catalog ready'); console.log('dense catalog ready');
assert.ok( assert.ok(
await p.evaluate(() => window.sa.trackById(25544, { origin: 'user' })), await p.evaluate(() => window.sa.trackById(25544, { origin: 'user' })),
@@ -119,7 +135,7 @@ await strict.run({}, async (b) => {
before.mission, before.mission,
before.replay?.active, before.replay?.active,
); );
// Each source read exactly once: the seven TLE groups of the dense // Each source read exactly once: the twelve TLE groups of the dense
// catalog; in Space Missions the launch list and every TLE group the // catalog; in Space Missions the launch list and every TLE group the
// mission view asks for. // mission view asks for.
const groupPaths = Object.keys(groups).map((g) => '/api/celestrak/' + g); const groupPaths = Object.keys(groups).map((g) => '/api/celestrak/' + g);
@@ -130,7 +146,7 @@ await strict.run({}, async (b) => {
layer, layer,
missions missions
? 'the launch list and each TLE group read exactly once' ? 'the launch list and each TLE group read exactly once'
: 'each of the seven TLE groups read exactly once', : 'each of the twelve TLE groups read exactly once',
Object.values(reads).every((n) => n === 1) && Object.values(reads).every((n) => n === 1) &&
(missions (missions
? reads['/api/launches'] === 1 ? reads['/api/launches'] === 1
@@ -181,7 +197,7 @@ await strict.run({}, async (b) => {
before.replay.phaseProgress, before.replay.phaseProgress,
); );
} else { } else {
assert.equal(state.sat.count, 6839); assert.equal(state.sat.count, denseCount);
assert.equal(state.params.selectedSatTrackingId, 25544); assert.equal(state.params.selectedSatTrackingId, 25544);
assert.ok(state.follow && state.ring > 0); assert.ok(state.follow && state.ring > 0);
assert.equal(state.sat.lastUpdate, before.stamp); assert.equal(state.sat.lastUpdate, before.stamp);
@@ -191,7 +207,7 @@ await strict.run({}, async (b) => {
layer, layer,
missions missions
? 'same models; Space Missions mode, the same mission paused at the same progress, speed 4' ? 'same models; Space Missions mode, the same mission paused at the same progress, speed 4'
: 'same models; 6 839 objects, the ISS tracked with its ring, same update stamp', : `same models; ${denseCount} objects, the ISS tracked with its ring, same update stamp`,
); );
await readsOnce(); await readsOnce();
} }
+15
View File
@@ -29,6 +29,20 @@ import {
import { createMissLoader, tileCacheFile } from './qa/tileCache.mjs'; import { createMissLoader, tileCacheFile } from './qa/tileCache.mjs';
import { closeBrowser, diagnoseExit, exitAfterFlush } from './qa/browser.mjs'; import { closeBrowser, diagnoseExit, exitAfterFlush } from './qa/browser.mjs';
import { DAYTIME, shiftTime } from './qa/time.mjs'; import { DAYTIME, shiftTime } from './qa/time.mjs';
import {
PLANESPOTTERS_EMPTY_BODY,
PLANESPOTTERS_ORIGIN,
} from './qa-photo-stub.mjs';
// Tracking a civil flight asks Planespotters for its photo; strict runs
// answer every lookup with no photos instead of leaving the machine.
const PHOTO_ROUTE = Object.freeze({
pattern: `${PLANESPOTTERS_ORIGIN}/*`,
respond: () => ({
contentType: 'application/json',
body: PLANESPOTTERS_EMPTY_BODY,
}),
});
export const ENGINES = Object.freeze(['cesium', 'navara']); export const ENGINES = Object.freeze(['cesium', 'navara']);
/** What the Globe Engine picker offers: the engines and Navara HD. */ /** What the Globe Engine picker offers: the engines and Navara HD. */
@@ -104,6 +118,7 @@ export async function installStrictNetwork(
}, },
) { ) {
const preview = new URL(origin); const preview = new URL(origin);
routes = [...routes, PHOTO_ROUTE];
fixtures = [...fixtures, ...routes.map((route) => route.pattern)]; fixtures = [...fixtures, ...routes.map((route) => route.pattern)];
const urlPatterns = strictBlockPatterns(origin, { fixtures, tileHosts }); const urlPatterns = strictBlockPatterns(origin, { fixtures, tileHosts });
const answers = routes.map((route) => ({ const answers = routes.map((route) => ({
+5
View File
@@ -28,6 +28,11 @@ const GROUPS = {
galileo: [42000, 30, 56, 1.7047, 'QA GALILEO'], galileo: [42000, 30, 56, 1.7047, 'QA GALILEO'],
geo: [45000, 32, 0.1, 1.0027, 'QA GEO'], geo: [45000, 32, 0.1, 1.0027, 'QA GEO'],
starlink: [50000, 6000, 53, 15.2, 'QA STARLINK'], starlink: [50000, 6000, 53, 15.2, 'QA STARLINK'],
resource: [60000, 12, 98.2, 14.6, 'QA RESOURCE'],
weather: [61000, 8, 98.7, 14.1, 'QA WEATHER'],
planet: [62000, 24, 97.5, 15.1, 'QA PLANET'],
sar: [63000, 6, 97.9, 15.0, 'QA SAR'],
science: [64000, 6, 28.5, 15.1, 'QA SCIENCE'],
}; };
export const SATELLITE_FIXTURE_EPOCH = W1_FROZEN_MS; export const SATELLITE_FIXTURE_EPOCH = W1_FROZEN_MS;
export function satelliteFixture(group) { export function satelliteFixture(group) {
+5
View File
@@ -16,6 +16,11 @@ test('satellite fixture has distinct, valid SGP4 catalogs including LEO, MEO and
galileo: 30, galileo: 30,
geo: 32, geo: 32,
starlink: 6000, starlink: 6000,
resource: 12,
weather: 8,
planet: 24,
sar: 6,
science: 6,
}; };
for (const [group, count] of Object.entries(counts)) { for (const [group, count] of Object.entries(counts)) {
const lines = satelliteFixture(group).trim().split('\n'); const lines = satelliteFixture(group).trim().split('\n');