5835799b69
- 新增 vitest 配置和测试基础设施 - 添加 adapter.test.ts: 测试 Core 模块初始化和 Agent 管理 (18 tests) - 添加 token.test.ts: 测试 Token 生成、验证和中间件 (25 tests) - 添加 handler.test.ts: 测试权限处理器 (18 tests) - 添加 ws.test.ts: 测试 WebSocket 连接和消息处理 (19 tests) - 添加 sse.test.ts: 测试 SSE 事件发送 (14 tests) - 添加 sessions.test.ts: 测试会话路由 (16 tests) - 添加 config.test.ts: 测试配置路由 (10 tests) - 添加 context.test.ts: 测试上下文压缩路由 (9 tests) - 添加 providers.test.ts: 测试 Provider 管理路由 (18 tests) - 添加 manager.test.ts: 测试 SessionManager (48 tests) 总计 195 个测试,覆盖率从 0% 提升至 29.59%
281 lines
8.4 KiB
TypeScript
281 lines
8.4 KiB
TypeScript
/**
|
|
* Sessions Route 测试
|
|
*
|
|
* 测试会话管理 REST API 端点
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { Hono } from 'hono';
|
|
|
|
// Use vi.hoisted to create mocks before vi.mock is hoisted
|
|
const { mockList, mockCreate, mockGet, mockExists, mockDelete, mockGetMessages, mockAddMessage } = vi.hoisted(() => ({
|
|
mockList: vi.fn(),
|
|
mockCreate: vi.fn(),
|
|
mockGet: vi.fn(),
|
|
mockExists: vi.fn(),
|
|
mockDelete: vi.fn(),
|
|
mockGetMessages: vi.fn(),
|
|
mockAddMessage: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../../../src/session/manager.js', () => ({
|
|
getSessionManager: vi.fn(() => ({
|
|
list: mockList,
|
|
create: mockCreate,
|
|
get: mockGet,
|
|
exists: mockExists,
|
|
delete: mockDelete,
|
|
getMessages: mockGetMessages,
|
|
addMessage: mockAddMessage,
|
|
})),
|
|
}));
|
|
|
|
import { sessionsRouter } from '../../../src/routes/sessions.js';
|
|
|
|
// Create test app
|
|
const app = new Hono();
|
|
app.route('/sessions', sessionsRouter);
|
|
|
|
describe('Sessions Route', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('GET /sessions - 列出会话', () => {
|
|
it('返回会话列表', async () => {
|
|
const sessions = [
|
|
{ id: 'session-1', name: 'Test 1', status: 'idle', createdAt: 1000, updatedAt: 1000 },
|
|
{ id: 'session-2', name: 'Test 2', status: 'active', createdAt: 2000, updatedAt: 2000 },
|
|
];
|
|
mockList.mockReturnValue(sessions);
|
|
|
|
const res = await app.request('/sessions');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(json.success).toBe(true);
|
|
expect(json.data).toEqual(sessions);
|
|
});
|
|
|
|
it('空列表返回空数组', async () => {
|
|
mockList.mockReturnValue([]);
|
|
|
|
const res = await app.request('/sessions');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(json.success).toBe(true);
|
|
expect(json.data).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('POST /sessions - 创建会话', () => {
|
|
it('创建新会话', async () => {
|
|
const newSession = {
|
|
id: 'new-session',
|
|
name: 'My Session',
|
|
status: 'idle',
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
};
|
|
mockCreate.mockResolvedValue(newSession);
|
|
|
|
const res = await app.request('/sessions', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name: 'My Session' }),
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(201);
|
|
expect(json.success).toBe(true);
|
|
expect(json.data).toEqual(newSession);
|
|
});
|
|
|
|
it('无效输入返回 400', async () => {
|
|
const res = await app.request('/sessions', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: 'invalid json',
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(400);
|
|
expect(json.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('GET /sessions/:id - 获取单个会话', () => {
|
|
it('返回存在的会话', async () => {
|
|
const session = { id: 'session-1', name: 'Test', status: 'idle' };
|
|
mockGet.mockReturnValue(session);
|
|
|
|
const res = await app.request('/sessions/session-1');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(json.success).toBe(true);
|
|
expect(json.data).toEqual(session);
|
|
});
|
|
|
|
it('不存在的会话返回 404', async () => {
|
|
mockGet.mockReturnValue(null);
|
|
|
|
const res = await app.request('/sessions/non-existent');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(404);
|
|
expect(json.success).toBe(false);
|
|
expect(json.error).toBe('Session not found');
|
|
});
|
|
});
|
|
|
|
describe('DELETE /sessions/:id - 删除会话', () => {
|
|
it('删除存在的会话', async () => {
|
|
mockExists.mockReturnValue(true);
|
|
mockDelete.mockResolvedValue(true);
|
|
|
|
const res = await app.request('/sessions/session-1', {
|
|
method: 'DELETE',
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(json.success).toBe(true);
|
|
expect(mockDelete).toHaveBeenCalledWith('session-1');
|
|
});
|
|
|
|
it('不存在的会话返回 404', async () => {
|
|
mockExists.mockReturnValue(false);
|
|
|
|
const res = await app.request('/sessions/non-existent', {
|
|
method: 'DELETE',
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(404);
|
|
expect(json.success).toBe(false);
|
|
expect(json.error).toBe('Session not found');
|
|
});
|
|
});
|
|
|
|
describe('GET /sessions/:id/messages - 获取消息', () => {
|
|
it('返回会话消息', async () => {
|
|
const messages = [
|
|
{ id: 'msg-1', role: 'user', content: 'Hello', timestamp: 1000 },
|
|
{ id: 'msg-2', role: 'assistant', content: 'Hi!', timestamp: 2000 },
|
|
];
|
|
mockExists.mockReturnValue(true);
|
|
mockGetMessages.mockReturnValue(messages);
|
|
|
|
const res = await app.request('/sessions/session-1/messages');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(json.success).toBe(true);
|
|
expect(json.data).toEqual(messages);
|
|
});
|
|
|
|
it('不存在的会话返回 404', async () => {
|
|
mockExists.mockReturnValue(false);
|
|
|
|
const res = await app.request('/sessions/non-existent/messages');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(404);
|
|
expect(json.success).toBe(false);
|
|
expect(json.error).toBe('Session not found');
|
|
});
|
|
|
|
it('空消息返回空数组', async () => {
|
|
mockExists.mockReturnValue(true);
|
|
mockGetMessages.mockReturnValue([]);
|
|
|
|
const res = await app.request('/sessions/session-1/messages');
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(json.data).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('POST /sessions/:id/messages - 发送消息', () => {
|
|
it('添加用户消息', async () => {
|
|
const message = { id: 'msg-1', role: 'user', content: 'Hello', timestamp: Date.now() };
|
|
mockExists.mockReturnValue(true);
|
|
mockAddMessage.mockResolvedValue(message);
|
|
|
|
const res = await app.request('/sessions/session-1/messages', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ role: 'user', content: 'Hello' }),
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(201);
|
|
expect(json.success).toBe(true);
|
|
expect(json.data).toEqual(message);
|
|
});
|
|
|
|
it('添加助手消息', async () => {
|
|
const message = { id: 'msg-2', role: 'assistant', content: 'Hi!', timestamp: Date.now() };
|
|
mockExists.mockReturnValue(true);
|
|
mockAddMessage.mockResolvedValue(message);
|
|
|
|
const res = await app.request('/sessions/session-1/messages', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ role: 'assistant', content: 'Hi!' }),
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(201);
|
|
expect(json.success).toBe(true);
|
|
});
|
|
|
|
it('不存在的会话返回 404', async () => {
|
|
mockExists.mockReturnValue(false);
|
|
|
|
const res = await app.request('/sessions/non-existent/messages', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ role: 'user', content: 'Hello' }),
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(404);
|
|
expect(json.success).toBe(false);
|
|
});
|
|
|
|
it('无效输入返回 400', async () => {
|
|
mockExists.mockReturnValue(true);
|
|
|
|
const res = await app.request('/sessions/session-1/messages', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ role: 'invalid', content: 'Hello' }),
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(400);
|
|
expect(json.success).toBe(false);
|
|
});
|
|
|
|
it('添加消息失败返回 500', async () => {
|
|
mockExists.mockReturnValue(true);
|
|
mockAddMessage.mockResolvedValue(null);
|
|
|
|
const res = await app.request('/sessions/session-1/messages', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ role: 'user', content: 'Hello' }),
|
|
});
|
|
const json = await res.json();
|
|
|
|
expect(res.status).toBe(500);
|
|
expect(json.success).toBe(false);
|
|
expect(json.error).toBe('Failed to add message');
|
|
});
|
|
});
|
|
});
|