119 lines
3.5 KiB
JavaScript
119 lines
3.5 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import {
|
|
cancelSessionActiveRequest,
|
|
quiesceSessionStdioExtensions,
|
|
sessionStdioExtensionNames,
|
|
} from './session-runtime-lifecycle.mjs';
|
|
|
|
function jsonResponse(payload, { ok = true, status = 200 } = {}) {
|
|
return {
|
|
ok,
|
|
status,
|
|
text: async () => JSON.stringify(payload),
|
|
};
|
|
}
|
|
|
|
test('sessionStdioExtensionNames returns unique stdio extensions only', () => {
|
|
assert.deepEqual(
|
|
sessionStdioExtensionNames([
|
|
{ name: 'sandbox-fs', type: 'stdio' },
|
|
{ name: 'skills', type: 'platform' },
|
|
{ name: 'sandbox-fs', type: 'stdio' },
|
|
{ name: 'tkmind-search', type: 'stdio' },
|
|
]),
|
|
['sandbox-fs', 'tkmind-search'],
|
|
);
|
|
});
|
|
|
|
test('cancelSessionActiveRequest cancels an in-flight request without deleting its session', async () => {
|
|
const calls = [];
|
|
const result = await cancelSessionActiveRequest(
|
|
async (pathname, init) => {
|
|
calls.push({ pathname, init });
|
|
return {
|
|
ok: true,
|
|
status: 204,
|
|
text: async () => '',
|
|
};
|
|
},
|
|
'session-1',
|
|
'request-1',
|
|
);
|
|
|
|
assert.deepEqual(result, { cancelled: true, skipped: false });
|
|
assert.deepEqual(calls.map(({ pathname }) => pathname), ['/sessions/session-1/cancel']);
|
|
assert.deepEqual(JSON.parse(calls[0].init.body), { request_id: 'request-1' });
|
|
assert.equal(calls.some(({ pathname }) => pathname.includes('delete')), false);
|
|
});
|
|
|
|
test('cancelSessionActiveRequest tolerates a request that already finished', async () => {
|
|
const result = await cancelSessionActiveRequest(
|
|
async () => ({
|
|
ok: false,
|
|
status: 409,
|
|
text: async () => 'no active request',
|
|
}),
|
|
'session-1',
|
|
'request-1',
|
|
);
|
|
assert.deepEqual(result, { cancelled: false, skipped: true });
|
|
});
|
|
|
|
test('quiesceSessionStdioExtensions removes stdio children without deleting session', async () => {
|
|
const calls = [];
|
|
const apiFetch = async (pathname, init = {}) => {
|
|
calls.push({ pathname, init });
|
|
if (pathname === '/sessions/session-1/extensions') {
|
|
return jsonResponse({
|
|
extensions: [
|
|
{ name: 'sandbox-fs', type: 'stdio' },
|
|
{ name: 'skills', type: 'platform' },
|
|
{ name: 'tkmind-search', type: 'stdio' },
|
|
],
|
|
});
|
|
}
|
|
if (pathname === '/agent/remove_extension') {
|
|
return jsonResponse({ ok: true });
|
|
}
|
|
throw new Error(`unexpected path: ${pathname}`);
|
|
};
|
|
|
|
const result = await quiesceSessionStdioExtensions(apiFetch, 'session-1');
|
|
|
|
assert.deepEqual(result, {
|
|
removed: ['sandbox-fs', 'tkmind-search'],
|
|
skipped: false,
|
|
});
|
|
assert.deepEqual(
|
|
calls.map(({ pathname }) => pathname),
|
|
[
|
|
'/sessions/session-1/extensions',
|
|
'/agent/remove_extension',
|
|
'/agent/remove_extension',
|
|
],
|
|
);
|
|
assert.deepEqual(
|
|
calls.slice(1).map(({ init }) => JSON.parse(init.body)),
|
|
[
|
|
{ session_id: 'session-1', name: 'sandbox-fs' },
|
|
{ session_id: 'session-1', name: 'tkmind-search' },
|
|
],
|
|
);
|
|
assert.equal(calls.some(({ pathname }) => pathname.includes('delete')), false);
|
|
});
|
|
|
|
test('quiesceSessionStdioExtensions fails when upstream removal is not acknowledged', async () => {
|
|
const apiFetch = async (pathname) => {
|
|
if (pathname.endsWith('/extensions')) {
|
|
return jsonResponse({ extensions: [{ name: 'sandbox-fs', type: 'stdio' }] });
|
|
}
|
|
return jsonResponse({ message: 'remove failed' }, { ok: false, status: 500 });
|
|
};
|
|
|
|
await assert.rejects(
|
|
quiesceSessionStdioExtensions(apiFetch, 'session-1'),
|
|
/remove failed/,
|
|
);
|
|
});
|