Harden traffic history worker lifecycle and query performance
Build and Deploy Gateway / build-and-push (push) Successful in 37s
Build and Deploy Gateway / deploy (push) Successful in 19s

This commit is contained in:
2026-09-19 09:58:54 +03:00
parent 74c5b66482
commit 4c58384056
14 changed files with 509 additions and 89 deletions
+46 -3
View File
@@ -143,8 +143,12 @@ test('typed endpoint facade preserves exact request contracts and raw payload id
assert.equal(await invoke(), payload);
const [actualUrl, actualOptions] = calls.at(-1);
assert.equal(actualUrl, url);
assert.deepEqual(actualOptions, {
...options,
assert.ok(actualOptions.signal instanceof AbortSignal);
assert.equal(actualOptions.signal.aborted, false);
const { signal: requestedSignal, ...requestOptions } = options;
const { signal: actualSignal, ...fetchOptions } = actualOptions;
assert.deepEqual(fetchOptions, {
...requestOptions,
headers: { 'content-type': 'application/json' },
});
}
@@ -162,7 +166,9 @@ test('request preserves caller headers, AbortError identity and JSON fallbacks',
received = [url, options];
return { ok: true, status: 200, json: async () => value };
}), value);
assert.deepEqual(received, ['/api/test', {
assert.ok(received[1].signal instanceof AbortSignal);
const { signal, ...options } = received[1];
assert.deepEqual([received[0], options], ['/api/test', {
headers: { 'content-type': 'application/custom', 'x-harbor': 'yes' },
}]);
@@ -188,3 +194,40 @@ test('request preserves caller headers, AbortError identity and JSON fallbacks',
(error) => error.code === 'CONTROL_UNREACHABLE' && error.status === 503,
);
});
test('API deadlines cover headers and response bodies, while caller cancellation keeps its reason', async (t) => {
t.mock.timers.enable({ apis: ['setTimeout'] });
const stalled = (signal) => new Promise((resolve, reject) => {
signal.addEventListener('abort', () => reject(signal.reason), { once: true });
});
for (const phase of ['headers', 'body']) {
let signal;
const pending = request('/api/state', {}, async (url, options) => {
signal = options.signal;
return phase === 'headers' ? stalled(signal)
: { ok: true, status: 200, json: () => stalled(signal) };
});
const checked = assert.rejects(pending, (error) => error.code === 'CONTROL_UNREACHABLE' && error.retryable);
await Promise.resolve();
t.mock.timers.tick(14_999);
assert.equal(signal.aborted, false);
t.mock.timers.tick(1);
await checked;
}
const caller = new AbortController();
const reason = new DOMException('left the page', 'AbortError');
const pending = request('/api/test', { signal: caller.signal }, (url, options) => stalled(options.signal));
const checked = assert.rejects(pending, (error) => error === reason);
caller.abort(reason);
await checked;
let commandSignal;
const command = request('/api/diagnostics/dns', { method: 'POST' }, (url, options) => {
commandSignal = options.signal;
return stalled(commandSignal);
});
const commandChecked = assert.rejects(command, (error) => error.code === 'CONTROL_UNREACHABLE');
t.mock.timers.tick(59_999);
assert.equal(commandSignal.aborted, false);
t.mock.timers.tick(1);
await commandChecked;
});
+42
View File
@@ -1,6 +1,7 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
import { parse } from '@babel/parser';
const index = readFileSync(new URL('../../index.html', import.meta.url), 'utf8');
const main = readFileSync(new URL('../../src/web/main.tsx', import.meta.url), 'utf8');
@@ -23,3 +24,44 @@ test('App remains the exported composition component without bootstrap side effe
assert.match(app, /<ClientOverviewPage/);
assert.match(app, /<StaleBanner/);
});
test('state polling waits for completion and stops after cleanup', async (t) => {
const compiled = readFileSync(new URL('../../.test-dist/src/web/App.js', import.meta.url), 'utf8');
const component = parse(compiled, { sourceType: 'module' }).program.body
.find((node) => node.declaration?.id?.name === 'App').declaration;
const effect = component.body.body.map((node) => node.expression)
.filter((node) => node?.callee?.name === 'useEffect')
.map((node) => node.arguments[0])
.find((node) => compiled.slice(node.start, node.end).includes('loadState('));
// Execute the shipped effect with a deferred request; no DOM or copied polling loop.
const setup = new Function('loadState', `return (${compiled.slice(effect.start, effect.end)})`);
t.mock.timers.enable({ apis: ['setTimeout', 'setInterval'] });
let calls = 0;
let finish;
const start = setup(() => {
calls++;
return new Promise((resolve) => { finish = resolve; });
});
const cleanup = start();
assert.equal(calls, 1);
t.mock.timers.tick(40_000);
assert.equal(calls, 1);
finish();
await Promise.resolve();
t.mock.timers.tick(4_999);
assert.equal(calls, 1);
t.mock.timers.tick(1);
assert.equal(calls, 2);
cleanup();
finish();
await Promise.resolve();
t.mock.timers.tick(40_000);
assert.equal(calls, 2);
const cleanupScheduled = start();
finish();
await Promise.resolve();
cleanupScheduled();
t.mock.timers.tick(40_000);
assert.equal(calls, 3);
});