kt-template-online-api/test/qqbot/account/qqbot-napcat-watchdog.service.spec.ts

103 lines
3.2 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.

import { ConfigService } from '@nestjs/config';
import { QqbotNapcatWatchdogService } from '@/modules/qqbot/napcat/login/qqbot-napcat-watchdog.service';
function buildService(
configValues: Record<string, string | undefined>,
runOfflineWatchdog: jest.Mock,
) {
const configService = {
get: jest.fn((key: string) => configValues[key]),
} as unknown as ConfigService;
const accountService = { runOfflineWatchdog } as any;
return new QqbotNapcatWatchdogService(configService, accountService);
}
// 刷新微任务队列,让定时器回调里的 async tick含 finally 复位 running执行完。
async function flushMicrotasks() {
await Promise.resolve();
await Promise.resolve();
}
describe('QqbotNapcatWatchdogService', () => {
afterEach(() => {
jest.useRealTimers();
});
it('periodically triggers the offline watchdog when enabled', async () => {
jest.useFakeTimers();
const runOfflineWatchdog = jest.fn().mockResolvedValue({ checked: 1 });
const service = buildService(
{ QQBOT_NAPCAT_WATCHDOG_INTERVAL_MS: '30000' },
runOfflineWatchdog,
);
service.onModuleInit();
expect(runOfflineWatchdog).not.toHaveBeenCalled();
jest.advanceTimersByTime(30000);
await flushMicrotasks();
expect(runOfflineWatchdog).toHaveBeenCalledTimes(1);
jest.advanceTimersByTime(30000);
await flushMicrotasks();
expect(runOfflineWatchdog).toHaveBeenCalledTimes(2);
service.onModuleDestroy();
jest.advanceTimersByTime(60000);
await flushMicrotasks();
expect(runOfflineWatchdog).toHaveBeenCalledTimes(2);
});
it('does not start a timer when disabled', async () => {
jest.useFakeTimers();
const runOfflineWatchdog = jest.fn().mockResolvedValue({ checked: 0 });
const service = buildService(
{ QQBOT_NAPCAT_WATCHDOG_ENABLED: 'false' },
runOfflineWatchdog,
);
service.onModuleInit();
jest.advanceTimersByTime(600000);
await flushMicrotasks();
expect(runOfflineWatchdog).not.toHaveBeenCalled();
});
it('clamps an unreasonably small interval to the safe default', () => {
const service = buildService(
{ QQBOT_NAPCAT_WATCHDOG_INTERVAL_MS: '1000' },
jest.fn(),
) as any;
expect(service.getIntervalMs()).toBe(120_000);
});
it('skips overlapping ticks while a previous run is still pending', async () => {
jest.useFakeTimers();
let resolvePending: (() => void) | undefined;
const runOfflineWatchdog = jest.fn(
() =>
new Promise<{ checked: number }>((resolve) => {
resolvePending = () => resolve({ checked: 1 });
}),
);
const service = buildService(
{ QQBOT_NAPCAT_WATCHDOG_INTERVAL_MS: '30000' },
runOfflineWatchdog,
);
service.onModuleInit();
jest.advanceTimersByTime(30000); // first tick starts, stays pending
await flushMicrotasks();
jest.advanceTimersByTime(30000); // second tick should be skipped
await flushMicrotasks();
expect(runOfflineWatchdog).toHaveBeenCalledTimes(1);
resolvePending?.();
await flushMicrotasks();
jest.advanceTimersByTime(30000); // running reset, a new tick can run
await flushMicrotasks();
expect(runOfflineWatchdog).toHaveBeenCalledTimes(2);
service.onModuleDestroy();
});
});