tests
This commit is contained in:
parent
54f37f9521
commit
3a7254708e
19 changed files with 1560 additions and 1237 deletions
|
|
@ -1,36 +1,57 @@
|
|||
import { beforeEach, describe, expect, it, mock } from 'bun:test';
|
||||
import { beforeEach, describe, expect, it, mock, type Mock } from 'bun:test';
|
||||
import { QueueMetricsCollector } from '../src/queue-metrics';
|
||||
import type { Queue, QueueEvents } from 'bullmq';
|
||||
import type { Queue, QueueEvents, Job } from 'bullmq';
|
||||
|
||||
describe('QueueMetricsCollector', () => {
|
||||
let metrics: QueueMetricsCollector;
|
||||
|
||||
const mockQueue = {
|
||||
name: 'test-queue',
|
||||
getWaitingCount: mock(() => Promise.resolve(0)),
|
||||
getActiveCount: mock(() => Promise.resolve(0)),
|
||||
getCompletedCount: mock(() => Promise.resolve(0)),
|
||||
getFailedCount: mock(() => Promise.resolve(0)),
|
||||
getDelayedCount: mock(() => Promise.resolve(0)),
|
||||
isPaused: mock(() => Promise.resolve(false)),
|
||||
getWaiting: mock(() => Promise.resolve([])),
|
||||
} as unknown as Queue;
|
||||
|
||||
const mockQueueEvents = {
|
||||
on: mock(() => {}),
|
||||
} as unknown as QueueEvents;
|
||||
let mockQueue: {
|
||||
name: string;
|
||||
getWaitingCount: Mock<() => Promise<number>>;
|
||||
getActiveCount: Mock<() => Promise<number>>;
|
||||
getCompletedCount: Mock<() => Promise<number>>;
|
||||
getFailedCount: Mock<() => Promise<number>>;
|
||||
getDelayedCount: Mock<() => Promise<number>>;
|
||||
isPaused: Mock<() => Promise<boolean>>;
|
||||
getWaiting: Mock<() => Promise<Job[]>>;
|
||||
};
|
||||
let mockQueueEvents: {
|
||||
on: Mock<(event: string, handler: Function) => void>;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
metrics = new QueueMetricsCollector(mockQueue, mockQueueEvents);
|
||||
mockQueue = {
|
||||
name: 'test-queue',
|
||||
getWaitingCount: mock(() => Promise.resolve(0)),
|
||||
getActiveCount: mock(() => Promise.resolve(0)),
|
||||
getCompletedCount: mock(() => Promise.resolve(0)),
|
||||
getFailedCount: mock(() => Promise.resolve(0)),
|
||||
getDelayedCount: mock(() => Promise.resolve(0)),
|
||||
isPaused: mock(() => Promise.resolve(false)),
|
||||
getWaiting: mock(() => Promise.resolve([])),
|
||||
};
|
||||
|
||||
mockQueueEvents = {
|
||||
on: mock(() => {}),
|
||||
};
|
||||
|
||||
metrics = new QueueMetricsCollector(mockQueue as unknown as Queue, mockQueueEvents as unknown as QueueEvents);
|
||||
});
|
||||
|
||||
describe('collect metrics', () => {
|
||||
it('should collect current metrics', async () => {
|
||||
(mockQueue.getWaitingCount as any) = mock(() => Promise.resolve(5));
|
||||
(mockQueue.getActiveCount as any) = mock(() => Promise.resolve(2));
|
||||
(mockQueue.getCompletedCount as any) = mock(() => Promise.resolve(100));
|
||||
(mockQueue.getFailedCount as any) = mock(() => Promise.resolve(3));
|
||||
(mockQueue.getDelayedCount as any) = mock(() => Promise.resolve(1));
|
||||
mockQueue.getWaitingCount.mockImplementation(() => Promise.resolve(5));
|
||||
mockQueue.getActiveCount.mockImplementation(() => Promise.resolve(2));
|
||||
mockQueue.getCompletedCount.mockImplementation(() => Promise.resolve(100));
|
||||
mockQueue.getFailedCount.mockImplementation(() => Promise.resolve(3));
|
||||
mockQueue.getDelayedCount.mockImplementation(() => Promise.resolve(1));
|
||||
|
||||
// Add some completed timestamps to avoid 100% failure rate
|
||||
const completedHandler = mockQueueEvents.on.mock.calls.find(call => call[0] === 'completed')?.[1];
|
||||
if (completedHandler) {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
completedHandler();
|
||||
}
|
||||
}
|
||||
|
||||
const result = await metrics.collect();
|
||||
|
||||
|
|
@ -43,9 +64,9 @@ describe('QueueMetricsCollector', () => {
|
|||
});
|
||||
|
||||
it('should detect health issues', async () => {
|
||||
(mockQueue.getWaitingCount as any) = mock(() => Promise.resolve(2000)); // High backlog
|
||||
(mockQueue.getActiveCount as any) = mock(() => Promise.resolve(150)); // High active
|
||||
(mockQueue.getFailedCount as any) = mock(() => Promise.resolve(50));
|
||||
mockQueue.getWaitingCount.mockImplementation(() => Promise.resolve(2000)); // High backlog
|
||||
mockQueue.getActiveCount.mockImplementation(() => Promise.resolve(150)); // High active
|
||||
mockQueue.getFailedCount.mockImplementation(() => Promise.resolve(50));
|
||||
|
||||
const result = await metrics.collect();
|
||||
|
||||
|
|
@ -56,8 +77,8 @@ describe('QueueMetricsCollector', () => {
|
|||
});
|
||||
|
||||
it('should handle paused queue', async () => {
|
||||
(mockQueue.getWaitingCount as any) = mock(() => Promise.resolve(10));
|
||||
(mockQueue.isPaused as any) = mock(() => Promise.resolve(true));
|
||||
mockQueue.getWaitingCount.mockImplementation(() => Promise.resolve(10));
|
||||
mockQueue.isPaused.mockImplementation(() => Promise.resolve(true));
|
||||
|
||||
const result = await metrics.collect();
|
||||
|
||||
|
|
@ -67,8 +88,11 @@ describe('QueueMetricsCollector', () => {
|
|||
|
||||
describe('processing time metrics', () => {
|
||||
it('should calculate processing time metrics', async () => {
|
||||
// Simulate some processing times
|
||||
(metrics as any).processingTimes = [1000, 2000, 3000, 4000, 5000];
|
||||
// Access private property for testing
|
||||
const metricsWithPrivate = metrics as QueueMetricsCollector & {
|
||||
processingTimes: number[];
|
||||
};
|
||||
metricsWithPrivate.processingTimes = [1000, 2000, 3000, 4000, 5000];
|
||||
|
||||
const result = await metrics.collect();
|
||||
|
||||
|
|
@ -89,14 +113,19 @@ describe('QueueMetricsCollector', () => {
|
|||
|
||||
describe('throughput metrics', () => {
|
||||
it('should calculate throughput', async () => {
|
||||
// Simulate completed and failed timestamps
|
||||
// Access private properties for testing
|
||||
const metricsWithPrivate = metrics as QueueMetricsCollector & {
|
||||
completedTimestamps: number[];
|
||||
failedTimestamps: number[];
|
||||
};
|
||||
|
||||
const now = Date.now();
|
||||
(metrics as any).completedTimestamps = [
|
||||
metricsWithPrivate.completedTimestamps = [
|
||||
now - 30000, // 30 seconds ago
|
||||
now - 20000,
|
||||
now - 10000,
|
||||
];
|
||||
(metrics as any).failedTimestamps = [
|
||||
metricsWithPrivate.failedTimestamps = [
|
||||
now - 25000,
|
||||
now - 5000,
|
||||
];
|
||||
|
|
@ -111,10 +140,18 @@ describe('QueueMetricsCollector', () => {
|
|||
|
||||
describe('getReport', () => {
|
||||
it('should generate formatted report', async () => {
|
||||
(mockQueue.getWaitingCount as any) = mock(() => Promise.resolve(5));
|
||||
(mockQueue.getActiveCount as any) = mock(() => Promise.resolve(2));
|
||||
(mockQueue.getCompletedCount as any) = mock(() => Promise.resolve(100));
|
||||
(mockQueue.getFailedCount as any) = mock(() => Promise.resolve(3));
|
||||
mockQueue.getWaitingCount.mockImplementation(() => Promise.resolve(5));
|
||||
mockQueue.getActiveCount.mockImplementation(() => Promise.resolve(2));
|
||||
mockQueue.getCompletedCount.mockImplementation(() => Promise.resolve(100));
|
||||
mockQueue.getFailedCount.mockImplementation(() => Promise.resolve(3));
|
||||
|
||||
// Add some completed timestamps to make it healthy
|
||||
const completedHandler = mockQueueEvents.on.mock.calls.find(call => call[0] === 'completed')?.[1];
|
||||
if (completedHandler) {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
completedHandler();
|
||||
}
|
||||
}
|
||||
|
||||
const report = await metrics.getReport();
|
||||
|
||||
|
|
@ -129,10 +166,10 @@ describe('QueueMetricsCollector', () => {
|
|||
|
||||
describe('getPrometheusMetrics', () => {
|
||||
it('should generate Prometheus formatted metrics', async () => {
|
||||
(mockQueue.getWaitingCount as any) = mock(() => Promise.resolve(5));
|
||||
(mockQueue.getActiveCount as any) = mock(() => Promise.resolve(2));
|
||||
(mockQueue.getCompletedCount as any) = mock(() => Promise.resolve(100));
|
||||
(mockQueue.getFailedCount as any) = mock(() => Promise.resolve(3));
|
||||
mockQueue.getWaitingCount.mockImplementation(() => Promise.resolve(5));
|
||||
mockQueue.getActiveCount.mockImplementation(() => Promise.resolve(2));
|
||||
mockQueue.getCompletedCount.mockImplementation(() => Promise.resolve(100));
|
||||
mockQueue.getFailedCount.mockImplementation(() => Promise.resolve(3));
|
||||
|
||||
const prometheusMetrics = await metrics.getPrometheusMetrics();
|
||||
|
||||
|
|
@ -149,10 +186,10 @@ describe('QueueMetricsCollector', () => {
|
|||
describe('event listeners', () => {
|
||||
it('should setup event listeners on construction', () => {
|
||||
const newMockQueueEvents = {
|
||||
on: mock(() => {}),
|
||||
} as unknown as QueueEvents;
|
||||
on: mock<(event: string, handler: Function) => void>(() => {}),
|
||||
};
|
||||
|
||||
new QueueMetricsCollector(mockQueue, newMockQueueEvents);
|
||||
new QueueMetricsCollector(mockQueue as unknown as Queue, newMockQueueEvents as unknown as QueueEvents);
|
||||
|
||||
expect(newMockQueueEvents.on).toHaveBeenCalledWith('completed', expect.any(Function));
|
||||
expect(newMockQueueEvents.on).toHaveBeenCalledWith('failed', expect.any(Function));
|
||||
|
|
@ -164,9 +201,9 @@ describe('QueueMetricsCollector', () => {
|
|||
it('should get oldest waiting job date', async () => {
|
||||
const oldJob = {
|
||||
timestamp: Date.now() - 60000, // 1 minute ago
|
||||
};
|
||||
} as Job;
|
||||
|
||||
(mockQueue.getWaiting as any) = mock(() => Promise.resolve([oldJob]));
|
||||
mockQueue.getWaiting.mockImplementation(() => Promise.resolve([oldJob]));
|
||||
|
||||
const result = await metrics.collect();
|
||||
|
||||
|
|
@ -175,11 +212,11 @@ describe('QueueMetricsCollector', () => {
|
|||
});
|
||||
|
||||
it('should return null when no waiting jobs', async () => {
|
||||
(mockQueue.getWaiting as any) = mock(() => Promise.resolve([]));
|
||||
mockQueue.getWaiting.mockImplementation(() => Promise.resolve([]));
|
||||
|
||||
const result = await metrics.collect();
|
||||
|
||||
expect(result.oldestWaitingJob).toBeNull();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue