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
This commit is contained in:
moyin
2026-01-10 19:27:28 +08:00
parent f4ce162a38
commit d04ab7f75f
40 changed files with 5766 additions and 3519 deletions

View File

@@ -0,0 +1,358 @@
/**
* Zulip聊天性能测试
*
* 功能描述:
* - 测试优化后聊天架构的性能表现
* - 验证游戏内实时广播 + Zulip异步同步的效果
* - 测试高并发场景下的系统稳定性
*
* 测试场景:
* - 单用户消息发送性能
* - 多用户并发聊天性能
* - 大量消息批量处理性能
* - 内存使用和资源清理
*
* @author moyin
* @version 1.0.0
* @since 2026-01-10
*/
import { Test, TestingModule } from '@nestjs/testing';
import { ZulipService } from '../../../src/business/zulip/zulip.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 {
private sentMessages: Array<{ socketId: string; data: any }> = [];
private broadcastMessages: Array<{ mapId: string; data: any }> = [];
sendToPlayer(socketId: string, data: any): void {
this.sentMessages.push({ socketId, data });
}
broadcastToMap(mapId: string, data: any, excludeId?: string): void {
this.broadcastMessages.push({ mapId, data });
}
getSentMessages() { return this.sentMessages; }
getBroadcastMessages() { return this.broadcastMessages; }
clearMessages() {
this.sentMessages = [];
this.broadcastMessages = [];
}
}
describe('Zulip聊天性能测试', () => {
let zulipService: ZulipService;
let sessionManager: SessionManagerService;
let mockWebSocketGateway: MockWebSocketGateway;
let mockZulipClientPool: any;
beforeAll(async () => {
// 创建模拟服务
mockZulipClientPool = {
sendMessage: jest.fn().mockResolvedValue({
success: true,
messageId: 'zulip-msg-123',
}),
createUserClient: jest.fn(),
destroyUserClient: jest.fn(),
};
const mockSessionManager = {
getSession: jest.fn().mockResolvedValue({
sessionId: 'test-session',
userId: 'user-123',
username: 'TestPlayer',
currentMap: 'whale_port',
position: { x: 100, y: 200 },
}),
injectContext: jest.fn().mockResolvedValue({
stream: 'Whale Port',
topic: 'Town Square Chat',
}),
getSocketsInMap: jest.fn().mockResolvedValue(['socket-1', 'socket-2', 'socket-3']),
createSession: jest.fn(),
destroySession: jest.fn(),
updatePlayerPosition: jest.fn().mockResolvedValue(true),
};
const mockMessageFilter = {
validateMessage: jest.fn().mockResolvedValue({
allowed: true,
filteredContent: null,
}),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
ZulipService,
{
provide: 'ZULIP_CLIENT_POOL_SERVICE',
useValue: mockZulipClientPool,
},
{
provide: SessionManagerService,
useValue: mockSessionManager,
},
{
provide: MessageFilterService,
useValue: mockMessageFilter,
},
{
provide: 'API_KEY_SECURITY_SERVICE',
useValue: {
getApiKey: jest.fn().mockResolvedValue({
success: true,
apiKey: 'test-api-key',
}),
},
},
{
provide: 'LoginCoreService',
useValue: {
verifyToken: jest.fn().mockResolvedValue({
sub: 'user-123',
username: 'TestPlayer',
email: 'test@example.com',
}),
},
},
],
}).compile();
zulipService = module.get<ZulipService>(ZulipService);
sessionManager = module.get<SessionManagerService>(SessionManagerService);
// 设置WebSocket网关
mockWebSocketGateway = new MockWebSocketGateway();
zulipService.setWebSocketGateway(mockWebSocketGateway as any);
});
beforeEach(() => {
jest.clearAllMocks();
mockWebSocketGateway.clearMessages();
});
describe('单用户消息发送性能', () => {
it('应该在50ms内完成游戏内广播', async () => {
const startTime = Date.now();
const result = await zulipService.sendChatMessage({
socketId: 'test-socket',
content: 'Performance test message',
scope: 'local',
});
const duration = Date.now() - startTime;
expect(result.success).toBe(true);
expect(duration).toBeLessThan(50); // 游戏内广播应该在50ms内完成
console.log(`游戏内广播耗时: ${duration}ms`);
});
it('应该异步处理Zulip同步不阻塞游戏聊天', async () => {
// 模拟Zulip同步延迟
mockZulipClientPool.sendMessage.mockImplementation(() =>
new Promise(resolve => setTimeout(() => resolve({
success: true,
messageId: 'delayed-msg',
}), 200))
);
const startTime = Date.now();
const result = await zulipService.sendChatMessage({
socketId: 'test-socket',
content: 'Async test message',
scope: 'local',
});
const duration = Date.now() - startTime;
expect(result.success).toBe(true);
expect(duration).toBeLessThan(100); // 不应该等待Zulip同步完成
console.log(`异步处理耗时: ${duration}ms`);
});
});
describe('多用户并发聊天性能', () => {
it('应该处理50个并发消息', async () => {
const messageCount = 50;
const startTime = Date.now();
const promises = Array.from({ length: messageCount }, (_, i) =>
zulipService.sendChatMessage({
socketId: `socket-${i}`,
content: `Concurrent message ${i}`,
scope: 'local',
})
);
const results = await Promise.all(promises);
const duration = Date.now() - startTime;
// 验证所有消息都成功处理
expect(results).toHaveLength(messageCount);
results.forEach(result => {
expect(result.success).toBe(true);
});
const avgTimePerMessage = duration / messageCount;
console.log(`处理${messageCount}条并发消息耗时: ${duration}ms, 平均每条: ${avgTimePerMessage.toFixed(2)}ms`);
// 期望平均每条消息处理时间不超过20ms
expect(avgTimePerMessage).toBeLessThan(20);
}, 10000);
it('应该正确广播给地图内的所有玩家', async () => {
await zulipService.sendChatMessage({
socketId: 'sender-socket',
content: 'Broadcast test message',
scope: 'local',
});
// 验证广播消息
const broadcastMessages = mockWebSocketGateway.getBroadcastMessages();
expect(broadcastMessages).toHaveLength(1);
const broadcastMessage = broadcastMessages[0];
expect(broadcastMessage.mapId).toBe('whale_port');
expect(broadcastMessage.data.t).toBe('chat_render');
expect(broadcastMessage.data.txt).toBe('Broadcast test message');
});
});
describe('批量消息处理性能', () => {
it('应该高效处理大量消息', async () => {
const batchSize = 100;
const startTime = Date.now();
// 创建批量消息
const batchPromises = Array.from({ length: batchSize }, (_, i) =>
zulipService.sendChatMessage({
socketId: 'batch-socket',
content: `Batch message ${i}`,
scope: 'local',
})
);
const results = await Promise.all(batchPromises);
const duration = Date.now() - startTime;
// 验证处理结果
expect(results).toHaveLength(batchSize);
results.forEach((result, index) => {
expect(result.success).toBe(true);
expect(result.messageId).toBeDefined();
});
const throughput = (batchSize / duration) * 1000; // 每秒处理的消息数
console.log(`批量处理${batchSize}条消息耗时: ${duration}ms, 吞吐量: ${throughput.toFixed(2)} msg/s`);
// 期望吞吐量至少达到500 msg/s
expect(throughput).toBeGreaterThan(500);
}, 15000);
});
describe('内存使用和资源清理', () => {
it('应该正确清理会话资源', async () => {
// 创建多个会话
const sessionCount = 10;
const sessionIds = Array.from({ length: sessionCount }, (_, i) => `session-${i}`);
// 模拟会话创建
for (const sessionId of sessionIds) {
await zulipService.handlePlayerLogin({
socketId: sessionId,
token: 'valid-jwt-token',
});
}
// 清理所有会话
for (const sessionId of sessionIds) {
await zulipService.handlePlayerLogout(sessionId);
}
// 验证资源清理
expect(mockZulipClientPool.destroyUserClient).toHaveBeenCalledTimes(sessionCount);
});
it('应该处理内存压力测试', async () => {
const initialMemory = process.memoryUsage();
// 创建大量临时对象
const largeDataSet = Array.from({ length: 1000 }, (_, i) => ({
id: i,
data: 'x'.repeat(1000), // 1KB per object
timestamp: new Date(),
}));
// 处理大量消息
const promises = largeDataSet.map((item, i) =>
zulipService.sendChatMessage({
socketId: `memory-test-${i}`,
content: `Memory test ${item.id}: ${item.data.substring(0, 50)}...`,
scope: 'local',
})
);
await Promise.all(promises);
// 强制垃圾回收(如果可用)
if (global.gc) {
global.gc();
}
const finalMemory = process.memoryUsage();
const memoryIncrease = finalMemory.heapUsed - initialMemory.heapUsed;
console.log(`内存使用增加: ${(memoryIncrease / 1024 / 1024).toFixed(2)} MB`);
// 期望内存增加不超过50MB
expect(memoryIncrease).toBeLessThan(50 * 1024 * 1024);
}, 20000);
});
describe('错误处理性能', () => {
it('应该快速处理无效会话', async () => {
const startTime = Date.now();
const result = await zulipService.sendChatMessage({
socketId: 'invalid-socket',
content: 'This should fail quickly',
scope: 'local',
});
const duration = Date.now() - startTime;
expect(result.success).toBe(false);
expect(result.error).toContain('会话不存在');
expect(duration).toBeLessThan(10); // 错误处理应该很快
console.log(`错误处理耗时: ${duration}ms`);
});
it('应该处理Zulip服务异常而不影响游戏聊天', async () => {
// 模拟Zulip服务异常
mockZulipClientPool.sendMessage.mockRejectedValue(new Error('Zulip service unavailable'));
const result = await zulipService.sendChatMessage({
socketId: 'test-socket',
content: 'Message during Zulip outage',
scope: 'local',
});
// 游戏内聊天应该仍然成功
expect(result.success).toBe(true);
// 验证游戏内广播仍然工作
const broadcastMessages = mockWebSocketGateway.getBroadcastMessages();
expect(broadcastMessages).toHaveLength(1);
});
});
});