/** * 引擎工具回调的端到端用例(任务 A2.5)。 * * 路径:HTTP 入口(/internal/tool-call)→ 应用服务 → Core.invoke → 假 Provider → 回执与执行记录。 * 同时验证鉴权:只允许 loopback + 内部令牌。 */ import assert from 'node:assert/strict'; import { test } from 'node:test'; async function startWithProvider() { process.env.APS_DEV_PROVIDER = '1'; const { startServer } = await import('../server/dist/index.js'); const server = await startServer({ host: '127.0.0.1', port: 0, version: 'test', databasePath: ':memory:', engine: 'fake' }); const created = await fetch(`${server.url}/v1/sessions`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ scope: 'project', projectId: 'p-default', title: '工具回调会话' }), }); const session = (await created.json()).session; return { server, session }; } const callTool = (server, body, token) => fetch(`${server.url}/internal/tool-call`, { method: 'POST', headers: { 'content-type': 'application/json', ...(token === undefined ? {} : { 'x-aps-internal-token': token }) }, body: JSON.stringify(body), }); test('HTTP → 应用服务 → Core → 假 Provider 的完整链路', async () => { const { server, session } = await startWithProvider(); try { const response = await callTool( server, { sessionId: session.sessionId, capabilityId: 'fake.echo', params: { text: '端到端' } }, server.internalToken, ); assert.equal(response.status, 200); const receipt = await response.json(); assert.equal(receipt.status, 'succeeded'); assert.deepEqual(receipt.result, { echo: '端到端' }); // 执行记录:身份取自会话归属者,参数只留摘要 const record = server.service.core.executions.get(receipt.executionId); assert.ok(record); assert.equal(record.sessionId, session.sessionId); assert.equal(record.projectId, 'p-default'); assert.equal(record.subjectUserId, 'dev-user', '身份应取自会话归属者,而不是调用方自带'); assert.match(record.paramsDigest, /^sha256:/); const lookup = await fetch(`${server.url}/v1/executions/${receipt.executionId}`); assert.equal(lookup.status, 200); assert.equal((await lookup.json()).status, 'succeeded'); } finally { delete process.env.APS_DEV_PROVIDER; await server.close(); } }); test('内部令牌缺失或错误时拒绝,且不产生执行记录', async () => { const { server, session } = await startWithProvider(); try { const body = { sessionId: session.sessionId, capabilityId: 'fake.echo', params: { text: 'x' } }; const missing = await callTool(server, body); assert.equal(missing.status, 401); assert.equal((await missing.json()).error.code, 'unauthorized'); const wrong = await callTool(server, body, 'not-the-token'); assert.equal(wrong.status, 401); const before = server.service.core.executions.list().length; const bad = await callTool(server, { sessionId: session.sessionId }, server.internalToken); assert.equal(bad.status, 400, '缺 capabilityId 应 400'); assert.equal(server.service.core.executions.list().length, before, '被拒的调用不应产生执行记录'); } finally { delete process.env.APS_DEV_PROVIDER; await server.close(); } }); test('未知能力经回调返回失败回执(不是 HTTP 错误)', async () => { const { server, session } = await startWithProvider(); try { const response = await callTool( server, { sessionId: session.sessionId, capabilityId: 'fake.__nope__', params: {} }, server.internalToken, ); assert.equal(response.status, 200, '能力不存在属于业务失败,不是协议错误'); const receipt = await response.json(); assert.equal(receipt.status, 'failed'); assert.equal(receipt.errorKind, 'invalid_argument'); } finally { delete process.env.APS_DEV_PROVIDER; await server.close(); } });