kt-template-online-api/test/qqbot/plugins/repeater/qqbot-repeater.plugin.spec.ts

122 lines
3.7 KiB
TypeScript

import { ToolsService } from '@/common';
import { QqbotRepeaterPluginService } from '@/qqbot/plugins/repeater/qqbot-repeater.plugin';
import type { QqbotNormalizedMessage } from '@/qqbot/qqbot.types';
function createMessage(text: string): QqbotNormalizedMessage {
return {
eventTime: new Date(),
groupId: 'group-1',
messageId: `message-${text}-${Date.now()}`,
messageText: text,
messageType: 'group',
rawEvent: {},
rawMessage: text,
selfId: 'bot-1',
targetId: 'group-1',
userId: 'user-1',
};
}
function createService(config: Record<string, number | string | undefined>) {
const sendService = {
sendText: jest.fn().mockResolvedValue({ status: 'ok' }),
};
const service = new QqbotRepeaterPluginService(
{
get: jest.fn((key: string) => config[key]),
} as any,
{
getBoundEventPluginKeys: jest.fn().mockResolvedValue(['repeater']),
} as any,
sendService as any,
new ToolsService(),
);
return { sendService, service };
}
describe('QqbotRepeaterPluginService risk-control defaults', () => {
beforeEach(() => {
jest.useFakeTimers();
jest.setSystemTime(new Date('2026-06-12T00:00:00.000Z'));
});
afterEach(() => {
jest.useRealTimers();
});
it('uses a conservative default threshold before repeating', async () => {
const { sendService, service } = createService({});
await service.handleMessage(createMessage('哈'));
await service.handleMessage(createMessage('哈'));
await service.handleMessage(createMessage('哈'));
expect(sendService.sendText).not.toHaveBeenCalled();
await service.handleMessage(createMessage('哈'));
expect(sendService.sendText).toHaveBeenCalledTimes(1);
});
it('applies a conversation interval after one repeated send', async () => {
const { sendService, service } = createService({
QQBOT_REPEATER_CONFIG_CACHE_TTL_MS: 600000,
QQBOT_REPEATER_MIN_INTERVAL_MS: 600000,
QQBOT_REPEATER_THRESHOLD: 4,
});
for (let index = 0; index < 4; index += 1) {
await service.handleMessage(createMessage('哈'));
}
for (let index = 0; index < 4; index += 1) {
await service.handleMessage(createMessage('呀'));
}
expect(sendService.sendText).toHaveBeenCalledTimes(1);
jest.setSystemTime(new Date(Date.now() + 600000));
await service.handleMessage(createMessage('呀'));
expect(sendService.sendText).toHaveBeenCalledTimes(2);
});
it('applies the conversation interval even when repeated send fails', async () => {
const { sendService, service } = createService({
QQBOT_REPEATER_CONFIG_CACHE_TTL_MS: 600000,
QQBOT_REPEATER_MIN_INTERVAL_MS: 600000,
QQBOT_REPEATER_THRESHOLD: 4,
});
sendService.sendText.mockRejectedValueOnce(new Error('send failed'));
jest.spyOn((service as any).logger, 'warn').mockImplementation();
for (let index = 0; index < 4; index += 1) {
await service.handleMessage(createMessage('哈'));
}
for (let index = 0; index < 4; index += 1) {
await service.handleMessage(createMessage('呀'));
}
expect(sendService.sendText).toHaveBeenCalledTimes(1);
});
it('keeps the conversation interval after a non-repeatable message', async () => {
const { sendService, service } = createService({
QQBOT_REPEATER_CONFIG_CACHE_TTL_MS: 600000,
QQBOT_REPEATER_MIN_INTERVAL_MS: 600000,
QQBOT_REPEATER_THRESHOLD: 4,
});
for (let index = 0; index < 4; index += 1) {
await service.handleMessage(createMessage('哈'));
}
await service.handleMessage(createMessage('!help'));
for (let index = 0; index < 4; index += 1) {
await service.handleMessage(createMessage('呀'));
}
expect(sendService.sendText).toHaveBeenCalledTimes(1);
});
});