import { describe, it, expect, beforeEach } from 'vitest'; import { testClient } from 'hono/testing'; import { IntegrationTestDatabase, setupIntegrationDatabaseHooks, TestDataFactory } from '../utils/integration-test-db'; import { UserEntity } from '../../src/modules/users/user.entity'; import { authRoutes } from '../../src/api'; import { AuthService } from '../../src/modules/auth/auth.service'; import { UserService } from '../../src/modules/users/user.service'; import { DisabledStatus } from '../../src/share/types'; // 设置集成测试钩子 setupIntegrationDatabaseHooks() describe('认证API集成测试 (使用hono/testing)', () => { let client: ReturnType>['api']['v1']; let authService: AuthService; let userService: UserService; let testToken: string; let testUser: any; beforeEach(async () => { // 创建测试客户端 client = testClient(authRoutes).api.v1; // 获取数据源 const dataSource = await IntegrationTestDatabase.getDataSource(); // 初始化服务 userService = new UserService(dataSource); authService = new AuthService(userService); // 创建测试用户前先删除可能存在的重复用户 const userRepository = dataSource.getRepository(UserEntity); await userRepository.delete({ username: 'testuser' }); testUser = await TestDataFactory.createTestUser(dataSource, { username: 'testuser', password: 'TestPassword123!', email: 'testuser@example.com' }); // 生成测试用户的token testToken = authService.generateToken(testUser); }); describe('登录端点测试 (POST /api/v1/auth/login)', () => { it('应该使用正确凭据成功登录', async () => { const loginData = { username: 'testuser', password: 'TestPassword123!' }; const response = await client.auth.login.$post({ json: loginData }); expect(response.status).toBe(200); if (response.status === 200) { const responseData = await response.json(); expect(responseData).toHaveProperty('token'); expect(responseData).toHaveProperty('user'); expect(responseData.user.username).toBe('testuser'); expect(responseData.user.email).toBe('testuser@example.com'); expect(typeof responseData.token).toBe('string'); expect(responseData.token.length).toBeGreaterThan(0); } }); it('应该拒绝错误密码的登录', async () => { const loginData = { username: 'testuser', password: 'WrongPassword123!' }; const response = await client.auth.login.$post({ json: loginData }); // 认证失败应该返回401 expect(response.status).toBe(401); if (response.status === 401){ const responseData = await response.json(); expect(responseData.message).toContain('用户名或密码错误'); } }); it('应该拒绝不存在的用户登录', async () => { const loginData = { username: 'nonexistent_user', password: 'TestPassword123!' }; const response = await client.auth.login.$post({ json: loginData }); // 认证失败应该返回401 expect(response.status).toBe(401); if (response.status === 401){ const responseData = await response.json(); expect(responseData.message).toContain('用户名或密码错误'); } }); it('应该拒绝禁用账户的登录', async () => { // 创建禁用账户 const dataSource = await IntegrationTestDatabase.getDataSource(); if (!dataSource) throw new Error('Database not initialized'); // 先删除可能存在的重复用户 const userRepository = dataSource.getRepository(UserEntity); await userRepository.delete({ username: 'disabled_user' }); await TestDataFactory.createTestUser(dataSource, { username: 'disabled_user', password: 'TestPassword123!', email: 'disabled@example.com', isDisabled: DisabledStatus.DISABLED }); const loginData = { username: 'disabled_user', password: 'TestPassword123!' }; const response = await client.auth.login.$post({ json: loginData }); // 禁用账户应该返回401状态码 expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('账户已禁用'); } }); }); describe('令牌验证端点测试 (GET /api/v1/auth/sso-verify)', () => { it('应该成功验证有效令牌', async () => { const response = await client.auth['sso-verify'].$get( {}, { headers: { 'Authorization': `Bearer ${testToken}` } } ); expect(response.status).toBe(200); if (response.status === 200) { const responseText = await response.text(); expect(responseText).toBe('OK'); } }); it('应该拒绝无效令牌', async () => { const response = await client.auth['sso-verify'].$get( {}, { headers: { 'Authorization': 'Bearer invalid.token.here' } } ); expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('令牌验证失败'); } }); it('应该拒绝过期令牌', async () => { // 创建立即过期的令牌 const expiredToken = authService.generateToken(testUser, '1ms'); // 等待令牌过期 await new Promise(resolve => setTimeout(resolve, 10)); const response = await client.auth['sso-verify'].$get( {}, { headers: { 'Authorization': `Bearer ${expiredToken}` } } ); expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('令牌验证失败'); } }); }); describe('用户信息端点测试 (GET /api/v1/auth/me)', () => { it('应该成功获取用户信息', async () => { const response = await client.auth.me.$get( {}, { headers: { 'Authorization': `Bearer ${testToken}` } } ); expect(response.status).toBe(200); if (response.status === 200) { const responseData = await response.json(); expect(responseData).toHaveProperty('username'); expect(responseData).toHaveProperty('email'); expect(responseData.username).toBe('testuser'); expect(responseData.email).toBe('testuser@example.com'); } }); it('应该拒绝无令牌的用户信息请求', async () => { const response = await client.auth.me.$get(); expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('Authorization header missing'); } }); it('应该拒绝无效令牌的用户信息请求', async () => { const response = await client.auth.me.$get( {}, { headers: { 'Authorization': 'Bearer invalid.token.here' } } ); expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('Invalid token'); } }); }); describe('角色权限验证测试', () => { it('应该为不同角色的用户生成包含正确角色信息的令牌', async () => { const dataSource = await IntegrationTestDatabase.getDataSource(); if (!dataSource) throw new Error('Database not initialized'); // 创建管理员角色 const adminRole = await TestDataFactory.createTestRole(dataSource, { name: 'admin', permissions: ['user:create', 'user:delete', 'user:update'] }); // 创建普通用户角色 const userRole = await TestDataFactory.createTestRole(dataSource, { name: 'user', permissions: ['user:read'] }); // 创建管理员用户 const adminUser = await TestDataFactory.createTestUser(dataSource, { username: 'admin_user', password: 'TestPassword123!', email: 'admin@example.com' }); // 创建普通用户 const regularUser = await TestDataFactory.createTestUser(dataSource, { username: 'regular_user', password: 'TestPassword123!', email: 'regular@example.com' }); // 分配角色 await userService.assignRoles(adminUser.id, [adminRole.id]); await userService.assignRoles(regularUser.id, [userRole.id]); // 重新加载用户以确保角色信息正确加载 const adminUserWithRoles = await userService.getUserById(adminUser.id); const regularUserWithRoles = await userService.getUserById(regularUser.id); // 生成令牌并验证角色信息 const adminToken = authService.generateToken(adminUserWithRoles!); const regularToken = authService.generateToken(regularUserWithRoles!); // 验证管理员令牌包含admin角色 const adminDecoded = authService.verifyToken(adminToken); expect(adminDecoded.roles).toContain('admin'); // 验证普通用户令牌包含user角色 const regularDecoded = authService.verifyToken(regularToken); expect(regularDecoded.roles).toContain('user'); }); }); describe('错误处理测试', () => { it('应该正确处理认证失败错误', async () => { const loginData = { username: 'testuser', password: 'WrongPassword' }; const response = await client.auth.login.$post({ json: loginData }); expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData).toHaveProperty('code', 401); expect(responseData).toHaveProperty('message'); expect(responseData.message).toContain('用户名或密码错误'); } }); it('应该正确处理令牌过期错误', async () => { // 模拟过期令牌 const expiredToken = 'expired.jwt.token.here'; const response = await client.auth['sso-verify'].$get( {}, { headers: { 'Authorization': `Bearer ${expiredToken}` } } ); expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData).toHaveProperty('code', 401); expect(responseData.message).toContain('令牌验证失败'); } }); it('应该正确处理权限不足错误', async () => { // 创建普通用户(无管理员权限) const dataSource = await IntegrationTestDatabase.getDataSource(); if (!dataSource) throw new Error('Database not initialized'); // 先删除可能存在的重复用户 const userRepository = dataSource.getRepository(UserEntity); await userRepository.delete({ username: 'regular_user' }); const regularUser = await TestDataFactory.createTestUser(dataSource, { username: 'regular_user', password: 'TestPassword123!', email: 'regular@example.com' }); const regularToken = authService.generateToken(regularUser); // 尝试访问需要认证的端点(这里使用/me端点) const response = await client.auth.me.$get( {}, { headers: { 'Authorization': `Bearer ${regularToken}` } } ); // 普通用户应该能够访问自己的信息 expect(response.status).toBe(200); }); }); describe('性能基准测试', () => { it('登录操作响应时间应小于200ms', async () => { const loginData = { username: 'testuser', password: 'TestPassword123!' }; const startTime = Date.now(); const response = await client.auth.login.$post({ json: loginData }); const endTime = Date.now(); const responseTime = endTime - startTime; expect(response.status).toBe(200); expect(responseTime).toBeLessThan(200); // 响应时间应小于200ms }); it('令牌验证操作响应时间应小于200ms', async () => { const startTime = Date.now(); const response = await client.auth['sso-verify'].$get( {}, { headers: { 'Authorization': `Bearer ${testToken}` } } ); const endTime = Date.now(); const responseTime = endTime - startTime; expect(response.status).toBe(200); expect(responseTime).toBeLessThan(200); // 响应时间应小于200ms }); }); });