Publish ITWorx Pulse source
Public source validation / validate (push) Failing after 3m8s

This commit is contained in:
ITWorx Pulse release export
2026-09-03 02:09:19 +02:00
commit bd774932d5
614 changed files with 77116 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { LiveClient, type SocketFactory } from '../../src/liveClient';
import type { MetricQueryRequest } from '../../src/metricClient';
class FakeSocket {
readyState = 0;
onopen: (() => void) | null = null;
onmessage: ((event: { data: unknown }) => void) | null = null;
onerror: (() => void) | null = null;
onclose: (() => void) | null = null;
readonly sent: string[] = [];
open(): void { this.readyState = 1; this.onopen?.(); }
send(payload: string): void { this.sent.push(payload); }
close(): void { this.readyState = 3; this.onclose?.(); }
}
const request: MetricQueryRequest = {
metric: 'host.cpu.utilization',
scope: { serverId: 'smoke-host' },
range: { from: '2026-08-10T06:00:00.000Z', to: '2026-08-10T06:05:00.000Z', stepSeconds: 15 },
aggregation: 'avg',
};
afterEach(() => vi.useRealTimers());
describe('LiveClient subscription lifecycle', () => {
it('reuses one socket when React replaces an equivalent listener inside the release grace', async () => {
vi.useFakeTimers();
const sockets: FakeSocket[] = [];
const factory = vi.fn(() => {
const socket = new FakeSocket();
sockets.push(socket);
return socket;
}) as unknown as SocketFactory;
const client = new LiveClient('/api/v1/live', factory);
const first = client.subscribe(request, () => undefined);
sockets[0].open();
await Promise.resolve();
first.unsubscribe();
const shifted = { ...request, range: { ...request.range, from: '2026-08-10T06:01:00.000Z', to: '2026-08-10T06:06:00.000Z' } };
const second = client.subscribe(shifted, () => undefined);
await vi.advanceTimersByTimeAsync(300);
expect(factory).toHaveBeenCalledTimes(1);
expect(sockets[0].readyState).toBe(1);
expect(sockets[0].sent.filter((payload) => payload.includes('unsubscribe'))).toHaveLength(0);
await vi.advanceTimersByTimeAsync(30_000);
expect(sockets[0].sent.some((payload) => payload.includes('"type":"ping"'))).toBe(true);
second.unsubscribe();
await vi.advanceTimersByTimeAsync(251);
expect(sockets[0].readyState).toBe(1);
await vi.advanceTimersByTimeAsync(10_000);
expect(sockets[0].readyState).toBe(3);
});
it('reuses an idle transport while a rotating dashboard loads its next query', async () => {
vi.useFakeTimers();
const sockets: FakeSocket[] = [];
const factory = vi.fn(() => {
const socket = new FakeSocket();
sockets.push(socket);
return socket;
}) as unknown as SocketFactory;
const client = new LiveClient('/api/v1/live', factory);
const first = client.subscribe(request, () => undefined);
sockets[0].open();
await Promise.resolve();
first.unsubscribe();
// Subscription state is released after 250 ms, but the bounded transport
// grace bridges a slower dashboard document fetch.
await vi.advanceTimersByTimeAsync(2_000);
expect(sockets[0].readyState).toBe(1);
const nextRequest = { ...request, metric: 'host.memory.utilization' };
const second = client.subscribe(nextRequest, () => undefined);
await Promise.resolve();
expect(factory).toHaveBeenCalledTimes(1);
expect(sockets[0].readyState).toBe(1);
expect(sockets[0].sent.some((payload) => payload.includes('host.memory.utilization'))).toBe(true);
second.unsubscribe();
await vi.advanceTimersByTimeAsync(10_251);
expect(sockets[0].readyState).toBe(3);
});
it('resubscribes once after reconnect and resumes samples on the bounded subscription', async () => {
vi.useFakeTimers();
const sockets: FakeSocket[] = [];
const factory = vi.fn(() => { const socket = new FakeSocket(); sockets.push(socket); return socket; }) as unknown as SocketFactory;
const events: string[] = [];
const client = new LiveClient('/api/v1/live', factory);
const subscription = client.subscribe(request, (event) => events.push(event.type));
sockets[0].open();
await Promise.resolve();
expect(sockets[0].sent.filter((payload) => payload.includes('"type":"subscribe"'))).toHaveLength(1);
sockets[0].close();
expect(events).toContain('status');
await vi.advanceTimersByTimeAsync(1_000);
expect(factory).toHaveBeenCalledTimes(2);
sockets[1].open();
await Promise.resolve();
const subscribe = JSON.parse(sockets[1].sent.find((payload) => payload.includes('"type":"subscribe"')) ?? '{}') as { subscriptionId?: string };
expect(sockets[1].sent.filter((payload) => payload.includes('"type":"subscribe"'))).toHaveLength(1);
sockets[1].onmessage?.({ data: JSON.stringify({ type: 'samples', subscriptionId: subscribe.subscriptionId, sequence: 1, samples: [{ timestamp: '2026-08-10T06:06:00.000Z', value: 42, labels: {} }] }) });
expect(events.at(-1)).toBe('samples');
expect(sockets).toHaveLength(2);
subscription.unsubscribe();
await vi.advanceTimersByTimeAsync(10_251);
});
});