Files
whale-town-end/test/zulip_integration/chat_message_e2e.spec.ts
moyin d04ab7f75f CRITICAL ISSUES: Database management service with major problems
WARNING: This commit contains code with significant issues that need immediate attention:

1. Type Safety Issues:
   - Unused import ZulipAccountsService causing compilation warnings
   - Implicit 'any' type in formatZulipAccount method parameter
   - Type inconsistencies in service injections

2. Service Integration Problems:
   - Inconsistent service interface usage
   - Missing proper type definitions for injected services
   - Potential runtime errors due to type mismatches

3. Code Quality Issues:
   - Violation of TypeScript strict mode requirements
   - Inconsistent error handling patterns
   - Missing proper interface implementations

 Files affected:
   - src/business/admin/database_management.service.ts (main issue)
   - Multiple test files and service implementations
   - Configuration and documentation updates

 Next steps required:
   1. Fix TypeScript compilation errors
   2. Implement proper type safety
   3. Resolve service injection inconsistencies
   4. Add comprehensive error handling
   5. Update tests to match new implementations

 Impact: High - affects admin functionality and system stability
 Priority: Urgent - requires immediate review and fixes

Author: moyin
Date: 2026-01-10
2026-01-10 19:27:28 +08:00

448 lines
13 KiB
TypeScript
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.
/**
* 聊天消息端到端集成测试
*
* 功能描述:
* - 测试从WebSocket接收消息到Zulip服务器发送的完整流程
* - 验证消息路由、过滤、认证等中间环节
* - 测试真实的网络请求和响应处理
*
* 测试范围:
* - WebSocket → ZulipService → ZulipClientPool → ZulipClient → Zulip API
*
* @author moyin
* @version 1.0.0
* @since 2026-01-10
*/
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { ZulipService } from '../../src/business/zulip/zulip.service';
import { ZulipClientPoolService } from '../../src/core/zulip_core/services/zulip_client_pool.service';
import { ZulipClientService, ZulipClientInstance } from '../../src/core/zulip_core/services/zulip_client.service';
import { SessionManagerService } from '../../src/business/zulip/services/session_manager.service';
import { AppModule } from '../../src/app.module';
describe('ChatMessage E2E Integration', () => {
let app: INestApplication;
let zulipService: ZulipService;
let zulipClientPool: ZulipClientPoolService;
let zulipClient: ZulipClientService;
let sessionManager: SessionManagerService;
// 模拟的Zulip客户端
let mockZulipSdkClient: any;
// 测试数据
const testUserId = 'test-user-12345';
const testSocketId = 'ws_test_socket_123';
const testConfig = {
username: 'test-bot@example.com',
apiKey: 'test-api-key-abcdef',
realm: 'https://test-zulip.example.com',
};
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
// 获取服务实例
zulipService = moduleFixture.get<ZulipService>(ZulipService);
zulipClientPool = moduleFixture.get<ZulipClientPoolService>(ZulipClientPoolService);
zulipClient = moduleFixture.get<ZulipClientService>(ZulipClientService);
sessionManager = moduleFixture.get<SessionManagerService>(SessionManagerService);
await app.init();
});
afterAll(async () => {
await app.close();
});
beforeEach(() => {
// 创建模拟的zulip-js客户端
mockZulipSdkClient = {
config: testConfig,
users: {
me: {
getProfile: jest.fn().mockResolvedValue({
result: 'success',
email: testConfig.username,
full_name: 'Test Bot',
user_id: 123,
}),
},
},
messages: {
send: jest.fn().mockResolvedValue({
result: 'success',
id: 12345,
}),
},
queues: {
register: jest.fn().mockResolvedValue({
result: 'success',
queue_id: 'test-queue-123',
last_event_id: 0,
}),
deregister: jest.fn().mockResolvedValue({
result: 'success',
}),
},
events: {
retrieve: jest.fn().mockResolvedValue({
result: 'success',
events: [],
}),
},
};
// Mock zulip-js模块
jest.spyOn(zulipClient as any, 'loadZulipModule').mockResolvedValue(() => mockZulipSdkClient);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('完整的聊天消息流程', () => {
it('应该成功处理从登录到消息发送的完整流程', async () => {
// 1. 模拟用户登录
const loginResult = await zulipService.handlePlayerLogin({
socketId: testSocketId,
token: 'valid-jwt-token', // 这里需要有效的JWT token
});
// 验证登录成功可能需要根据实际JWT验证逻辑调整
if (loginResult.success) {
expect(loginResult.userId).toBeDefined();
expect(loginResult.sessionId).toBeDefined();
// 2. 发送聊天消息
const chatResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'Hello from E2E test!',
scope: 'local',
});
// 验证消息发送成功
expect(chatResult.success).toBe(true);
expect(chatResult.messageId).toBeDefined();
// 验证Zulip API被正确调用
expect(mockZulipSdkClient.messages.send).toHaveBeenCalledWith({
type: 'stream',
to: expect.any(String), // Stream名称
subject: expect.any(String), // Topic名称
content: 'Hello from E2E test!',
});
} else {
// 如果登录失败,跳过测试或使用模拟会话
console.warn('登录失败,使用模拟会话进行测试');
// 创建模拟会话
await sessionManager.createSession(
testSocketId,
testUserId,
'test-queue-123',
'TestUser',
'whale_port',
{ x: 0, y: 0 }
);
// 发送消息
const chatResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'Hello from E2E test with mock session!',
scope: 'local',
});
expect(chatResult.success).toBe(true);
}
}, 15000);
it('应该正确处理不同消息范围的路由', async () => {
// 创建测试会话
await sessionManager.createSession(
testSocketId,
testUserId,
'test-queue-123',
'TestUser',
'whale_port',
{ x: 0, y: 0 }
);
// 测试本地消息
const localResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'Local message test',
scope: 'local',
});
expect(localResult.success).toBe(true);
// 验证消息被发送到正确的Stream
const localCall = mockZulipSdkClient.messages.send.mock.calls.find(
(call: any) => call[0].content === 'Local message test'
);
expect(localCall).toBeDefined();
expect(localCall[0].to).toBe('Whale Port'); // 应该路由到地图对应的Stream
// 测试全局消息
const globalResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'Global message test',
scope: 'global',
});
expect(globalResult.success).toBe(true);
// 验证全局消息路由
const globalCall = mockZulipSdkClient.messages.send.mock.calls.find(
(call: any) => call[0].content === 'Global message test'
);
expect(globalCall).toBeDefined();
});
it('应该处理消息过滤和验证', async () => {
// 创建测试会话
await sessionManager.createSession(
testSocketId,
testUserId,
'test-queue-123',
'TestUser',
'whale_port',
{ x: 0, y: 0 }
);
// 测试正常消息
const normalResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'This is a normal message',
scope: 'local',
});
expect(normalResult.success).toBe(true);
// 测试空消息
const emptyResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: '',
scope: 'local',
});
expect(emptyResult.success).toBe(false);
// 测试过长消息
const longMessage = 'A'.repeat(2000); // 假设限制是1000字符
const longResult = await zulipService.sendChatMessage({
socketId: testSocketId,
content: longMessage,
scope: 'local',
});
// 根据实际过滤规则验证结果
console.log('Long message result:', longResult);
});
it('应该处理Zulip API错误', async () => {
// 创建测试会话
await sessionManager.createSession(
testSocketId,
testUserId,
'test-queue-123',
'TestUser',
'whale_port',
{ x: 0, y: 0 }
);
// 模拟Zulip API错误
mockZulipSdkClient.messages.send.mockResolvedValueOnce({
result: 'error',
msg: 'Stream does not exist',
code: 'STREAM_NOT_FOUND',
});
const result = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'This message will fail',
scope: 'local',
});
// 验证错误处理(根据实际业务逻辑,可能返回成功但记录错误)
expect(result).toBeDefined();
});
it('应该处理网络异常', async () => {
// 创建测试会话
await sessionManager.createSession(
testSocketId,
testUserId,
'test-queue-123',
'TestUser',
'whale_port',
{ x: 0, y: 0 }
);
// 模拟网络异常
mockZulipSdkClient.messages.send.mockRejectedValueOnce(new Error('Network timeout'));
const result = await zulipService.sendChatMessage({
socketId: testSocketId,
content: 'This will timeout',
scope: 'local',
});
// 验证网络异常处理
expect(result).toBeDefined();
});
});
describe('客户端池管理', () => {
it('应该正确管理用户的Zulip客户端', async () => {
// 创建用户客户端
const clientInstance = await zulipClientPool.createUserClient(testUserId, testConfig);
expect(clientInstance).toBeDefined();
expect(clientInstance.userId).toBe(testUserId);
expect(clientInstance.isValid).toBe(true);
// 验证客户端可以发送消息
const sendResult = await zulipClientPool.sendMessage(
testUserId,
'test-stream',
'test-topic',
'Test message from pool'
);
expect(sendResult.success).toBe(true);
expect(mockZulipSdkClient.messages.send).toHaveBeenCalledWith({
type: 'stream',
to: 'test-stream',
subject: 'test-topic',
content: 'Test message from pool',
});
// 清理客户端
await zulipClientPool.destroyUserClient(testUserId);
});
it('应该处理多用户并发', async () => {
const userIds = ['user1', 'user2', 'user3'];
const clients: ZulipClientInstance[] = [];
// 创建多个用户客户端
for (const userId of userIds) {
const client = await zulipClientPool.createUserClient(userId, {
...testConfig,
username: `${userId}@example.com`,
});
clients.push(client);
}
// 并发发送消息
const sendPromises = userIds.map(userId =>
zulipClientPool.sendMessage(
userId,
'concurrent-stream',
'concurrent-topic',
`Message from ${userId}`
)
);
const results = await Promise.all(sendPromises);
// 验证所有消息都成功发送
results.forEach(result => {
expect(result.success).toBe(true);
});
// 清理所有客户端
for (const userId of userIds) {
await zulipClientPool.destroyUserClient(userId);
}
});
});
describe('事件队列集成', () => {
it('应该正确处理事件队列生命周期', async () => {
// 创建客户端
const clientInstance = await zulipClientPool.createUserClient(testUserId, testConfig);
// 验证队列已注册
expect(clientInstance.queueId).toBeDefined();
expect(mockZulipSdkClient.queues.register).toHaveBeenCalled();
// 模拟接收事件
const mockEvents = [
{
id: 1,
type: 'message',
message: {
id: 98765,
sender_email: 'other-user@example.com',
content: 'Hello from other user',
stream_id: 1,
subject: 'Test Topic',
},
},
];
mockZulipSdkClient.events.retrieve.mockResolvedValueOnce({
result: 'success',
events: mockEvents,
});
// 获取事件
const userClient: ZulipClientInstance | null = await zulipClientPool.getUserClient(testUserId);
if (userClient) {
const eventsResult = await zulipClient.getEvents(userClient, true);
expect(eventsResult.success).toBe(true);
expect(eventsResult.events).toEqual(mockEvents);
}
// 清理
await zulipClientPool.destroyUserClient(testUserId);
expect(mockZulipSdkClient.queues.deregister).toHaveBeenCalled();
});
});
describe('性能测试', () => {
it('应该在高负载下保持性能', async () => {
const messageCount = 50;
const startTime = Date.now();
// 创建测试会话
await sessionManager.createSession(
testSocketId,
testUserId,
'test-queue-123',
'TestUser',
'whale_port',
{ x: 0, y: 0 }
);
// 发送大量消息
const promises = Array.from({ length: messageCount }, (_, i) =>
zulipService.sendChatMessage({
socketId: testSocketId,
content: `Performance test message ${i}`,
scope: 'local',
})
);
const results = await Promise.all(promises);
const endTime = Date.now();
const duration = endTime - startTime;
// 验证所有消息处理完成
expect(results).toHaveLength(messageCount);
// 性能检查
const avgTimePerMessage = duration / messageCount;
console.log(`处理${messageCount}条消息耗时: ${duration}ms, 平均每条: ${avgTimePerMessage.toFixed(2)}ms`);
// 期望平均每条消息处理时间不超过100ms
expect(avgTimePerMessage).toBeLessThan(100);
}, 30000);
});
});