import { recordSlowPrismaQuery, recordSlowRequest, clearOpsRuntimeEventsForTests } from './ops-runtime.store'; import { OpsService } from './ops.service'; describe('OpsService', () => { afterEach(() => clearOpsRuntimeEventsForTests()); it('returns runtime performance counters without exposing secrets', async () => { const prisma = { backgroundJob: { findMany: jest.fn().mockResolvedValue([ { id: 'job-queued', type: 'xiaobao.summary.refresh', status: 'queued', attempts: 0, maxAttempts: 5, availableAt: new Date('2026-07-08T08:00:00.000Z'), lockedUntil: null, lastError: null, updatedAt: new Date('2026-07-08T08:00:00.000Z'), }, { id: 'job-running', type: 'xiaobao.ai.interpret', status: 'running', attempts: 1, maxAttempts: 3, availableAt: new Date('2026-07-08T08:01:00.000Z'), lockedUntil: new Date('2026-07-08T08:05:00.000Z'), lastError: null, updatedAt: new Date('2026-07-08T08:02:00.000Z'), }, { id: 'job-failed', type: 'xiaobao.ai.interpret', status: 'failed', attempts: 3, maxAttempts: 3, availableAt: new Date('2026-07-08T08:03:00.000Z'), lockedUntil: null, lastError: 'provider failed with sk-secret-token', updatedAt: new Date('2026-07-08T08:04:00.000Z'), }, ]), }, xiaobaoRiskSummary: { count: jest.fn().mockResolvedValue(7), }, }; recordSlowRequest({ method: 'POST', url: '/api/v1/ai/risk-interpret?token=sk-secret-token', durationMs: 1500, thresholdMs: 1000, occurredAt: new Date('2026-07-08T08:05:00.000Z'), }); recordSlowPrismaQuery({ query: 'SELECT * FROM background_jobs WHERE last_error = "sk-secret-token"', durationMs: 420, thresholdMs: 300, occurredAt: new Date('2026-07-08T08:06:00.000Z'), }); const service = new OpsService(prisma as any); const snapshot = await service.getRuntimeSnapshot(new Date('2026-07-08T08:07:00.000Z')); expect(snapshot.dirtySummaryCount).toBe(7); expect(snapshot.jobQueue.totals).toEqual({ queued: 1, running: 1, succeeded: 0, failed: 1, total: 3 }); expect(snapshot.jobQueue.byType).toEqual([ expect.objectContaining({ type: 'xiaobao.ai.interpret', running: 1, failed: 1, total: 2 }), expect.objectContaining({ type: 'xiaobao.summary.refresh', queued: 1, total: 1 }), ]); expect(snapshot.jobQueue.recentFailures).toEqual([ expect.objectContaining({ id: 'job-failed', type: 'xiaobao.ai.interpret', lastError: expect.stringContaining('[redacted]'), }), ]); expect(snapshot.slowRequests[0].path).toBe('/api/v1/ai/risk-interpret'); expect(snapshot.slowQueries[0].queryPreview).toContain('[redacted]'); expect(JSON.stringify(snapshot)).not.toContain('sk-secret-token'); expect(snapshot.access).toEqual({ requiredPermission: 'ops:view', backendEnforced: false, adapter: 'OpsPermissionAdapter', }); }); });