76 lines
3.8 KiB
TypeScript
76 lines
3.8 KiB
TypeScript
|
|
import assert from 'node:assert/strict';
|
||
|
|
import test from 'node:test';
|
||
|
|
import { isStreamingMonitorCommand, TerminalMonitorGuard } from './terminalMonitorGuard';
|
||
|
|
import { applyMonitorStopResult } from './capabilityTools';
|
||
|
|
|
||
|
|
test('TerminalMonitorGuard bounds lines and batches', () => {
|
||
|
|
const guard = new TerminalMonitorGuard();
|
||
|
|
const result = guard.process('chat:job', `${'x'.repeat(800)}\n${'line\n'.repeat(1_000)}`);
|
||
|
|
|
||
|
|
assert.equal(result.action, 'deliver');
|
||
|
|
assert.ok((result.content?.length ?? Infinity) <= 3_000);
|
||
|
|
assert.ok((result.content?.split('\n')[0].length ?? Infinity) <= 500);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('TerminalMonitorGuard suppresses bursts and stops a sustained overload', () => {
|
||
|
|
let now = 0;
|
||
|
|
const guard = new TerminalMonitorGuard({ now: () => now });
|
||
|
|
for (let index = 0; index < 10; index += 1) {
|
||
|
|
assert.equal(guard.process('chat:job', `line ${index}`).action, 'deliver');
|
||
|
|
}
|
||
|
|
assert.equal(guard.process('chat:job', 'burst').action, 'suppress');
|
||
|
|
let action = guard.process('chat:job', 'still flooding').action;
|
||
|
|
for (now = 1_000; now <= 31_000 && action !== 'stop'; now += 1_000) {
|
||
|
|
action = guard.process('chat:job', 'still flooding').action;
|
||
|
|
}
|
||
|
|
assert.equal(action, 'stop');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('monitor stop result does not claim success when the backend stop failed', () => {
|
||
|
|
const failed = applyMonitorStopResult(
|
||
|
|
{ jobId: 'job-1', status: 'running' },
|
||
|
|
{ ok: false, error: 'lost worker' },
|
||
|
|
12,
|
||
|
|
);
|
||
|
|
assert.equal(failed.status, 'running');
|
||
|
|
assert.match(String(failed.output), /stop failed/);
|
||
|
|
assert.match(String(failed.output), /may still be running/);
|
||
|
|
|
||
|
|
const accepted = applyMonitorStopResult(
|
||
|
|
{ jobId: 'job-1', status: 'running' },
|
||
|
|
{ ok: true },
|
||
|
|
12,
|
||
|
|
);
|
||
|
|
assert.equal(accepted.status, 'stopping');
|
||
|
|
assert.match(String(accepted.output), /stop requested/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('isStreamingMonitorCommand requires an actual follow option', () => {
|
||
|
|
assert.equal(isStreamingMonitorCommand('tail app-file.log'), false);
|
||
|
|
assert.equal(isStreamingMonitorCommand('tail -n 10 foo.log'), false);
|
||
|
|
assert.equal(isStreamingMonitorCommand('journalctl --since 5m foo'), false);
|
||
|
|
assert.equal(isStreamingMonitorCommand('tail -f app.log'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('tail -n0F app.log'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('journalctl --follow -u nginx'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('docker logs -f api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('kubectl logs --follow pod/api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('cd /srv && watch npm test'), true);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('isStreamingMonitorCommand recognizes common wrappers and compose logs', () => {
|
||
|
|
assert.equal(isStreamingMonitorCommand('sudo journalctl -f -u nginx'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('sudo -u root tail -f /var/log/syslog'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('env LANG=C tail --follow app.log'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('stdbuf -oL kubectl logs -f pod/api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('timeout 60s tail -f app.log'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('docker compose logs -f api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('sudo -H journalctl -f -u nginx'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('kubectl -n production logs -f pod/api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('kubectl --context prod logs --follow pod/api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('docker --context prod logs -f api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('docker compose -f compose.prod.yml logs -f api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('docker compose -p demo logs -f api'), true);
|
||
|
|
assert.equal(isStreamingMonitorCommand('sudo tail -n 10 app.log'), false);
|
||
|
|
assert.equal(isStreamingMonitorCommand('timeout 60s journalctl --since 5m'), false);
|
||
|
|
});
|