| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- import { describe, test, expect, beforeAll, afterAll, vi } from 'vitest'
- import { testClient } from 'hono/testing'
- import { agoraApiRoutes } from '@/server/api'
- import { AgoraTokenService } from '@/server/modules/agora/agora-token.service'
- import { authMiddleware } from '@/server/middleware/auth.middleware'
- // 模拟模块
- vi.mock('@/server/modules/agora/agora-token.service', () => ({
- AgoraTokenService: vi.fn().mockImplementation(() => ({
- generateRtcToken: vi.fn().mockReturnValue('mock-rtc-token'),
- generateRtmToken: vi.fn().mockReturnValue('mock-rtm-token'),
- validateTokenParams: vi.fn(),
- getTokenInfo: vi.fn().mockImplementation((token, type) => ({
- token,
- type,
- expiresAt: Math.floor(Date.now() / 1000) + 3600,
- expiresIn: 3600,
- generatedAt: Math.floor(Date.now() / 1000)
- }))
- }))
- }));
- vi.mock('@/server/middleware/auth.middleware');
- // Mock用户数据
- const mockUser = {
- id: 1,
- username: 'testuser',
- password: 'password123',
- phone: null,
- email: 'test@example.com',
- nickname: null,
- name: null,
- avatarFileId: null,
- avatarFile: null,
- isDisabled: 0,
- isDeleted: 0,
- roles: [],
- createdAt: new Date(),
- updatedAt: new Date()
- }
- describe('Agora Token API 集成测试', () => {
- let client: ReturnType<typeof testClient<typeof agoraApiRoutes>>['api']['v1']
- beforeAll(() => {
- // 设置测试环境变量
- process.env.AGORA_APP_ID = 'test-app-id'
- process.env.AGORA_APP_SECRET = 'test-app-secret'
- process.env.AGORA_TOKEN_EXPIRY = '3600'
- // Mock auth middleware
- vi.mocked(authMiddleware).mockImplementation(async (c, next) => {
- const authHeader = c.req.header('Authorization')
- if (!authHeader) {
- return c.json({ message: 'Authorization header missing' }, 401)
- }
- c.set('user', mockUser)
- await next()
- })
- // 创建测试客户端
- client = testClient(agoraApiRoutes).api.v1
- })
- afterAll(() => {
- vi.clearAllMocks()
- })
- test('AgoraTokenService参数验证功能', () => {
- const agoraTokenService = new AgoraTokenService()
- // 测试RTC Token参数验证
- expect(() => {
- agoraTokenService.validateTokenParams('rtc', 'test-channel')
- }).not.toThrow()
- // 测试RTC Token缺少channel参数
- expect(() => {
- agoraTokenService.validateTokenParams('rtc')
- }).toThrow('RTC Token需要提供channel参数')
- // 测试RTM Token参数验证
- expect(() => {
- agoraTokenService.validateTokenParams('rtm', undefined, 'test-user')
- }).not.toThrow()
- // 测试RTM Token缺少userId参数
- expect(() => {
- agoraTokenService.validateTokenParams('rtm')
- }).toThrow('RTM Token需要提供userId参数')
- // 测试频道名称长度限制
- expect(() => {
- agoraTokenService.validateTokenParams('rtc', 'a'.repeat(65))
- }).toThrow('频道名称长度不能超过64个字符')
- // 测试用户ID长度限制
- expect(() => {
- agoraTokenService.validateTokenParams('rtm', undefined, 'a'.repeat(65))
- }).toThrow('用户ID长度不能超过64个字符')
- })
- test('AgoraTokenService Token生成功能', () => {
- const agoraTokenService = new AgoraTokenService()
- // 测试RTC Token生成
- const rtcToken = agoraTokenService.generateRtcToken('test-channel', '123')
- expect(rtcToken).toBe('mock-rtc-token')
- // 测试RTM Token生成
- const rtmToken = agoraTokenService.generateRtmToken('test-user')
- expect(rtmToken).toBe('mock-rtm-token')
- // 测试Token信息获取
- const tokenInfo = agoraTokenService.getTokenInfo('test-token', 'rtc')
- expect(tokenInfo).toEqual({
- token: 'test-token',
- type: 'rtc',
- expiresAt: expect.any(Number),
- expiresIn: 3600,
- generatedAt: expect.any(Number)
- })
- })
- test('未认证用户访问Token API应该返回401', async () => {
- // 临时修改mock以模拟未认证
- vi.mocked(authMiddleware).mockImplementation(async (c) => {
- return c.json({ message: 'Authorization header missing' }, 401)
- })
- const response = await client.agora.token.$get({
- query: { type: 'rtc', channel: 'test-channel' }
- })
- expect(response.status).toBe(401)
- // 恢复mock
- vi.mocked(authMiddleware).mockImplementation(async (c, next) => {
- const authHeader = c.req.header('Authorization')
- if (!authHeader) {
- return c.json({ message: 'Authorization header missing' }, 401)
- }
- c.set('user', mockUser)
- await next()
- })
- })
- test('认证用户生成RTC Token成功', async () => {
- const response = await client.agora.token.$get({
- query: { type: 'rtc', channel: 'test-channel' }
- },
- {
- headers: {
- 'Authorization': 'Bearer test-token'
- }
- })
- expect(response.status).toBe(200)
- const data = await response.json()
- if ('token' in data) {
- expect(data.token).toBe('mock-rtc-token')
- expect(data.type).toBe('rtc')
- expect(data.expiresIn).toBe(3600)
- expect(data.expiresAt).toBeGreaterThan(Math.floor(Date.now() / 1000))
- }
- })
- test('认证用户生成RTM Token成功', async () => {
- const response = await client.agora.token.$get({
- query: { type: 'rtm', userId: 'test-user-123' }
- },
- {
- headers: {
- 'Authorization': 'Bearer test-token'
- }
- })
- expect(response.status).toBe(200)
- const data = await response.json()
- if ('token' in data) {
- expect(data.token).toBe('mock-rtm-token')
- expect(data.type).toBe('rtm')
- expect(data.expiresIn).toBe(3600)
- }
- })
- test('路由参数验证 - 无效Token类型', async () => {
- // 使用无效的type参数
- const response = await client.agora.token.$get({
- query: { type: 'rtc' as any, channel: 'test-channel' }
- },
- {
- headers: {
- 'Authorization': 'Bearer test-token'
- }
- })
- // 由于Zod验证,应该返回400错误
- expect(response.status).toBe(400)
- })
- test('路由参数验证 - 缺少必需参数', async () => {
- // 测试缺少channel参数
- const response1 = await client.agora.token.$get({
- query: { type: 'rtc' } // 缺少channel参数
- },
- {
- headers: {
- 'Authorization': 'Bearer test-token'
- }
- })
- // 由于Zod验证,应该返回400错误
- expect(response1.status).toBe(400)
- // 测试缺少userId参数
- const response2 = await client.agora.token.$get({
- query: { type: 'rtm' } // 缺少userId参数
- },
- {
- headers: {
- 'Authorization': 'Bearer test-token'
- }
- })
- // 由于Zod验证,应该返回400错误
- expect(response2.status).toBe(400)
- })
- test('Token有效期和格式验证', async () => {
- const response = await client.agora.token.$get({
- query: { type: 'rtc', channel: 'test-channel' }
- },
- {
- headers: {
- 'Authorization': 'Bearer test-token'
- }
- })
- expect(response.status).toBe(200)
- const data = await response.json()
- if ('token' in data) {
- // 验证Token信息格式
- expect(data).toHaveProperty('token')
- expect(data).toHaveProperty('type')
- expect(data).toHaveProperty('expiresAt')
- expect(data).toHaveProperty('expiresIn')
- expect(data).toHaveProperty('generatedAt')
- // 验证时间戳格式
- expect(data.expiresAt).toBeGreaterThan(data.generatedAt)
- expect(data.expiresIn).toBe(3600)
- expect(data.expiresAt - data.generatedAt).toBe(data.expiresIn)
- }
- })
- })
|