Introduce stable server IDs for subscription state
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
createStateSnapshot,
|
||||
normalizeStoredState,
|
||||
} from '../../src/shared/contracts/state.js';
|
||||
import { createServerId } from '../../src/shared/serverIdentity.js';
|
||||
import { HARBOR_VERSIONS } from '../../src/shared/versions.js';
|
||||
|
||||
const root = path.resolve(import.meta.dirname, '../..');
|
||||
@@ -59,10 +60,12 @@ async function waitForState(port, child, stderr) {
|
||||
}
|
||||
|
||||
test('state v1 normalizes legacy storage and validates the canonical snapshot', () => {
|
||||
const legacyServer = { tag: ' legacy ', type: 'vless', server: 'vpn.example', server_port: 443 };
|
||||
const legacyServerId = createServerId(legacyServer);
|
||||
const stored = normalizeStoredState({
|
||||
subscriptionUrl: 'https://provider.example/subscription/test',
|
||||
selectedTag: ' legacy ',
|
||||
servers: [{ tag: ' legacy ', type: 'vless', server: 'vpn.example', server_port: 443 }],
|
||||
servers: [legacyServer],
|
||||
});
|
||||
const snapshot = createStateSnapshot({
|
||||
storedState: stored,
|
||||
@@ -76,8 +79,8 @@ test('state v1 normalizes legacy storage and validates the canonical snapshot',
|
||||
|
||||
assert.equal(snapshot.apiVersion, 1);
|
||||
assert.deepEqual(snapshot.selection, {
|
||||
desiredServerId: 'legacy',
|
||||
appliedServerId: 'legacy',
|
||||
desiredServerId: legacyServerId,
|
||||
appliedServerId: legacyServerId,
|
||||
});
|
||||
assert.equal(snapshot.connection.process, 'running');
|
||||
assert.equal(JSON.stringify(snapshot).includes(stored.subscriptionUrl), false);
|
||||
@@ -100,6 +103,7 @@ test('GET and domain mutations return one state shape with monotonic revisions',
|
||||
tls: { enabled: true },
|
||||
}],
|
||||
};
|
||||
const testServerId = createServerId(config.outbounds[0]);
|
||||
fs.mkdirSync(binDir);
|
||||
const singboxPath = path.join(binDir, 'sing-box');
|
||||
const workingSingbox = `#!/usr/bin/env node
|
||||
@@ -190,7 +194,7 @@ setInterval(() => {}, 60_000);
|
||||
runtime: { singBox: '1.12.13' },
|
||||
});
|
||||
assertStateSnapshot(initial);
|
||||
assert.equal(initial.selection.appliedServerId, 'test-vpn');
|
||||
assert.equal(initial.selection.appliedServerId, testServerId);
|
||||
assert.deepEqual(initial.route.localRules, [
|
||||
{ type: 'domain_suffix', value: 'ru', enabled: true },
|
||||
]);
|
||||
@@ -266,7 +270,7 @@ setInterval(() => {}, 60_000);
|
||||
);
|
||||
assert.equal(missingServer.response.status, 404);
|
||||
assert.equal(missingServer.payload.error.code, 'SERVER_NOT_FOUND');
|
||||
assert.equal((await request(port, '/api/state')).selection.desiredServerId, 'test-vpn');
|
||||
assert.equal((await request(port, '/api/state')).selection.desiredServerId, testServerId);
|
||||
|
||||
async function stateResponse(pathname, method = 'POST', body) {
|
||||
const result = await request(port, pathname, method, body);
|
||||
@@ -285,10 +289,14 @@ setInterval(() => {}, 60_000);
|
||||
const fetchesBeforeImport = providerFetchCount;
|
||||
await mutation('/api/subscription/fetch', 'POST', { url: subscriptionUrl });
|
||||
assert.equal(providerFetchCount, fetchesBeforeImport + 1);
|
||||
const applied = await mutation('/api/apply', 'POST', { selectedTag: 'test-vpn' });
|
||||
assert.equal(
|
||||
JSON.parse(fs.readFileSync(path.join(dir, 'subscription-cache.json'))).config.outbounds[0].tag,
|
||||
'test-vpn',
|
||||
);
|
||||
const applied = await mutation('/api/apply', 'POST', { serverId: testServerId });
|
||||
assert.deepEqual(applied.state.selection, {
|
||||
desiredServerId: 'test-vpn',
|
||||
appliedServerId: 'test-vpn',
|
||||
desiredServerId: testServerId,
|
||||
appliedServerId: testServerId,
|
||||
});
|
||||
assert.equal(applied.state.connection.process, 'running');
|
||||
const cacheBeforeFailedRefresh = fs.readFileSync(path.join(dir, 'subscription-cache.json'), 'utf8');
|
||||
@@ -323,7 +331,7 @@ setInterval(() => {}, 60_000);
|
||||
assert.deepEqual(JSON.parse(fs.readFileSync(path.join(dir, 'sing-box-config.json'))).route.rules.slice(0, 3), [
|
||||
{ domain: ['example.com'], outbound: 'direct' },
|
||||
{ domain_suffix: ['example.org'], outbound: 'direct' },
|
||||
{ inbound: ['mixed-in'], outbound: 'test-vpn' },
|
||||
{ inbound: ['mixed-in'], outbound: testServerId },
|
||||
]);
|
||||
|
||||
await mutation('/api/singbox/stop');
|
||||
|
||||
Reference in New Issue
Block a user