225 lines
6.1 KiB
JavaScript
225 lines
6.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { attachPortalRuntimeRoutes } from './portal-runtime-routes.mjs';
|
|
|
|
function createRouterRecorder() {
|
|
const routes = new Map();
|
|
return {
|
|
routes,
|
|
get(path, handler) {
|
|
routes.set(path, handler);
|
|
},
|
|
};
|
|
}
|
|
|
|
function createResponseRecorder() {
|
|
return {
|
|
statusCode: 200,
|
|
body: undefined,
|
|
responseType: null,
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
},
|
|
send(body) {
|
|
this.responseType = 'send';
|
|
this.body = body;
|
|
return this;
|
|
},
|
|
json(body) {
|
|
this.responseType = 'json';
|
|
this.body = body;
|
|
return this;
|
|
},
|
|
};
|
|
}
|
|
|
|
test('portal runtime route module preserves the status route inventory', () => {
|
|
const api = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(api);
|
|
assert.deepEqual([...api.routes.keys()], ['/status', '/runtime/status']);
|
|
});
|
|
|
|
test('GET /status preserves upstream status and body', async () => {
|
|
const api = createRouterRecorder();
|
|
let waited = false;
|
|
attachPortalRuntimeRoutes(api, {
|
|
waitForUserAuthReady: async () => {
|
|
waited = true;
|
|
},
|
|
getUserAuth: () => ({}),
|
|
getTkmindProxy: () => ({
|
|
async apiFetch(path, init) {
|
|
assert.equal(path, '/status');
|
|
assert.deepEqual(init, { method: 'GET' });
|
|
return {
|
|
status: 207,
|
|
async text() {
|
|
return 'upstream-status';
|
|
},
|
|
};
|
|
},
|
|
}),
|
|
});
|
|
const res = createResponseRecorder();
|
|
let nextCalled = false;
|
|
|
|
await api.routes.get('/status')({}, res, () => {
|
|
nextCalled = true;
|
|
});
|
|
|
|
assert.equal(waited, true);
|
|
assert.equal(nextCalled, false);
|
|
assert.equal(res.statusCode, 207);
|
|
assert.equal(res.responseType, 'send');
|
|
assert.equal(res.body, 'upstream-status');
|
|
});
|
|
|
|
test('GET /status falls through when multi-user proxy services are unavailable', async () => {
|
|
const api = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(api);
|
|
const res = createResponseRecorder();
|
|
let nextCalled = false;
|
|
|
|
await api.routes.get('/status')({}, res, () => {
|
|
nextCalled = true;
|
|
});
|
|
|
|
assert.equal(nextCalled, true);
|
|
assert.equal(res.body, undefined);
|
|
});
|
|
|
|
test('GET /status preserves proxy failure response', async () => {
|
|
const api = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(api, {
|
|
getUserAuth: () => ({}),
|
|
getTkmindProxy: () => ({
|
|
async apiFetch() {
|
|
throw new Error('proxy down');
|
|
},
|
|
}),
|
|
});
|
|
const res = createResponseRecorder();
|
|
|
|
await api.routes.get('/status')({}, res, () => {});
|
|
|
|
assert.equal(res.statusCode, 502);
|
|
assert.deepEqual(res.body, { message: 'proxy down' });
|
|
});
|
|
|
|
test('GET /runtime/status preserves memory, queue, and code-run policy projection', async () => {
|
|
const api = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(api, {
|
|
getTkmindProxy: () => ({
|
|
async getRuntimeStatus() {
|
|
return { workers: [{ id: 'goosed-1' }], memory: { backend: 'legacy' } };
|
|
},
|
|
}),
|
|
getEpisodicMemoryService: () => ({
|
|
async getStatus() {
|
|
return { configuredEnabled: true, mode: 'canary' };
|
|
},
|
|
}),
|
|
getAgentRunGateway: () => ({
|
|
async getQueueStatus() {
|
|
return { active: 1, pendingDispatches: 2 };
|
|
},
|
|
}),
|
|
env: {
|
|
MEMIND_AGENT_CODE_RUNS_ENABLED: '1',
|
|
MEMIND_AGENT_CODE_RUNS_USER_IDS: 'user-a, user-b',
|
|
MEMIND_AGENT_CODE_RUN_TASK_TYPES: 'page,code',
|
|
MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION: 'true',
|
|
},
|
|
});
|
|
const res = createResponseRecorder();
|
|
|
|
await api.routes.get('/runtime/status')({}, res);
|
|
|
|
assert.equal(res.statusCode, 200);
|
|
assert.equal(res.body.ok, true);
|
|
assert.equal(typeof res.body.timestamp, 'string');
|
|
assert.deepEqual(res.body.memory, {
|
|
backend: 'legacy',
|
|
episodic: { configuredEnabled: true, mode: 'canary' },
|
|
});
|
|
assert.deepEqual(res.body.toolRuntime, {
|
|
codeRunPolicy: {
|
|
source: 'env',
|
|
enabled: true,
|
|
clientEnabled: false,
|
|
userAllowlist: ['user-a', 'user-b'],
|
|
taskTypeAllowlist: ['page', 'code'],
|
|
requireValidation: true,
|
|
pageDataDevAutodetect: false,
|
|
generalAutodetect: false,
|
|
envOverrideActive: false,
|
|
updatedAt: null,
|
|
updatedBy: null,
|
|
},
|
|
queue: { active: 1, pendingDispatches: 2 },
|
|
});
|
|
});
|
|
|
|
test('GET /runtime/status preserves fail-open dependency projections', async () => {
|
|
const api = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(api, {
|
|
getTkmindProxy: () => ({
|
|
async getRuntimeStatus() {
|
|
return { memory: { backend: 'legacy' } };
|
|
},
|
|
}),
|
|
getEpisodicMemoryService: () => ({
|
|
async getStatus() {
|
|
throw new Error('episodic unavailable');
|
|
},
|
|
}),
|
|
getAgentRunGateway: () => ({
|
|
async getQueueStatus() {
|
|
throw new Error('queue unavailable');
|
|
},
|
|
}),
|
|
});
|
|
const res = createResponseRecorder();
|
|
|
|
await api.routes.get('/runtime/status')({}, res);
|
|
|
|
assert.deepEqual(res.body.memory, {
|
|
backend: 'legacy',
|
|
episodic: {
|
|
configuredEnabled: false,
|
|
mode: 'off',
|
|
error: 'episodic unavailable',
|
|
},
|
|
});
|
|
assert.deepEqual(res.body.toolRuntime.queue, { error: 'queue unavailable' });
|
|
});
|
|
|
|
test('GET /runtime/status preserves unavailable and upstream error responses', async () => {
|
|
const unavailableApi = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(unavailableApi);
|
|
const unavailableRes = createResponseRecorder();
|
|
await unavailableApi.routes.get('/runtime/status')({}, unavailableRes);
|
|
assert.equal(unavailableRes.statusCode, 503);
|
|
assert.deepEqual(unavailableRes.body, {
|
|
ok: false,
|
|
message: 'runtime router unavailable',
|
|
});
|
|
|
|
const failingApi = createRouterRecorder();
|
|
attachPortalRuntimeRoutes(failingApi, {
|
|
getTkmindProxy: () => ({
|
|
async getRuntimeStatus() {
|
|
throw new Error('runtime down');
|
|
},
|
|
}),
|
|
});
|
|
const failingRes = createResponseRecorder();
|
|
await failingApi.routes.get('/runtime/status')({}, failingRes);
|
|
assert.equal(failingRes.statusCode, 502);
|
|
assert.deepEqual(failingRes.body, {
|
|
ok: false,
|
|
message: 'runtime down',
|
|
});
|
|
});
|