forked from datawhale/whale-town-end
docs(zulip): 完善Zulip业务模块功能文档
范围: src/business/zulip/README.md - 补充对外提供的接口章节(14个公共方法) - 添加使用的项目内部依赖说明(7个依赖) - 完善核心特性描述(5个特性) - 添加潜在风险评估(4个风险及缓解措施) - 优化文档结构和内容完整性
This commit is contained in:
@@ -7,27 +7,33 @@
|
||||
* - 测试真实的网络请求和响应处理
|
||||
*
|
||||
* 测试范围:
|
||||
* - WebSocket → ZulipService → ZulipClientPool → ZulipClient → Zulip API
|
||||
* - WebSocket → ChatService → ZulipClientPool → ZulipClient → Zulip API
|
||||
*
|
||||
* 更新记录:
|
||||
* - 2026-01-14: 重构后更新 - 使用新的四层架构模块
|
||||
* - ChatService 替代 ZulipService
|
||||
* - ChatSessionService 替代 SessionManagerService
|
||||
*
|
||||
* @author moyin
|
||||
* @version 1.0.0
|
||||
* @version 2.0.0
|
||||
* @since 2026-01-10
|
||||
* @lastModified 2026-01-14
|
||||
*/
|
||||
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { ZulipService } from '../../src/business/zulip/zulip.service';
|
||||
import { ChatService } from '../../src/business/chat/chat.service';
|
||||
import { ChatSessionService } from '../../src/business/chat/services/chat_session.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 chatService: ChatService;
|
||||
let zulipClientPool: ZulipClientPoolService;
|
||||
let zulipClient: ZulipClientService;
|
||||
let sessionManager: SessionManagerService;
|
||||
let sessionManager: ChatSessionService;
|
||||
|
||||
// 模拟的Zulip客户端
|
||||
let mockZulipSdkClient: any;
|
||||
@@ -48,11 +54,11 @@ describe('ChatMessage E2E Integration', () => {
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
|
||||
// 获取服务实例
|
||||
zulipService = moduleFixture.get<ZulipService>(ZulipService);
|
||||
// 获取服务实例(使用新的四层架构模块)
|
||||
chatService = moduleFixture.get<ChatService>(ChatService);
|
||||
zulipClientPool = moduleFixture.get<ZulipClientPoolService>(ZulipClientPoolService);
|
||||
zulipClient = moduleFixture.get<ZulipClientService>(ZulipClientService);
|
||||
sessionManager = moduleFixture.get<SessionManagerService>(SessionManagerService);
|
||||
sessionManager = moduleFixture.get<ChatSessionService>(ChatSessionService);
|
||||
|
||||
await app.init();
|
||||
});
|
||||
@@ -110,7 +116,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
describe('完整的聊天消息流程', () => {
|
||||
it('应该成功处理从登录到消息发送的完整流程', async () => {
|
||||
// 1. 模拟用户登录
|
||||
const loginResult = await zulipService.handlePlayerLogin({
|
||||
const loginResult = await chatService.handlePlayerLogin({
|
||||
socketId: testSocketId,
|
||||
token: 'valid-jwt-token', // 这里需要有效的JWT token
|
||||
});
|
||||
@@ -121,7 +127,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
expect(loginResult.sessionId).toBeDefined();
|
||||
|
||||
// 2. 发送聊天消息
|
||||
const chatResult = await zulipService.sendChatMessage({
|
||||
const chatResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'Hello from E2E test!',
|
||||
scope: 'local',
|
||||
@@ -153,7 +159,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
);
|
||||
|
||||
// 发送消息
|
||||
const chatResult = await zulipService.sendChatMessage({
|
||||
const chatResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'Hello from E2E test with mock session!',
|
||||
scope: 'local',
|
||||
@@ -175,7 +181,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
);
|
||||
|
||||
// 测试本地消息
|
||||
const localResult = await zulipService.sendChatMessage({
|
||||
const localResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'Local message test',
|
||||
scope: 'local',
|
||||
@@ -191,7 +197,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
expect(localCall[0].to).toBe('Whale Port'); // 应该路由到地图对应的Stream
|
||||
|
||||
// 测试全局消息
|
||||
const globalResult = await zulipService.sendChatMessage({
|
||||
const globalResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'Global message test',
|
||||
scope: 'global',
|
||||
@@ -218,7 +224,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
);
|
||||
|
||||
// 测试正常消息
|
||||
const normalResult = await zulipService.sendChatMessage({
|
||||
const normalResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'This is a normal message',
|
||||
scope: 'local',
|
||||
@@ -226,7 +232,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
expect(normalResult.success).toBe(true);
|
||||
|
||||
// 测试空消息
|
||||
const emptyResult = await zulipService.sendChatMessage({
|
||||
const emptyResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: '',
|
||||
scope: 'local',
|
||||
@@ -235,7 +241,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
|
||||
// 测试过长消息
|
||||
const longMessage = 'A'.repeat(2000); // 假设限制是1000字符
|
||||
const longResult = await zulipService.sendChatMessage({
|
||||
const longResult = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: longMessage,
|
||||
scope: 'local',
|
||||
@@ -262,7 +268,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
code: 'STREAM_NOT_FOUND',
|
||||
});
|
||||
|
||||
const result = await zulipService.sendChatMessage({
|
||||
const result = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'This message will fail',
|
||||
scope: 'local',
|
||||
@@ -286,7 +292,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
// 模拟网络异常
|
||||
mockZulipSdkClient.messages.send.mockRejectedValueOnce(new Error('Network timeout'));
|
||||
|
||||
const result = await zulipService.sendChatMessage({
|
||||
const result = await chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: 'This will timeout',
|
||||
scope: 'local',
|
||||
@@ -423,7 +429,7 @@ describe('ChatMessage E2E Integration', () => {
|
||||
|
||||
// 发送大量消息
|
||||
const promises = Array.from({ length: messageCount }, (_, i) =>
|
||||
zulipService.sendChatMessage({
|
||||
chatService.sendChatMessage({
|
||||
socketId: testSocketId,
|
||||
content: `Performance test message ${i}`,
|
||||
scope: 'local',
|
||||
@@ -445,4 +451,4 @@ describe('ChatMessage E2E Integration', () => {
|
||||
expect(avgTimePerMessage).toBeLessThan(100);
|
||||
}, 30000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,16 +12,23 @@
|
||||
* - 大量消息批量处理性能
|
||||
* - 内存使用和资源清理
|
||||
*
|
||||
* 更新记录:
|
||||
* - 2026-01-14: 重构后更新 - 使用新的四层架构模块
|
||||
* - ChatService 替代 ZulipService
|
||||
* - ChatSessionService 替代 SessionManagerService
|
||||
* - ChatFilterService 替代 MessageFilterService
|
||||
*
|
||||
* @author moyin
|
||||
* @version 1.0.0
|
||||
* @version 2.0.0
|
||||
* @since 2026-01-10
|
||||
* @lastModified 2026-01-14
|
||||
*/
|
||||
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ZulipService } from '../../../src/business/zulip/zulip.service';
|
||||
import { ChatService } from '../../../src/business/chat/chat.service';
|
||||
import { ChatSessionService } from '../../../src/business/chat/services/chat_session.service';
|
||||
import { ChatFilterService } from '../../../src/business/chat/services/chat_filter.service';
|
||||
import { ZulipClientPoolService } from '../../../src/core/zulip_core/services/zulip_client_pool.service';
|
||||
import { SessionManagerService } from '../../../src/business/zulip/services/session_manager.service';
|
||||
import { MessageFilterService } from '../../../src/business/zulip/services/message_filter.service';
|
||||
|
||||
// 模拟WebSocket网关
|
||||
class MockWebSocketGateway {
|
||||
@@ -45,8 +52,8 @@ class MockWebSocketGateway {
|
||||
}
|
||||
|
||||
describe('Zulip聊天性能测试', () => {
|
||||
let zulipService: ZulipService;
|
||||
let sessionManager: SessionManagerService;
|
||||
let chatService: ChatService;
|
||||
let sessionManager: ChatSessionService;
|
||||
let mockWebSocketGateway: MockWebSocketGateway;
|
||||
let mockZulipClientPool: any;
|
||||
|
||||
@@ -88,17 +95,17 @@ describe('Zulip聊天性能测试', () => {
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
ZulipService,
|
||||
ChatService,
|
||||
{
|
||||
provide: 'ZULIP_CLIENT_POOL_SERVICE',
|
||||
useValue: mockZulipClientPool,
|
||||
},
|
||||
{
|
||||
provide: SessionManagerService,
|
||||
provide: ChatSessionService,
|
||||
useValue: mockSessionManager,
|
||||
},
|
||||
{
|
||||
provide: MessageFilterService,
|
||||
provide: ChatFilterService,
|
||||
useValue: mockMessageFilter,
|
||||
},
|
||||
{
|
||||
@@ -123,12 +130,12 @@ describe('Zulip聊天性能测试', () => {
|
||||
],
|
||||
}).compile();
|
||||
|
||||
zulipService = module.get<ZulipService>(ZulipService);
|
||||
sessionManager = module.get<SessionManagerService>(SessionManagerService);
|
||||
chatService = module.get<ChatService>(ChatService);
|
||||
sessionManager = module.get<ChatSessionService>(ChatSessionService);
|
||||
|
||||
// 设置WebSocket网关
|
||||
mockWebSocketGateway = new MockWebSocketGateway();
|
||||
zulipService.setWebSocketGateway(mockWebSocketGateway as any);
|
||||
chatService.setWebSocketGateway(mockWebSocketGateway as any);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -140,7 +147,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
it('应该在50ms内完成游戏内广播', async () => {
|
||||
const startTime = Date.now();
|
||||
|
||||
const result = await zulipService.sendChatMessage({
|
||||
const result = await chatService.sendChatMessage({
|
||||
socketId: 'test-socket',
|
||||
content: 'Performance test message',
|
||||
scope: 'local',
|
||||
@@ -165,7 +172,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
const result = await zulipService.sendChatMessage({
|
||||
const result = await chatService.sendChatMessage({
|
||||
socketId: 'test-socket',
|
||||
content: 'Async test message',
|
||||
scope: 'local',
|
||||
@@ -186,7 +193,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
const startTime = Date.now();
|
||||
|
||||
const promises = Array.from({ length: messageCount }, (_, i) =>
|
||||
zulipService.sendChatMessage({
|
||||
chatService.sendChatMessage({
|
||||
socketId: `socket-${i}`,
|
||||
content: `Concurrent message ${i}`,
|
||||
scope: 'local',
|
||||
@@ -210,7 +217,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
}, 10000);
|
||||
|
||||
it('应该正确广播给地图内的所有玩家', async () => {
|
||||
await zulipService.sendChatMessage({
|
||||
await chatService.sendChatMessage({
|
||||
socketId: 'sender-socket',
|
||||
content: 'Broadcast test message',
|
||||
scope: 'local',
|
||||
@@ -234,7 +241,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
|
||||
// 创建批量消息
|
||||
const batchPromises = Array.from({ length: batchSize }, (_, i) =>
|
||||
zulipService.sendChatMessage({
|
||||
chatService.sendChatMessage({
|
||||
socketId: 'batch-socket',
|
||||
content: `Batch message ${i}`,
|
||||
scope: 'local',
|
||||
@@ -267,7 +274,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
|
||||
// 模拟会话创建
|
||||
for (const sessionId of sessionIds) {
|
||||
await zulipService.handlePlayerLogin({
|
||||
await chatService.handlePlayerLogin({
|
||||
socketId: sessionId,
|
||||
token: 'valid-jwt-token',
|
||||
});
|
||||
@@ -275,7 +282,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
|
||||
// 清理所有会话
|
||||
for (const sessionId of sessionIds) {
|
||||
await zulipService.handlePlayerLogout(sessionId);
|
||||
await chatService.handlePlayerLogout(sessionId);
|
||||
}
|
||||
|
||||
// 验证资源清理
|
||||
@@ -294,7 +301,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
|
||||
// 处理大量消息
|
||||
const promises = largeDataSet.map((item, i) =>
|
||||
zulipService.sendChatMessage({
|
||||
chatService.sendChatMessage({
|
||||
socketId: `memory-test-${i}`,
|
||||
content: `Memory test ${item.id}: ${item.data.substring(0, 50)}...`,
|
||||
scope: 'local',
|
||||
@@ -322,7 +329,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
it('应该快速处理无效会话', async () => {
|
||||
const startTime = Date.now();
|
||||
|
||||
const result = await zulipService.sendChatMessage({
|
||||
const result = await chatService.sendChatMessage({
|
||||
socketId: 'invalid-socket',
|
||||
content: 'This should fail quickly',
|
||||
scope: 'local',
|
||||
@@ -341,7 +348,7 @@ describe('Zulip聊天性能测试', () => {
|
||||
// 模拟Zulip服务异常
|
||||
mockZulipClientPool.sendMessage.mockRejectedValue(new Error('Zulip service unavailable'));
|
||||
|
||||
const result = await zulipService.sendChatMessage({
|
||||
const result = await chatService.sendChatMessage({
|
||||
socketId: 'test-socket',
|
||||
content: 'Message during Zulip outage',
|
||||
scope: 'local',
|
||||
@@ -355,4 +362,4 @@ describe('Zulip聊天性能测试', () => {
|
||||
expect(broadcastMessages).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user