Handle rejected subscriptions and add local client compose
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
readHostNetworkState,
|
||||
verifyGatewayPresence,
|
||||
} from '../../src/server/gatewayPresence.js';
|
||||
import { createStateSnapshot } from '../../src/shared/contracts/state.js';
|
||||
|
||||
const subscriptionUrl = 'https://subscription.example/0123456789abcdef0123456789abcdef';
|
||||
const nonce = '0123456789abcdef0123456789abcdef';
|
||||
@@ -34,16 +35,19 @@ test('Gateway presence is authenticated by the shared subscription secret', asyn
|
||||
const result = await probeGatewayPresence({
|
||||
gateway: '192.168.50.111',
|
||||
subscriptionUrl,
|
||||
port: 4567,
|
||||
nonce,
|
||||
fetchImpl: async (url) => {
|
||||
assert.equal(
|
||||
url,
|
||||
`http://192.168.50.111:3456/api/gateway-presence?nonce=${nonce}`,
|
||||
`http://192.168.50.111:4567/api/gateway-presence?nonce=${nonce}`,
|
||||
);
|
||||
return { ok: true, json: async () => payload };
|
||||
},
|
||||
});
|
||||
assert.deepEqual(result, { gatewayId: 'gateway-1' });
|
||||
assert.equal(result.gatewayId, 'gateway-1');
|
||||
assert.equal(result.uiOrigin, 'http://192.168.50.111:4567');
|
||||
assert.equal(Number.isFinite(Date.parse(result.verifiedAt)), true);
|
||||
|
||||
assert.equal(buildGatewayPresence({
|
||||
appMode: 'gateway',
|
||||
@@ -88,9 +92,15 @@ test('host route freshness and Gateway failures drive a safe automatic fallback'
|
||||
|
||||
let state = nextGatewayAutoState(createGatewayAutoState(), {
|
||||
network,
|
||||
verifiedGateway: { gatewayId: 'gateway-1' },
|
||||
verifiedGateway: {
|
||||
gatewayId: 'gateway-1',
|
||||
uiOrigin: 'http://192.168.50.111:4567',
|
||||
verifiedAt: new Date(now).toISOString(),
|
||||
},
|
||||
});
|
||||
assert.equal(state.mode, 'gateway-direct');
|
||||
assert.equal(state.uiOrigin, 'http://192.168.50.111:4567');
|
||||
assert.equal(state.lastVerifiedAt, new Date(now).toISOString());
|
||||
|
||||
state = nextGatewayAutoState(state, { network });
|
||||
state = nextGatewayAutoState(state, { network });
|
||||
@@ -116,6 +126,44 @@ test('host route freshness and Gateway failures drive a safe automatic fallback'
|
||||
assert.equal(readHostNetworkState(statePath, { now }), null);
|
||||
});
|
||||
|
||||
test('canonical route distinguishes fresh, stale, lost, disabled and local states', () => {
|
||||
const storedState = {
|
||||
revision: 1,
|
||||
subscriptionUrl,
|
||||
gatewayAutoEnabled: true,
|
||||
};
|
||||
const snapshot = (gatewayAuto, stored = storedState) => createStateSnapshot({
|
||||
storedState: stored,
|
||||
runtime: { running: true },
|
||||
gatewayAuto,
|
||||
appMode: 'client',
|
||||
configExists: true,
|
||||
subscriptionHost: 'subscription.example/…',
|
||||
now: new Date('2026-07-13T12:00:00.000Z'),
|
||||
}).route;
|
||||
const fresh = {
|
||||
...createGatewayAutoState(),
|
||||
mode: 'gateway-direct',
|
||||
gateway: { gateway: '192.168.50.111' },
|
||||
gatewayId: 'gateway-1',
|
||||
uiOrigin: 'http://192.168.50.111:4567',
|
||||
lastVerifiedAt: '2026-07-13T11:59:59.000Z',
|
||||
};
|
||||
|
||||
const found = snapshot(fresh);
|
||||
assert.equal(found.mode, 'gateway-direct');
|
||||
assert.equal(found.reason, 'gateway-found');
|
||||
assert.equal(found.gatewayAddress, '192.168.50.111');
|
||||
assert.equal(found.gatewayUiOrigin, 'http://192.168.50.111:4567');
|
||||
assert.equal(found.lastVerifiedAt, '2026-07-13T11:59:59.000Z');
|
||||
assert.equal(found.autoEnabled, true);
|
||||
assert.equal(found.fallbackPreference, 'local-vpn');
|
||||
assert.equal(snapshot({ ...fresh, failures: 1 }).reason, 'gateway-stale');
|
||||
assert.equal(snapshot({ ...fresh, mode: 'local-vpn', gatewayId: '', lastError: 'lost' }).reason, 'gateway-lost');
|
||||
assert.equal(snapshot(fresh, { ...storedState, gatewayAutoEnabled: false }).reason, 'disabled');
|
||||
assert.equal(snapshot(createGatewayAutoState()).reason, 'local');
|
||||
});
|
||||
|
||||
test('client can ignore and restore a verified Gateway without losing discovery', () => {
|
||||
const detected = {
|
||||
...createGatewayAutoState(),
|
||||
|
||||
Reference in New Issue
Block a user