// Library searches run a few at a time rather than one behind another, and // the session is renewed before it expires. const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const src = fs.readFileSync(path.join(__dirname, '..', 'src/utils/clinicalMcpClient.js'), 'utf8'); // The slot and queue logic on its own, with the bounds given explicitly. function slots(concurrency, queueMax, waitMs) { const slice = src.slice(src.indexOf('function busyError'), src.indexOf('async function callMcpTool')); return new Function('MCP_CONCURRENCY', 'MCP_QUEUE_MAX', 'MCP_QUEUE_WAIT_MS', 'var _inFlight = 0, _waiting = [];' + slice + '; return { acquireSlot, releaseSlot, count: () => _inFlight, waiting: () => _waiting.length };')(concurrency, queueMax, waitMs); } test('a bounded number of calls run at once; the rest wait their turn', async () => { // The slot logic on its own, with the environment's default bound. const fn = slots(3, 12, 8000); await fn.acquireSlot(); await fn.acquireSlot(); await fn.acquireSlot(); assert.equal(fn.count(), 3); let fourthStarted = false; const fourth = fn.acquireSlot().then(() => { fourthStarted = true; }); await new Promise(r => setTimeout(r, 5)); assert.equal(fourthStarted, false, 'the fourth waits'); assert.equal(fn.waiting(), 1); fn.releaseSlot(); await fourth; assert.equal(fourthStarted, true, 'and runs when a slot frees'); assert.equal(fn.count(), 3, 'the slot passed hands rather than being freed'); fn.releaseSlot(); fn.releaseSlot(); fn.releaseSlot(); assert.equal(fn.count(), 0); }); test('past the queue bound a caller is told the library is busy, not held', async () => { const fn = slots(1, 2, 8000); await fn.acquireSlot(); const second = fn.acquireSlot(); const third = fn.acquireSlot(); assert.equal(fn.waiting(), 2); await assert.rejects(fn.acquireSlot(), e => e.statusCode === 503 && e.code === 'RETRIEVAL_BUSY' && e.retryAfterSeconds === 5); fn.releaseSlot(); await second; fn.releaseSlot(); await third; fn.releaseSlot(); assert.equal(fn.count(), 0); }); test('a caller that waits too long is released from the line, and the line forgets it', async () => { const fn = slots(1, 4, 20); // The wait timer is unref'd (a live search keeps the process up in real // use); hold the loop open here so it can fire. const hold = setTimeout(() => {}, 200); await fn.acquireSlot(); const late = fn.acquireSlot(); await assert.rejects(late, e => e.code === 'RETRIEVAL_BUSY'); assert.equal(fn.waiting(), 0, 'the timed-out waiter is gone'); fn.releaseSlot(); assert.equal(fn.count(), 0, 'releasing does not hand the slot to a caller that already gave up'); clearTimeout(hold); }); test('the queue bounds and the busy answer are wired where the route can see them', () => { assert.match(src, /MCP_QUEUE_MAX = positiveInt\(process\.env\.CLINICAL_ASSISTANT_MCP_QUEUE_MAX, MCP_CONCURRENCY \* 4\)/); assert.match(src, /MCP_QUEUE_WAIT_MS = positiveInt\(process\.env\.CLINICAL_ASSISTANT_MCP_QUEUE_WAIT_MS, 8000\)/); assert.match(src, /queueDepth: queueDepth/); }); test('the serial promise chain is gone, the session is kept warm, and the split is logged', () => { assert.doesNotMatch(src, /_mcpCallQueue = queued\.catch/, 'no more one-at-a-time chain'); assert.match(src, /var MCP_CONCURRENCY = positiveInt\(process\.env\.CLINICAL_ASSISTANT_MCP_CONCURRENCY, 3\)/); assert.match(src, /setInterval\(function\(\) \{[\s\S]*?getMcpSession\(\)\.catch/, 'renewed on a timer'); assert.match(src, /_warmTimer\.unref/, 'the timer never keeps the process alive'); assert.match(src, /mcp ' \+ name \+ ': session=' \+ sessionMs \+ 'ms total='/); });