57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
|
|
import { ProcessEventBuffer, RuntimeProcessEvent } from '../src/modules/netaclaw/runtime/process_events';
|
||
|
|
|
||
|
|
function event(input: Partial<RuntimeProcessEvent> = {}): RuntimeProcessEvent {
|
||
|
|
return {
|
||
|
|
version: 1,
|
||
|
|
operationId: 'tool-call-1',
|
||
|
|
targetType: 'tool',
|
||
|
|
source: 'tool',
|
||
|
|
status: 'running',
|
||
|
|
level: 'info',
|
||
|
|
message: 'working',
|
||
|
|
timestamp: '2026-05-06T00:00:00.000Z',
|
||
|
|
...input,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('ProcessEventBuffer', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
jest.useFakeTimers();
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
jest.useRealTimers();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('coalesces repeated non-terminal events until throttle flush', () => {
|
||
|
|
const emitted: RuntimeProcessEvent[] = [];
|
||
|
|
const buffer = new ProcessEventBuffer(item => emitted.push(item), { throttleMs: 100 });
|
||
|
|
|
||
|
|
buffer.push(event({ current: 1, total: 3 }));
|
||
|
|
buffer.push(event({ current: 2, total: 3 }));
|
||
|
|
|
||
|
|
expect(emitted).toEqual([]);
|
||
|
|
jest.advanceTimersByTime(100);
|
||
|
|
|
||
|
|
expect(emitted).toEqual([
|
||
|
|
expect.objectContaining({
|
||
|
|
current: 2,
|
||
|
|
payload: { repeatCount: 2 },
|
||
|
|
}),
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('flushes pending operation events before terminal events', () => {
|
||
|
|
const emitted: RuntimeProcessEvent[] = [];
|
||
|
|
const buffer = new ProcessEventBuffer(item => emitted.push(item), { throttleMs: 100 });
|
||
|
|
|
||
|
|
buffer.push(event({ current: 1, total: 2 }));
|
||
|
|
buffer.push(event({ status: 'failed', level: 'error', message: 'failed' }));
|
||
|
|
|
||
|
|
expect(emitted).toEqual([
|
||
|
|
expect.objectContaining({ current: 1 }),
|
||
|
|
expect.objectContaining({ status: 'failed', message: 'failed' }),
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
});
|