feat(ops): 增加运行时性能看板
This commit is contained in:
89
apps/server/src/modules/ops/ops.service.spec.ts
Normal file
89
apps/server/src/modules/ops/ops.service.spec.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
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',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user