75 lines
3.1 KiB
JavaScript
75 lines
3.1 KiB
JavaScript
|
|
/**
|
|||
|
|
* 落库用例(任务 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 });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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');
|
|||
|
|
});
|