6df82818c5
Gate and bound Portal shadow observations while preserving Native execution. Add fail-closed service boundaries, terminal retention controls, Canary readiness telemetry, ops visibility, and isolated regression coverage.
72 lines
2.2 KiB
JavaScript
72 lines
2.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createShadowObservationDispatcher } from './shadow-dispatcher.mjs';
|
|
|
|
async function flush() {
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
}
|
|
|
|
test('shadow dispatcher is a no-op when observation is disabled', () => {
|
|
const dispatcher = createShadowObservationDispatcher();
|
|
assert.equal(dispatcher.dispatch({ runId: 'run-disabled' }), false);
|
|
assert.deepEqual(dispatcher.status(), {
|
|
enabled: false,
|
|
active: 0,
|
|
queued: 0,
|
|
maxConcurrent: 2,
|
|
maxQueued: 100,
|
|
});
|
|
});
|
|
|
|
test('shadow dispatcher bounds concurrency and drops overflow without blocking callers', async () => {
|
|
const releases = [];
|
|
const started = [];
|
|
const skipped = [];
|
|
const dispatcher = createShadowObservationDispatcher({
|
|
maxConcurrent: 1,
|
|
maxQueued: 2,
|
|
observe: async ({ runId }) => {
|
|
started.push(runId);
|
|
await new Promise((resolve) => releases.push(resolve));
|
|
return { runId };
|
|
},
|
|
onSkipped: async ({ runId }, context) => {
|
|
skipped.push([runId, context.reason]);
|
|
},
|
|
logger: { warn() {} },
|
|
});
|
|
|
|
assert.equal(dispatcher.dispatch({ runId: 'run-1' }), true);
|
|
assert.equal(dispatcher.dispatch({ runId: 'run-2' }), true);
|
|
assert.equal(dispatcher.dispatch({ runId: 'run-3' }), false);
|
|
await flush();
|
|
assert.deepEqual(started, ['run-1']);
|
|
assert.deepEqual(skipped, [['run-3', 'shadow_queue_full']]);
|
|
|
|
releases.shift()();
|
|
await flush();
|
|
assert.deepEqual(started, ['run-1', 'run-2']);
|
|
releases.shift()();
|
|
await flush();
|
|
assert.equal(dispatcher.status().active, 0);
|
|
});
|
|
|
|
test('shadow dispatcher isolates observer and callback failures', async () => {
|
|
const failures = [];
|
|
const dispatcher = createShadowObservationDispatcher({
|
|
observe: async () => {
|
|
throw Object.assign(new Error('remote unavailable'), { code: 'REMOTE_DOWN' });
|
|
},
|
|
onFailed: async ({ runId }, error) => {
|
|
failures.push([runId, error.code]);
|
|
},
|
|
logger: { warn() {} },
|
|
});
|
|
|
|
assert.equal(dispatcher.dispatch({ runId: 'run-failed' }), true);
|
|
await flush();
|
|
assert.deepEqual(failures, [['run-failed', 'REMOTE_DOWN']]);
|
|
assert.equal(dispatcher.status().active, 0);
|
|
});
|