refactor: 更新WebSocket相关测试和location_broadcast模块
- 更新location_broadcast网关以支持原生WebSocket - 修改WebSocket认证守卫和中间件 - 更新相关的测试文件和规范 - 添加WebSocket测试工具 - 完善Zulip服务的测试覆盖 技术改进: - 统一WebSocket实现架构 - 优化性能监控和限流中间件 - 更新测试用例以适配新的WebSocket实现
This commit is contained in:
@@ -25,7 +25,7 @@ import {
|
||||
CleanupResult
|
||||
} from './session_cleanup.service';
|
||||
import { SessionManagerService } from './session_manager.service';
|
||||
import { IZulipClientPoolService } from '../../../core/zulip_core/interfaces/zulip_core.interfaces';
|
||||
import { IZulipClientPoolService } from '../../../core/zulip_core/zulip_core.interfaces';
|
||||
|
||||
describe('SessionCleanupService', () => {
|
||||
let service: SessionCleanupService;
|
||||
@@ -43,8 +43,9 @@ describe('SessionCleanupService', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
// Only use fake timers for tests that need them
|
||||
// The concurrent test will use real timers for proper Promise handling
|
||||
jest.clearAllTimers();
|
||||
// 确保每个测试开始时都使用真实定时器
|
||||
jest.useRealTimers();
|
||||
|
||||
mockSessionManager = {
|
||||
cleanupExpiredSessions: jest.fn(),
|
||||
@@ -85,12 +86,18 @@ describe('SessionCleanupService', () => {
|
||||
service = module.get<SessionCleanupService>(SessionCleanupService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
afterEach(async () => {
|
||||
// 确保停止所有清理任务
|
||||
service.stopCleanupTask();
|
||||
// Only restore timers if they were faked
|
||||
if (jest.isMockFunction(setTimeout)) {
|
||||
jest.useRealTimers();
|
||||
}
|
||||
|
||||
// 等待任何正在进行的异步操作完成
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
|
||||
// 清理定时器
|
||||
jest.clearAllTimers();
|
||||
|
||||
// 恢复真实定时器
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
@@ -127,6 +134,8 @@ describe('SessionCleanupService', () => {
|
||||
|
||||
expect(mockSessionManager.cleanupExpiredSessions).toHaveBeenCalledWith(30);
|
||||
|
||||
// 确保清理任务被停止
|
||||
service.stopCleanupTask();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
@@ -294,46 +303,49 @@ describe('SessionCleanupService', () => {
|
||||
it('对于任何有效的清理配置,系统应该按配置间隔执行清理', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
// 生成有效的清理间隔(1-10分钟)
|
||||
fc.integer({ min: 1, max: 10 }).map(minutes => minutes * 60 * 1000),
|
||||
// 生成有效的会话超时时间(10-120分钟)
|
||||
fc.integer({ min: 10, max: 120 }),
|
||||
// 生成有效的清理间隔(1-5分钟,减少范围)
|
||||
fc.integer({ min: 1, max: 5 }).map(minutes => minutes * 60 * 1000),
|
||||
// 生成有效的会话超时时间(10-60分钟,减少范围)
|
||||
fc.integer({ min: 10, max: 60 }),
|
||||
async (intervalMs, sessionTimeoutMinutes) => {
|
||||
// 重置mock以确保每次测试都是干净的状态
|
||||
jest.clearAllMocks();
|
||||
jest.useFakeTimers();
|
||||
|
||||
const config: Partial<CleanupConfig> = {
|
||||
intervalMs,
|
||||
sessionTimeoutMinutes,
|
||||
enabled: true,
|
||||
};
|
||||
try {
|
||||
const config: Partial<CleanupConfig> = {
|
||||
intervalMs,
|
||||
sessionTimeoutMinutes,
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
// 模拟清理结果
|
||||
mockSessionManager.cleanupExpiredSessions.mockResolvedValue(
|
||||
createMockCleanupResult({ cleanedCount: 2 })
|
||||
);
|
||||
// 模拟清理结果
|
||||
mockSessionManager.cleanupExpiredSessions.mockResolvedValue(
|
||||
createMockCleanupResult({ cleanedCount: 2 })
|
||||
);
|
||||
|
||||
service.updateConfig(config);
|
||||
service.startCleanupTask();
|
||||
service.updateConfig(config);
|
||||
service.startCleanupTask();
|
||||
|
||||
// 验证配置被正确设置
|
||||
const status = service.getStatus();
|
||||
expect(status.config.intervalMs).toBe(intervalMs);
|
||||
expect(status.config.sessionTimeoutMinutes).toBe(sessionTimeoutMinutes);
|
||||
expect(status.isEnabled).toBe(true);
|
||||
// 验证配置被正确设置
|
||||
const status = service.getStatus();
|
||||
expect(status.config.intervalMs).toBe(intervalMs);
|
||||
expect(status.config.sessionTimeoutMinutes).toBe(sessionTimeoutMinutes);
|
||||
expect(status.isEnabled).toBe(true);
|
||||
|
||||
// 验证立即执行了一次清理
|
||||
await jest.runOnlyPendingTimersAsync();
|
||||
expect(mockSessionManager.cleanupExpiredSessions).toHaveBeenCalledWith(sessionTimeoutMinutes);
|
||||
// 验证立即执行了一次清理
|
||||
await jest.runOnlyPendingTimersAsync();
|
||||
expect(mockSessionManager.cleanupExpiredSessions).toHaveBeenCalledWith(sessionTimeoutMinutes);
|
||||
|
||||
service.stopCleanupTask();
|
||||
jest.useRealTimers();
|
||||
} finally {
|
||||
service.stopCleanupTask();
|
||||
jest.useRealTimers();
|
||||
}
|
||||
}
|
||||
),
|
||||
{ numRuns: 50 }
|
||||
{ numRuns: 20, timeout: 5000 } // 减少运行次数并添加超时
|
||||
);
|
||||
}, 30000);
|
||||
}, 15000);
|
||||
|
||||
/**
|
||||
* 属性: 对于任何清理操作,都应该记录清理结果和统计信息
|
||||
@@ -343,11 +355,11 @@ describe('SessionCleanupService', () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
// 生成清理的会话数量
|
||||
fc.integer({ min: 0, max: 20 }),
|
||||
fc.integer({ min: 0, max: 10 }),
|
||||
// 生成Zulip队列ID列表
|
||||
fc.array(
|
||||
fc.string({ minLength: 5, maxLength: 20 }).filter(s => s.trim().length > 0),
|
||||
{ minLength: 0, maxLength: 20 }
|
||||
fc.string({ minLength: 5, maxLength: 15 }).filter(s => s.trim().length > 0),
|
||||
{ minLength: 0, maxLength: 10 }
|
||||
),
|
||||
async (cleanedCount, queueIds) => {
|
||||
// 重置mock以确保每次测试都是干净的状态
|
||||
@@ -375,9 +387,9 @@ describe('SessionCleanupService', () => {
|
||||
expect(lastResult!.cleanedSessions).toBe(cleanedCount);
|
||||
}
|
||||
),
|
||||
{ numRuns: 50 }
|
||||
{ numRuns: 20, timeout: 3000 } // 减少运行次数并添加超时
|
||||
);
|
||||
}, 30000);
|
||||
}, 10000);
|
||||
|
||||
/**
|
||||
* 属性: 清理过程中发生错误时,系统应该正确处理并记录错误信息
|
||||
@@ -387,7 +399,7 @@ describe('SessionCleanupService', () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
// 生成各种错误消息
|
||||
fc.string({ minLength: 5, maxLength: 100 }).filter(s => s.trim().length > 0),
|
||||
fc.string({ minLength: 5, maxLength: 50 }).filter(s => s.trim().length > 0),
|
||||
async (errorMessage) => {
|
||||
// 重置mock以确保每次测试都是干净的状态
|
||||
jest.clearAllMocks();
|
||||
@@ -411,9 +423,9 @@ describe('SessionCleanupService', () => {
|
||||
expect(lastResult!.error).toBe(errorMessage.trim());
|
||||
}
|
||||
),
|
||||
{ numRuns: 50 }
|
||||
{ numRuns: 20, timeout: 3000 } // 减少运行次数并添加超时
|
||||
);
|
||||
}, 30000);
|
||||
}, 10000);
|
||||
|
||||
/**
|
||||
* 属性: 并发清理请求应该被正确处理,避免重复执行
|
||||
@@ -475,11 +487,11 @@ describe('SessionCleanupService', () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
// 生成过期会话数量
|
||||
fc.integer({ min: 1, max: 10 }),
|
||||
fc.integer({ min: 1, max: 5 }),
|
||||
// 生成每个会话对应的Zulip队列ID
|
||||
fc.array(
|
||||
fc.string({ minLength: 8, maxLength: 20 }).filter(s => s.trim().length > 0),
|
||||
{ minLength: 1, maxLength: 10 }
|
||||
fc.string({ minLength: 8, maxLength: 15 }).filter(s => s.trim().length > 0),
|
||||
{ minLength: 1, maxLength: 5 }
|
||||
),
|
||||
async (sessionCount, queueIds) => {
|
||||
// 重置mock以确保每次测试都是干净的状态
|
||||
@@ -506,9 +518,9 @@ describe('SessionCleanupService', () => {
|
||||
expect(mockSessionManager.cleanupExpiredSessions).toHaveBeenCalledWith(30);
|
||||
}
|
||||
),
|
||||
{ numRuns: 50 }
|
||||
{ numRuns: 20, timeout: 3000 } // 减少运行次数并添加超时
|
||||
);
|
||||
}, 30000);
|
||||
}, 10000);
|
||||
|
||||
/**
|
||||
* 属性: 清理操作应该是原子性的,要么全部成功要么全部回滚
|
||||
@@ -520,7 +532,7 @@ describe('SessionCleanupService', () => {
|
||||
// 生成是否模拟清理失败
|
||||
fc.boolean(),
|
||||
// 生成会话数量
|
||||
fc.integer({ min: 1, max: 5 }),
|
||||
fc.integer({ min: 1, max: 3 }),
|
||||
async (shouldFail, sessionCount) => {
|
||||
// 重置mock以确保每次测试都是干净的状态
|
||||
jest.clearAllMocks();
|
||||
@@ -559,9 +571,9 @@ describe('SessionCleanupService', () => {
|
||||
expect(result.duration).toBeGreaterThanOrEqual(0);
|
||||
}
|
||||
),
|
||||
{ numRuns: 50 }
|
||||
{ numRuns: 20, timeout: 3000 } // 减少运行次数并添加超时
|
||||
);
|
||||
}, 30000);
|
||||
}, 10000);
|
||||
|
||||
/**
|
||||
* 属性: 清理配置更新应该正确重启清理任务而不丢失状态
|
||||
@@ -572,41 +584,44 @@ describe('SessionCleanupService', () => {
|
||||
fc.asyncProperty(
|
||||
// 生成初始配置
|
||||
fc.record({
|
||||
intervalMs: fc.integer({ min: 1, max: 5 }).map(m => m * 60 * 1000),
|
||||
sessionTimeoutMinutes: fc.integer({ min: 10, max: 60 }),
|
||||
intervalMs: fc.integer({ min: 1, max: 3 }).map(m => m * 60 * 1000),
|
||||
sessionTimeoutMinutes: fc.integer({ min: 10, max: 30 }),
|
||||
}),
|
||||
// 生成新配置
|
||||
fc.record({
|
||||
intervalMs: fc.integer({ min: 1, max: 5 }).map(m => m * 60 * 1000),
|
||||
sessionTimeoutMinutes: fc.integer({ min: 10, max: 60 }),
|
||||
intervalMs: fc.integer({ min: 1, max: 3 }).map(m => m * 60 * 1000),
|
||||
sessionTimeoutMinutes: fc.integer({ min: 10, max: 30 }),
|
||||
}),
|
||||
async (initialConfig, newConfig) => {
|
||||
// 重置mock以确保每次测试都是干净的状态
|
||||
jest.clearAllMocks();
|
||||
|
||||
// 设置初始配置并启动任务
|
||||
service.updateConfig(initialConfig);
|
||||
service.startCleanupTask();
|
||||
try {
|
||||
// 设置初始配置并启动任务
|
||||
service.updateConfig(initialConfig);
|
||||
service.startCleanupTask();
|
||||
|
||||
let status = service.getStatus();
|
||||
expect(status.isEnabled).toBe(true);
|
||||
expect(status.config.intervalMs).toBe(initialConfig.intervalMs);
|
||||
let status = service.getStatus();
|
||||
expect(status.isEnabled).toBe(true);
|
||||
expect(status.config.intervalMs).toBe(initialConfig.intervalMs);
|
||||
|
||||
// 更新配置
|
||||
service.updateConfig(newConfig);
|
||||
// 更新配置
|
||||
service.updateConfig(newConfig);
|
||||
|
||||
// 验证配置更新后任务仍在运行
|
||||
status = service.getStatus();
|
||||
expect(status.isEnabled).toBe(true);
|
||||
expect(status.config.intervalMs).toBe(newConfig.intervalMs);
|
||||
expect(status.config.sessionTimeoutMinutes).toBe(newConfig.sessionTimeoutMinutes);
|
||||
// 验证配置更新后任务仍在运行
|
||||
status = service.getStatus();
|
||||
expect(status.isEnabled).toBe(true);
|
||||
expect(status.config.intervalMs).toBe(newConfig.intervalMs);
|
||||
expect(status.config.sessionTimeoutMinutes).toBe(newConfig.sessionTimeoutMinutes);
|
||||
|
||||
service.stopCleanupTask();
|
||||
} finally {
|
||||
service.stopCleanupTask();
|
||||
}
|
||||
}
|
||||
),
|
||||
{ numRuns: 30 }
|
||||
{ numRuns: 15, timeout: 3000 } // 减少运行次数并添加超时
|
||||
);
|
||||
}, 30000);
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
describe('模块生命周期', () => {
|
||||
|
||||
Reference in New Issue
Block a user