feat(test): B5 整合測試框架 — 真實 DB, 5/5 通過
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 2m34s
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 2m34s
新增: - docker-compose.test.yml: CI 用臨時 pgvector PostgreSQL (port 15432) - tests/factories.py: Incident/Approval/Knowledge/RAG 測試資料工廠 - tests/integration/test_b5_core_flows.py: 5 個 E2E 整合測試 (5/5 PASSED 1.03s) - tests/integration/setup_test_schema.sql: CI schema 初始化 SQL - cd.yaml: 新增 Integration Tests B5 step - scripts/sync_dev_db.py: dev DB 同步工具 修正: - .env.test: DATABASE_URL 指向 awoooi_dev (本機設定, gitignore 不入庫) 禁止 Mock 鐵律: 所有 DB 測試使用真實 PostgreSQL, 無 SQLite/MagicMock Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
106
apps/api/tests/integration/setup_test_schema.sql
Normal file
106
apps/api/tests/integration/setup_test_schema.sql
Normal file
@@ -0,0 +1,106 @@
|
||||
-- Integration Test Schema Setup
|
||||
-- ================================
|
||||
-- 為 CI 環境的臨時 PostgreSQL 建立測試所需的 schema
|
||||
-- 使用: psql $TEST_DATABASE_URL -f setup_test_schema.sql
|
||||
-- 2026-04-10 Claude Sonnet 4.6 Asia/Taipei
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'incidentstatus') THEN
|
||||
CREATE TYPE incidentstatus AS ENUM ('INVESTIGATING','MITIGATING','RESOLVED','CLOSED','ESCALATED');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'severity') THEN
|
||||
CREATE TYPE severity AS ENUM ('P0','P1','P2','P3');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'approvalstatus') THEN
|
||||
CREATE TYPE approvalstatus AS ENUM ('PENDING','APPROVED','REJECTED','EXPIRED','EXECUTION_SUCCESS','EXECUTION_FAILED');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'risklevel') THEN
|
||||
CREATE TYPE risklevel AS ENUM ('LOW','MEDIUM','HIGH','CRITICAL');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrysource') THEN
|
||||
CREATE TYPE entrysource AS ENUM ('AI_EXTRACTED','HUMAN');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrystatus') THEN
|
||||
CREATE TYPE entrystatus AS ENUM ('DRAFT','REVIEW','APPROVED','ARCHIVED','published');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrytype') THEN
|
||||
CREATE TYPE entrytype AS ENUM ('INCIDENT_CASE','RUNBOOK','BEST_PRACTICE','POSTMORTEM','auto_runbook','anti_pattern');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS incidents (
|
||||
incident_id VARCHAR(30) PRIMARY KEY,
|
||||
status incidentstatus NOT NULL DEFAULT 'INVESTIGATING',
|
||||
severity severity NOT NULL DEFAULT 'P2',
|
||||
signals JSON DEFAULT '[]',
|
||||
affected_services JSON DEFAULT '[]',
|
||||
decision_chain JSON DEFAULT '[]',
|
||||
proposal_ids JSON DEFAULT '[]',
|
||||
outcome JSON DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
resolved_at TIMESTAMPTZ,
|
||||
closed_at TIMESTAMPTZ,
|
||||
ttl_days INTEGER DEFAULT 30,
|
||||
vectorized BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS approval_records (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
action VARCHAR(500) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
status approvalstatus NOT NULL DEFAULT 'PENDING',
|
||||
risk_level risklevel NOT NULL,
|
||||
required_signatures INTEGER DEFAULT 1,
|
||||
current_signatures INTEGER DEFAULT 0,
|
||||
signatures JSON DEFAULT '[]',
|
||||
blast_radius JSON DEFAULT '{}',
|
||||
dry_run_checks JSON DEFAULT '[]',
|
||||
requested_by VARCHAR,
|
||||
rejection_reason TEXT,
|
||||
extra_metadata JSON DEFAULT '{}',
|
||||
fingerprint VARCHAR,
|
||||
hit_count INTEGER DEFAULT 1,
|
||||
last_seen_at TIMESTAMPTZ,
|
||||
approval_level VARCHAR DEFAULT 'standard',
|
||||
approval_votes JSONB,
|
||||
required_votes INTEGER DEFAULT 1,
|
||||
incident_id VARCHAR,
|
||||
telegram_message_id INTEGER,
|
||||
telegram_chat_id INTEGER,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
expires_at TIMESTAMPTZ,
|
||||
resolved_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS knowledge_entries (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
title VARCHAR NOT NULL,
|
||||
content TEXT,
|
||||
entry_type entrytype NOT NULL,
|
||||
category VARCHAR,
|
||||
tags JSON DEFAULT '[]',
|
||||
source entrysource NOT NULL DEFAULT 'HUMAN',
|
||||
status entrystatus NOT NULL DEFAULT 'DRAFT',
|
||||
related_incident_id VARCHAR,
|
||||
related_playbook_id VARCHAR,
|
||||
symptoms_hash VARCHAR,
|
||||
view_count INTEGER DEFAULT 0,
|
||||
created_by VARCHAR,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rag_chunks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
source TEXT NOT NULL,
|
||||
source_id TEXT NOT NULL,
|
||||
title TEXT,
|
||||
chunk_text TEXT NOT NULL,
|
||||
embedding vector(768),
|
||||
metadata JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
Reference in New Issue
Block a user