GenerAI / worldmonitor /tests /analysis-infrastructure-cascade.test.mjs
amogaddy's picture
Fix build: ripristinate blog-site/tests/e2e/pro-test/convex (referenziate dagli script di build) (part 3)
ec8acdf verified
Raw
History Blame Contribute Delete
9.42 kB
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import {
buildDependencyGraph,
calculateCascade,
getGraphStats,
getPipelineById,
getPortById,
} from '../shared/analysis-infrastructure-cascade.ts';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
// Two Atlantic cables sharing GB so the redundancy finder has an alternative.
const CABLES = [
{
id: 'atlantic-1',
name: 'Atlantic Express',
points: [
[-10, 50],
[-70, 40],
],
capacityTbps: 100,
countriesServed: [
{ country: 'GB', capacityShare: 0.6, isRedundant: false },
{ country: 'US', capacityShare: 0.3, isRedundant: true },
],
landingPoints: [{ country: 'GB', countryName: 'United Kingdom', lat: 50, lon: -10 }],
},
{
id: 'atlantic-2',
name: 'Atlantic Backup',
points: [[-9, 51]],
countriesServed: [{ country: 'GB', capacityShare: 0.2, isRedundant: true }],
},
];
const PIPELINES = [
{
id: 'transnorth',
name: 'TransNorth',
type: 'gas',
status: 'operating',
points: [
[5, 55],
[8, 52],
],
capacity: '40 bcm/year',
operator: 'Test Operator',
countries: ['NO', 'DE'],
},
];
// singapore sits ~295km from the malacca_strait fixture (inside the 500km radius);
// rotterdam is far outside it.
const PORTS = [
{ id: 'singapore', name: 'Port of Singapore', lat: 1.26, lon: 103.84, country: 'Singapore', type: 'mixed', rank: 2, note: '' },
{ id: 'rotterdam', name: 'Port of Rotterdam', lat: 51.9, lon: 4.5, country: 'Netherlands', type: 'container', rank: 10, note: '' },
];
const WATERWAYS = [
{ id: 'malacca_strait', chokepointId: 'malacca_strait', name: 'MALACCA STRAIT', lat: 2.5, lon: 101.5, description: 'Major oil shipping route' },
];
function buildFixtureGraph() {
return buildDependencyGraph({
cables: CABLES,
pipelines: PIPELINES,
ports: PORTS,
waterways: WATERWAYS,
});
}
function closeTo(actual, expected, message) {
assert.ok(
Math.abs(actual - expected) < 1e-9,
`${message}: expected ~${expected}, got ${actual}`,
);
}
describe('infrastructure cascade core β€” graph build', () => {
it('creates one node per asset plus every country reachable from the datasets', () => {
const stats = getGraphStats(buildFixtureGraph());
assert.equal(stats.cables, 2);
assert.equal(stats.pipelines, 1);
assert.equal(stats.ports, 2);
assert.equal(stats.chokepoints, 1);
// GB/US from cables, NO/DE from the pipeline, SG/NL from port locations,
// CN/JP/KR pulled in by the Singapore trade-route + Malacca dependencies.
assert.equal(stats.countries, 9);
assert.equal(stats.nodes, 15);
// 4 cable→country, 2 pipeline→country, 5 port→country, 4 chokepoint edges.
assert.equal(stats.edges, 15);
});
it('weights port→country edges by port type and rank, and indexes edges both ways', () => {
const graph = buildFixtureGraph();
const sgEdge = graph.outgoing.get('port:singapore')?.find(e => e.to === 'country:SG');
assert.ok(sgEdge, 'singapore should serve country:SG');
assert.equal(sgEdge.type, 'serves');
// mixed (0.6) + rank-2 boost ((20-2)/20 * 0.3 = 0.27)
closeTo(sgEdge.strength, 0.87, 'singapore importance');
closeTo(sgEdge.redundancy, 0.2, 'top-5 ports are harder to replace');
assert.ok(
graph.incoming.get('country:SG')?.some(e => e.from === 'port:singapore'),
'incoming index must mirror the outgoing edge',
);
});
it('links chokepoints only to ports inside the 500km radius', () => {
const graph = buildFixtureGraph();
const access = (graph.outgoing.get('chokepoint:malacca_strait') ?? []).filter(
e => e.type === 'controls_access',
);
assert.deepEqual(access.map(e => e.to), ['port:singapore']);
});
it('falls back to the bundled pipeline and port datasets when none are supplied', () => {
const stats = getGraphStats(buildDependencyGraph({ cables: [], waterways: [] }));
assert.ok(stats.pipelines >= 20, `expected the bundled PIPELINES, got ${stats.pipelines}`);
assert.ok(stats.ports >= 20, `expected the bundled PORTS, got ${stats.ports}`);
assert.equal(stats.cables, 0);
});
});
describe('infrastructure cascade core β€” cascade simulation', () => {
it('propagates a cable failure to the countries it serves', () => {
const result = calculateCascade(buildFixtureGraph(), 'cable:atlantic-1', 1.0);
assert.ok(result);
assert.equal(result.source.name, 'Atlantic Express');
const byCountry = new Map(result.countriesAffected.map(c => [c.country, c]));
assert.deepEqual(result.countriesAffected.map(c => c.country), ['GB', 'US']);
// 0.6 strength, no redundancy β†’ high
assert.equal(byCountry.get('GB').impactLevel, 'high');
closeTo(byCountry.get('GB').affectedCapacity, 0.6, 'GB capacity share');
// 0.3 strength halved by 0.5 redundancy β†’ 0.15 β†’ low
assert.equal(byCountry.get('US').impactLevel, 'low');
closeTo(byCountry.get('US').affectedCapacity, 0.3, 'US capacity share');
const gb = result.affectedNodes.find(n => n.node.id === 'country:GB');
assert.equal(gb.pathLength, 1);
assert.deepEqual(gb.dependencyChain, ['cable:atlantic-1', 'country:GB']);
assert.equal(gb.redundancyAvailable, false);
assert.equal(gb.estimatedRecovery, 'High - limited redundancy');
const us = result.affectedNodes.find(n => n.node.id === 'country:US');
assert.equal(us.redundancyAvailable, true);
});
it('scales impact with disruptionLevel and drops sub-threshold effects', () => {
const graph = buildFixtureGraph();
const half = calculateCascade(graph, 'cable:atlantic-1', 0.5);
const halfGb = half.countriesAffected.find(c => c.country === 'GB');
assert.equal(halfGb.impactLevel, 'medium', '0.6 * 0.5 = 0.30 β†’ medium');
const faint = calculateCascade(graph, 'cable:atlantic-1', 0.1);
assert.deepEqual(
faint.countriesAffected.map(c => c.country),
['GB'],
'US falls under the 0.05 impact floor at disruptionLevel 0.1',
);
assert.equal(faint.countriesAffected[0].impactLevel, 'low');
});
it('walks multi-hop chokepoint β†’ port β†’ country chains and multiplies path capacity', () => {
const result = calculateCascade(buildFixtureGraph(), 'chokepoint:malacca_strait', 1.0);
assert.deepEqual(
result.countriesAffected.map(c => c.country),
['SG', 'CN', 'JP', 'KR'],
'sorted by impact level, then by affected capacity',
);
const sg = result.affectedNodes.find(n => n.node.id === 'country:SG');
assert.equal(sg.pathLength, 2);
assert.deepEqual(sg.dependencyChain, [
'chokepoint:malacca_strait',
'port:singapore',
'country:SG',
]);
// (0.7 * 0.8) * (0.87 * 0.8)
const sgImpact = result.countriesAffected.find(c => c.country === 'SG');
closeTo(sgImpact.affectedCapacity, 0.56 * 0.696, 'chained path capacity');
// Direct chokepoint β†’ country edge: 0.7 * (1 - 0.3)
const cn = result.countriesAffected.find(c => c.country === 'CN');
closeTo(cn.affectedCapacity, 0.49, 'direct trade-dependency capacity');
assert.equal(cn.impactLevel, 'medium');
});
it('offers alternative cables that serve the same countries', () => {
const result = calculateCascade(buildFixtureGraph(), 'cable:atlantic-1', 1.0);
assert.deepEqual(result.redundancies, [
{ id: 'atlantic-2', name: 'Atlantic Backup', capacityShare: 0.2 },
]);
});
it('reports no redundancies for non-cable sources', () => {
const result = calculateCascade(buildFixtureGraph(), 'chokepoint:malacca_strait', 1.0);
assert.deepEqual(result.redundancies, []);
});
it('returns null for an unknown source id', () => {
const graph = buildFixtureGraph();
assert.equal(calculateCascade(graph, 'cable:does-not-exist', 1.0), null);
assert.equal(calculateCascade(graph, 'country:GB', 1.0)?.affectedNodes.length, 0);
});
});
describe('infrastructure cascade core β€” lookups', () => {
it('finds pipelines and ports in a supplied dataset', () => {
assert.equal(getPipelineById('transnorth', PIPELINES)?.name, 'TransNorth');
assert.equal(getPortById('rotterdam', PORTS)?.country, 'Netherlands');
assert.equal(getPipelineById('nope', PIPELINES), undefined);
assert.equal(getPortById('nope', PORTS), undefined);
});
it('defaults to the bundled datasets', () => {
assert.equal(getPipelineById('keystone')?.name, 'Keystone Pipeline');
assert.equal(getPortById('shanghai')?.country, 'China');
});
});
describe('infrastructure cascade core β€” server importability', () => {
const SERVER_IMPORTABLE = [
'shared/analysis-infrastructure-cascade.ts',
'shared/pipelines-data.ts',
'shared/ports-data.ts',
];
for (const relPath of SERVER_IMPORTABLE) {
it(`${relPath} has no client-only imports`, () => {
const src = readFileSync(resolve(repoRoot, relPath), 'utf-8');
assert.ok(
!/from\s*['"]@\//.test(src),
`${relPath} must not import through the @/ (src) alias β€” it has to bundle server-side`,
);
assert.ok(
!/from\s*['"][^'"]*\/src\//.test(src),
`${relPath} must not reach into src/`,
);
});
}
});