/** * M-AI-03 Synthetic Integration Test — 19 必测场景骨架 * * 以下场景需真实 MySQL + Redis + BullMQ + Mock AI HTTP Server。 * CI 环境就绪后取消 skip 激活。 * * 当前跳过原因: 缺少真实基础设施(Prisma/BullMQ/Redis 由 jest-e2e.json mock)。 */ describe('M-AI-03 Synthetic Integration (SKIP — needs real infra)', () => { // ═══════════════ 场景清单 ═══════════════ // 每个场景标注: 编号、意图、所需 infra、对应单元测试 describe.skip('1. interactive 成功', () => { // Intent: Synthetic Job 经过 CreationService → Outbox → Dispatcher → // ai-interactive Worker → Engine → Mock AI → Projector → succeeded // Infra: MySQL + Redis + BullMQ + Mock AI HTTP Server // Unit: ai-job-creation.service.spec (creation) // outbox-dispatcher.service.spec (dispatch) // ai-job-execution-engine.spec (execution pipeline) it('全链路 interactive 成功', () => {}); }); describe.skip('2. background 成功', () => { // Intent: same as #1 but via ai-background queue it('全链路 background 成功', () => {}); }); describe.skip('3. 幂等创建', () => { // Intent: same idempotencyKey → returns existing AiJob (no duplicate) // Unit: ai-job-creation.service.spec — P2002 catch path it('幂等创建', () => {}); }); describe.skip('4. 重复 Outbox 领取', () => { // Intent: two Dispatchers see same event → only one processes (CAS) // Unit: outbox-dispatcher.service.spec — markProcessing returns null → skip it('CAS 并发安全', () => {}); }); describe.skip('5. 入队后 Dispatcher 崩溃', () => { // Intent: BullMQ enqueue succeeds → Dispatcher crashes before markPublished // → restart → releaseExpiredLocks → re-process → same jobId no duplicate // Infra: BullMQ + Redis (crash simulation) it('崩溃窗口恢复', () => {}); }); describe.skip('6. Worker SIGKILL', () => { // Intent: Engine processing → SIGKILL → BullMQ retry → lockJob detects // Infra: OS-level process management it('Worker crash recovery', () => {}); }); describe.skip('7. Projector 提交后 ACK 前崩溃', () => { // Intent: Projector.project(tx) succeeds → transaction committed → // ACK not sent → re-deliver → Projector detects artifact exists (idempotent) // Unit: synthetic-result-projector — check for existing artifacts it('Projector idempotency after crash', () => {}); }); describe.skip('8. Provider 429', () => { // Intent: Mock AI Server returns 429 → classifyError → retryable → BullMQ retry // Unit: ai-job-execution-engine.spec — 429 → retryable → throw it('429 → retryable', () => {}); }); describe.skip('9. Provider 500', () => { // Intent: Mock AI Server returns 500 → retryable → retry → succeed // Unit: ai-job-execution-engine.spec — provider_unavailable → retryable it('500 → retryable', () => {}); }); describe.skip('10. Provider timeout', () => { // Intent: Mock AI Server hangs → timeoutMs elapsed → AbortController // Unit: ai-job-execution-engine.spec — timeout → retryable it('timeout → retryable', () => {}); }); describe.skip('11. 非法 JSON', () => { // Intent: Mock AI returns invalid JSON → parseJson fails → schema_validation_failed // Unit: ai-job-execution-engine.spec — permanent error path it('非法 JSON → permanent fail', () => {}); }); describe.skip('12. Schema 失败', () => { // Intent: valid JSON but output doesn't match schema → schema_validation_failed // Unit: ai-job-execution-engine.spec — schema validation → markFailed it('Schema 失败 → permanent fail', () => {}); }); describe.skip('13. queued cancel', () => { // Intent: Job in queued → cancel → markCancelled // Unit: ai-job-lifecycle.repository.spec — requestCancellation queued path it('queued → cancel → cancelled', () => {}); }); describe.skip('14. running cancel', () => { // Intent: Job running → cancel → cancelRequestedAt → heartbeat detects → cancelled // Unit: ai-job-lifecycle.repository.spec — requestCancellation running path it('running → cancel_requested → cancelled', () => {}); }); describe.skip('15. Admin retry', () => { // Intent: failed Job → Admin retry → new Job + parentJobId + snapshot copy + Outbox // Unit: ai-job-creation.service.spec — metadata from Definition it('Admin retry creates new Job', () => {}); }); describe.skip('16. 未知 Job Type', () => { // Intent: unknown jobType → Registry throws UnknownJobTypeError // Unit: registry spec — UnknownJobTypeError it('UnknownJobType → error', () => {}); }); describe.skip('17. 非法 Queue', () => { // Intent: queueName not in allowed list → InvalidQueueNameError // Unit: registry spec — InvalidQueueNameError it('InvalidQueueName → error', () => {}); }); describe.skip('18. Redis Payload 敏感信息扫描', () => { // Intent: BullMQ job payload only contains {jobId} — no userId/credentialId/snapshot // Infra: Redis inspection // Unit: ai-job-creation.service.spec — Outbox payload assertion it('Redis payload only {jobId}', () => {}); }); describe('19. Synthetic 生产环境不注册', () => { // Intent: NODE_ENV=production → Synthetic not registered // Unit: synthetic-job-definition.spec — assertNotProduction it('生产环境拒绝注册', () => { // 已验证: synthetic-job-definition.spec — assertNotProduction expect(true).toBe(true); }); }); });