- 添加 docker-compose.local.yml(MySQL/Redis/Qdrant 本地基础设施) - 添加 mysql.conf.d 本地 MySQL 低资源配置 - RAG Worker Python 3.9 兼容(from __future__ import annotations) - 同步最新业务代码变更
137 lines
5.7 KiB
TypeScript
137 lines
5.7 KiB
TypeScript
/**
|
||
* 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);
|
||
});
|
||
});
|
||
});
|