Files
memind/server/portal-mindspace-agent-operation-routes.test.mjs

289 lines
8.1 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { attachPortalMindSpaceAgentOperationRoutes } from './portal-mindspace-agent-operation-routes.mjs';
function createRouterRecorder() {
const routes = new Map();
return {
routes,
post(path, handler) {
routes.set(`POST ${path}`, handler);
},
};
}
function createResponseRecorder() {
return {
statusCode: 200,
body: undefined,
status(code) {
this.statusCode = code;
return this;
},
json(body) {
this.body = body;
return this;
},
};
}
function createRequest(overrides = {}) {
return {
body: {},
ip: '127.0.0.1',
...overrides,
};
}
function createDependencies(overrides = {}) {
const calls = {
data: [],
errors: [],
mapped: [],
};
return {
calls,
dependencies: {
sendData(res, req, data, status = 200) {
calls.data.push({ res, req, data, status });
return res.status(status).json({ data });
},
sendError(res, req, status, code, message) {
calls.errors.push({ res, req, status, code, message });
return res.status(status).json({ error: { code, message } });
},
handleMindSpaceError(res, req, error) {
calls.mapped.push({ res, req, error });
return res.status(418).json({ mapped: error.message });
},
...overrides,
},
};
}
test('MindSpace agent operation module preserves route inventory and order', () => {
const api = createRouterRecorder();
attachPortalMindSpaceAgentOperationRoutes(api);
assert.deepEqual([...api.routes.keys()], [
'POST /agent/mindspace_page_patch',
'POST /agent/mindspace_asset_delete',
'POST /agent/mindspace_asset_download',
]);
});
test('page patch preserves payload projection and unavailable response', async () => {
const api = createRouterRecorder();
const dependencies = createDependencies({
getMindSpacePageLiveEdit: () => ({
async applyAgentPatch(body) {
assert.deepEqual(body, { page_id: 'page-1', patch: 'title' });
return {
page: {
id: 'page-1',
title: 'Updated',
summary: 'Summary',
versionNo: 3,
updatedAt: '2026-07-23T00:00:00Z',
},
liveRevision: 7,
internal: 'hidden',
};
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(api, dependencies.dependencies);
const res = createResponseRecorder();
await api.routes.get('POST /agent/mindspace_page_patch')(
createRequest({ body: { page_id: 'page-1', patch: 'title' } }),
res,
);
assert.deepEqual(res.body, {
data: {
pageId: 'page-1',
title: 'Updated',
summary: 'Summary',
versionNo: 3,
updatedAt: '2026-07-23T00:00:00Z',
liveRevision: 7,
},
});
const unavailableApi = createRouterRecorder();
attachPortalMindSpaceAgentOperationRoutes(unavailableApi);
const unavailableRes = createResponseRecorder();
await unavailableApi.routes.get('POST /agent/mindspace_page_patch')(
createRequest(),
unavailableRes,
);
assert.equal(unavailableRes.statusCode, 503);
assert.deepEqual(unavailableRes.body, { message: 'MindSpace 未启用' });
});
test('page patch preserves expected and fallback error mapping', async () => {
for (const [code, expectedStatus] of [
['forbidden', 403],
['page_binding_mismatch', 403],
['invalid_request', 400],
]) {
const api = createRouterRecorder();
const failure = Object.assign(new Error(code), { code });
const dependencies = createDependencies({
getMindSpacePageLiveEdit: () => ({
async applyAgentPatch() {
throw failure;
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(api, dependencies.dependencies);
await api.routes.get('POST /agent/mindspace_page_patch')(
createRequest(),
createResponseRecorder(),
);
assert.equal(dependencies.calls.errors[0].status, expectedStatus);
assert.equal(dependencies.calls.errors[0].code, code);
}
const api = createRouterRecorder();
const failure = new Error('patch failed');
const dependencies = createDependencies({
getMindSpacePageLiveEdit: () => ({
async applyAgentPatch() {
throw failure;
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(api, dependencies.dependencies);
await api.routes.get('POST /agent/mindspace_page_patch')(
createRequest(),
createResponseRecorder(),
);
assert.equal(dependencies.calls.mapped[0].error, failure);
});
test('asset delete preserves body, audit, response, and error mapping', async () => {
const audit = [];
const api = createRouterRecorder();
const dependencies = createDependencies({
getMindSpaceAssetAgent: () => ({
async applyAgentDelete(body) {
assert.deepEqual(body, { asset_id: 'asset-1', confirm: true });
return { userId: 'user-1', assetId: 'asset-1', deleted: true };
},
}),
getMindSpaceAudit: () => ({
async write(entry) {
audit.push(entry);
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(api, dependencies.dependencies);
const req = createRequest({
body: { asset_id: 'asset-1', confirm: true },
ip: '10.0.0.8',
});
const res = createResponseRecorder();
await api.routes.get('POST /agent/mindspace_asset_delete')(req, res);
assert.deepEqual(audit, [{
userId: 'user-1',
action: 'asset.delete',
objectType: 'asset',
objectId: 'asset-1',
ip: '10.0.0.8',
metadata: { via: 'agent' },
}]);
assert.deepEqual(dependencies.calls.data[0].data, {
userId: 'user-1',
assetId: 'asset-1',
deleted: true,
});
for (const [code, expectedStatus] of [
['forbidden', 403],
['invalid_request', 400],
['confirmation_required', 400],
]) {
const failureApi = createRouterRecorder();
const failureDependencies = createDependencies({
getMindSpaceAssetAgent: () => ({
async applyAgentDelete() {
throw Object.assign(new Error(code), { code });
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(
failureApi,
failureDependencies.dependencies,
);
await failureApi.routes.get('POST /agent/mindspace_asset_delete')(
createRequest(),
createResponseRecorder(),
);
assert.equal(failureDependencies.calls.errors[0].status, expectedStatus);
}
});
test('asset download preserves audit metadata and error mapping', async () => {
const audit = [];
const api = createRouterRecorder();
const dependencies = createDependencies({
getMindSpaceAssetAgent: () => ({
async applyAgentDownload(body) {
assert.deepEqual(body, { asset_id: 'asset-2' });
return {
userId: 'user-2',
assetId: 'asset-2',
relativePath: 'downloads/report.docx',
};
},
}),
getMindSpaceAudit: () => ({
async write(entry) {
audit.push(entry);
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(api, dependencies.dependencies);
await api.routes.get('POST /agent/mindspace_asset_download')(
createRequest({
body: { asset_id: 'asset-2' },
ip: '10.0.0.9',
}),
createResponseRecorder(),
);
assert.deepEqual(audit[0], {
userId: 'user-2',
action: 'asset.download',
objectType: 'asset',
objectId: 'asset-2',
ip: '10.0.0.9',
metadata: {
via: 'agent',
relativePath: 'downloads/report.docx',
},
});
for (const [code, expectedStatus] of [
['forbidden', 403],
['invalid_request', 400],
['asset_not_found', 400],
]) {
const failureApi = createRouterRecorder();
const failureDependencies = createDependencies({
getMindSpaceAssetAgent: () => ({
async applyAgentDownload() {
throw Object.assign(new Error(code), { code });
},
}),
});
attachPortalMindSpaceAgentOperationRoutes(
failureApi,
failureDependencies.dependencies,
);
await failureApi.routes.get('POST /agent/mindspace_asset_download')(
createRequest(),
createResponseRecorder(),
);
assert.equal(failureDependencies.calls.errors[0].status, expectedStatus);
}
});