/** * Anomaly Detection Service Tests */ import { describe, it, expect, beforeEach, vi } from 'vitest' import { detectAnomalies, getAnomalies } from '../anomaly-detection' import type { Context } from '../../types/context' describe('Anomaly Detection Service', () => { let mockContext: Context let mockDb: any beforeEach(() => { mockDb = { query: vi.fn(), } mockContext = { db: mockDb as any, user: { id: 'user-1', email: 'test@example.com', name: 'Test User', role: 'ADMIN', }, } as Context }) describe('detectAnomalies', () => { it('should detect spikes in metrics', async () => { // Mock metrics data with a spike const baseValue = 50 const spikeValue = 200 const metrics = Array.from({ length: 20 }, (_, i) => ({ timestamp: new Date(Date.now() - (20 - i) * 60000), value: i === 15 ? spikeValue.toString() : baseValue.toString(), labels: {}, })) mockDb.query .mockResolvedValueOnce({ rows: metrics }) .mockResolvedValue({ rows: [] }) // For storing anomalies const anomalies = await detectAnomalies(mockContext, { resourceId: 'resource-1', metricType: 'CPU_USAGE', sensitivity: 'MEDIUM', }) expect(anomalies.length).toBeGreaterThan(0) expect(anomalies.some((a) => a.anomalyType === 'SPIKE')).toBe(true) }) it('should detect drops in metrics', async () => { const baseValue = 50 const dropValue = 5 const metrics = Array.from({ length: 20 }, (_, i) => ({ timestamp: new Date(Date.now() - (20 - i) * 60000), value: i === 15 ? dropValue.toString() : baseValue.toString(), labels: {}, })) mockDb.query .mockResolvedValueOnce({ rows: metrics }) .mockResolvedValue({ rows: [] }) const anomalies = await detectAnomalies(mockContext, { resourceId: 'resource-1', metricType: 'CPU_USAGE', }) expect(anomalies.some((a) => a.anomalyType === 'DROP')).toBe(true) }) it('should return empty array when insufficient data', async () => { mockDb.query.mockResolvedValue({ rows: Array.from({ length: 5 }) }) const anomalies = await detectAnomalies(mockContext, { resourceId: 'resource-1', metricType: 'CPU_USAGE', }) expect(anomalies).toEqual([]) }) }) describe('getAnomalies', () => { it('should retrieve stored anomalies', async () => { const mockAnomalies = [ { id: 'anomaly-1', resource_id: 'resource-1', metric_type: 'CPU_USAGE', severity: 'HIGH', anomaly_type: 'SPIKE', value: '200', expected_value: '50', deviation: '300', timestamp: new Date(), description: 'CPU spike detected', recommendation: 'Scale up resources', }, ] mockDb.query.mockResolvedValue({ rows: mockAnomalies }) const anomalies = await getAnomalies(mockContext, 'resource-1') expect(anomalies).toHaveLength(1) expect(anomalies[0].severity).toBe('HIGH') }) }) })