Refactor VPN proxy client implementation
Build and Deploy Gateway / build-and-push (push) Failing after 2s
Build and Deploy Gateway / deploy (push) Has been skipped

This commit is contained in:
2026-08-09 00:41:52 +03:00
parent 32be4380a3
commit 34d8b681ad
190 changed files with 20064 additions and 9761 deletions
+115 -2
View File
@@ -1,8 +1,30 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
import { buildGatewayVersionInfo, buildVersionInfo } from '../../src/server/version.js';
import { HARBOR_VERSIONS, versionCompatibility } from '../../src/shared/versions.js';
import { buildGatewayVersionInfo, buildVersionInfo } from '../../dist/server/version.js';
import { createVersionRoute } from '../../dist/server/http/routes/versionRoute.js';
import { HARBOR_VERSIONS, versionCompatibility } from '../../dist/shared/versions.js';
function response() {
return {
writeHead(status, headers) {
this.status = status;
this.headers = headers;
},
end(payload) {
this.rawPayload = payload;
this.payload = JSON.parse(payload);
},
};
}
const controlVersionInfo = {
apiVersion: 1,
location: 'gateway',
components: { gatewayBackend: '0.21.17' },
runtime: { singBox: '1.12.13' },
};
test('component versions enforce one Harbor major and one Gateway major.minor', () => {
assert.deepEqual(versionCompatibility(HARBOR_VERSIONS), {
@@ -49,3 +71,94 @@ test('runtime version info reports the installed sing-box binary', () => {
runtime: { singBox: '1.12.13' },
});
});
test('version route returns prebuilt local info without a dataplane refresh', async () => {
const res = response();
const route = createVersionRoute({
versionInfo: controlVersionInfo,
refreshDataplaneRuntime: null,
});
assert.equal(await route.handle({ method: 'GET', url: '/api/version' }, res), true);
assert.equal(res.status, 200);
assert.equal(res.headers['content-type'], 'application/json; charset=utf-8');
assert.equal(res.rawPayload.endsWith('\n'), false);
assert.deepEqual(res.payload, controlVersionInfo);
});
test('version route refreshes split Gateway once and preserves remote runtime overlay', async () => {
let refreshes = 0;
const route = createVersionRoute({
versionInfo: controlVersionInfo,
refreshDataplaneRuntime: async () => {
refreshes += 1;
return {
gatewayBackendVersion: '0.21.16',
singBoxVersion: '1.12.14',
};
},
});
const res = response();
assert.equal(await route.handle({ method: 'GET', url: '/api/version' }, res), true);
assert.equal(refreshes, 1);
assert.deepEqual(res.payload, {
apiVersion: 1,
location: 'gateway',
components: { gatewayBackend: '0.21.17' },
runtime: { dataplaneVersion: '0.21.16', singBox: '1.12.14' },
});
});
test('version route keeps remote null fallbacks', async () => {
const route = createVersionRoute({
versionInfo: controlVersionInfo,
refreshDataplaneRuntime: async () => ({}),
});
const res = response();
await route.handle({ method: 'GET', url: '/api/version' }, res);
assert.deepEqual(res.payload.runtime, { dataplaneVersion: null, singBox: null });
});
test('version route exact guard avoids refresh and refresh errors propagate unchanged', async () => {
let refreshes = 0;
const refreshError = new Error('status failed');
const route = createVersionRoute({
versionInfo: controlVersionInfo,
refreshDataplaneRuntime: async () => {
refreshes += 1;
throw refreshError;
},
});
for (const [method, url] of [
['POST', '/api/version'],
['GET', '/api/version?source=client'],
['GET', '/api/version/'],
['GET', '/api/other'],
]) {
assert.equal(await route.handle({ method, url }, response()), false);
}
assert.equal(refreshes, 0);
const res = response();
await assert.rejects(
route.handle({ method: 'GET', url: '/api/version' }, res),
(error) => error === refreshError,
);
assert.equal(refreshes, 1);
assert.equal(res.status, undefined);
});
test('version route is the sole HTTP owner', () => {
const index = readFileSync(new URL('../../src/server/index.ts', import.meta.url), 'utf8');
const route = readFileSync(
new URL('../../src/server/http/routes/versionRoute.ts', import.meta.url),
'utf8',
);
assert.match(index, /createVersionRoute\(\{/);
assert.match(index, /versionRoute\.handle\(req, res\)/);
assert.doesNotMatch(index, /['"]\/api\/version['"]|buildGatewayVersionInfo|sendJson/);
assert.match(route, /req\.url !== '\/api\/version'/);
assert.match(route, /buildGatewayVersionInfo\(/);
});