aps-agent/scripts/storage.test.mjs

75 lines
3.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 落库用例(任务 A3.7):会话、消息与幂等键要在进程重启后仍然可查。
*
* 用同一个 SQLite 文件起两次服务,模拟「平台重启」。
*/
import assert from 'node:assert/strict';
import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { test } from 'node:test';
async function startWithDatabase(dbPath) {
const { startServer } = await import('../server/dist/index.js');
return startServer({ host: '127.0.0.1', port: 0, version: 'test', databasePath: dbPath, engine: 'fake' });
}
const postJson = (base, path, body) =>
fetch(`${base}${path}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
test('会话、消息与幂等键在重启后可查', async () => {
const dir = await mkdtemp(join(tmpdir(), 'aps-storage-'));
const dbPath = join(dir, 'aps.sqlite');
try {
let sessionId = '';
let firstRunId = '';
{
const server = await startWithDatabase(dbPath);
try {
const created = await (await postJson(server.url, '/v1/sessions', { scope: 'project', projectId: 'p-default', title: '持久化用例' })).json();
sessionId = created.session.sessionId;
const accepted = await (
await postJson(server.url, `/v1/sessions/${sessionId}/messages`, { text: '试排一版看看', idempotencyKey: 'idem-storage-0001' })
).json();
firstRunId = accepted.runId;
await new Promise((resolve) => setTimeout(resolve, 300));
} finally {
await server.close();
}
}
// 重启:同一个库文件,新的服务实例
{
const server = await startWithDatabase(dbPath);
try {
const sessions = await (await fetch(`${server.url}/v1/sessions`)).json();
assert.equal(sessions.sessions.length, 1, '重启后应还能列出会话');
assert.equal(sessions.sessions[0].sessionId, sessionId);
assert.equal(sessions.sessions[0].title, '持久化用例');
const detail = await (await fetch(`${server.url}/v1/sessions/${sessionId}`)).json();
assert.ok(detail.messages.length >= 2, `重启后应还能读到消息,实际 ${detail.messages.length} 条`);
assert.equal(detail.messages[0].role, 'user');
assert.equal(detail.messages.at(-1).role, 'assistant');
// 幂等键也持久化了:同一 key 重试仍返回同一个 run
const retry = await (
await postJson(server.url, `/v1/sessions/${sessionId}/messages`, { text: '试排一版看看', idempotencyKey: 'idem-storage-0001' })
).json();
assert.equal(retry.runId, firstRunId, '重启后重试应命中同一条受理记录');
} finally {
await server.close();
}
}
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('默认数据库路径来自配置(~/.aps/aps.sqlite)', async () => {
const { loadConfig } = await import('@aps/server/config');
const config = loadConfig({ env: {}, homeDir: 'C:/Users/example' });
assert.equal(config.database.path.replace(/\\/g, '/'), 'C:/Users/example/.aps/aps.sqlite');
});