E2E 測試平台 · 文件目錄
平台文件 / 03 資料模型與儲存規格與驗收參考

03 資料模型與儲存

主要讀者:DBA、後端研發工程師、測試平台維護者。

03 資料模型與儲存 圖 1
點擊圖片可放大、縮小或關閉;放大後可捲動查看。

1 範圍與責任

本章只描述 Crystal/Sentry/Northstar E2E 測試平台。受測 API 與其業務資料是測試對象,不納入本平台實體字典。Sentry 是共用核心 library,並非另一個獨立資料服務。

圖中的型別是 Java 映射型別。PK 表示映射識別鍵,FK 表示邏輯關聯;實體約束是否已部署尚未查驗。歷史建表雖有部分 PK/FK 宣告,但不足以證明現場 schema 與工作樹一致。完整欄位與歷史/現行差異見 04 資料字典。

1-1 實體對照與資料來源

圖中實體 真實資料表 權威內容與負責元件
PROJECT qa.qa_c001 Crystal 維護公司與專案
ENVIRONMENT/CONFIG qa.qa_c002/qa.qa_c012 Crystal 維護環境與設定;執行時由 Northstar 載入
SUITE/CASE_DEF/STEP_DEF qa.qa_c003/qa.qa_c004/qa.qa_c013 Crystal 維護測試群組、案例及六類步驟定義
PLAN/PLAN_CASE qa.qa_c005/qa.qa_c006 計畫選取哪些 Case;不等同選取整個 Suite
TRIGGER_DEF qa.qa_c007 計畫、環境、cron、下次執行時間與通知群組
RUN/RUN_SUITE/RUN_CASE/RUN_STEP qa.qa_c008~qa.qa_c011 Northstar 透過 Sentry 執行,經 Crystal API 回寫本次結果
COMPARE/COMPARE_DETAIL qa.qa_r001/qa.qa_r002 既有 SQL 比對資料與報表契約;有寫入 API,不保證每條現行 handler 都填入
ARTIFACT qa.qa_u001 執行產物的檔名、來源與遠端位置;實際儲存位置及停機後可用性待環境核對
INVOKE_TYPE qa.qa_z000 參數型別及可選呼叫類別的清單;不是方法執行紀錄

1-2 定義、結果、業務資料分開

資料層 保存什麼 不代表什麼
定義 下次執行的案例與設定 不包含某次實際回應或最後一次結果
執行結果 每次 Run 的狀態、時間、設定記錄與步驟證據 Run FINISHED 不等於全部 Case PASSED
測試資料 _in 基準來源、受測表、_qa 預期資料及 SQL 操作結果 不是每個 Run 都有獨立副本;不是平台 schema 固定欄位
執行變數 環境設定與 RUN/CASE 暫存值 不是持久工作佇列,也不是環境隔離
產物 SQL 比對 JSON、報告與其他已上傳檔案 檔案路徑存在不等於檔案仍可下載

早上供同仁使用及半夜測試,使用同一套 EKS 環境和資料。時間分流本身沒有資料隔離、互斥或每次 Run 還原到同一資料狀態的保證。夜間固定會強制關閉,早上再次啟動後須能查到前一夜的線索;不因測試異常或 Run 尚未結束而持續保留執行環境。關閉時可能仍有 RUNNING 紀錄,須在早上核對最後回報。這是已確認需求,尚未驗證完整持久化及強制關閉實作;目前 17 張表未提供完整環境啟停生命週期欄位,不能將 Run 的完成狀態當作 EKS 已關閉的證據。

2 識別碼、hooks 與結果快照

2-1 必須保留每次執行的識別碼

層次 定義識別碼 當次結果識別碼 解讀方式
Suite suite_num run_suite_num 同一群組可出現在多次 Run
Case case_num run_case_num 同一 Case/hook 在同一 Run 也可能被呼叫多次
Step step_num run_step_num 指向本次呼叫的實際結果,不只指向可重用定義

例如 BeforeEach 會在每個一般 Case 前執行,因此不能將 (runNum, caseNum) 設為所有結果的唯一鍵。結果查詢應沿 run_num → run_suite_num → run_case_num → run_step_num 取得證據。重跑會新增結果,不把第一次失敗改成第二次成功。

2-2 設定記錄的界限

結果層 保存的設定 限制
Run plan_record、env_record、trigger_record 各物件序列化內容;不是全部定義在同一時間鎖定版本
RunSuite suite_record 不能推論報表所有名稱都只讀此欄
RunCase case_record hooks 重複呼叫會有多筆結果;部分例外欄位未保證填值
RunStep step_exec、step_name、step_type、step_order 能追查當時步驟設定,不能完整還原受測系統及外部資料

結果列在執行時仍會更新狀態、時間與回應。部分報告仍 JOIN 現行 Case/Step 名稱;修改定義後,舊報告所有顯示內容並不保證不變。因此不能宣稱現況是不可變快照或完整可重播系統。

3 一致性與防呆

規則 現況 應如何驗證/改善
Plan 選案 透過 qa_c006 關聯 Case 核對 (plan_num, case_num) 重複資料及是否有組合唯一約束
案例與步驟排序 case_order/step_order 決定執行順序 重複排序值、同時修改及完整清單保存需 round-trip 測試
Case 相依 依 depends_on 取相依 Case 的結果 現況只攔截查得的 FAILED,查詢未限定本次 Run/RunSuite;ERROR/未執行與跨 Run 影響須修正及驗證
hooks BEFORE_ALL、BEFORE_EACH、AFTER_EACH、AFTER_ALL 也都是 Case 不可另造固定一對一結果;after hooks 不因名稱就有 finally 清理保證
環境設定 qa_c012 以 env_num、config_key 表達 未確認組合唯一,重複鍵及敏感內容保存須核對
同步快照 各層執行時保存自己的設定 需要統一定義版本是改善提案,並非現況
RunSuite 狀態 存在 suite_status 欄位 目前新增 RunSuite 段未填此欄,不能用欄位存在推論完整狀態流
比對輸出 現行兩類 SQL handler 保存 JSON 產物 qa_r001 報表資料與檔案內容是否同步需獨立核對
執行產物 qa_u001 以 source_num 查詢檔案 查詢未限制 source_type;混用來源類型前先處理識別碰撞
EKS 停機 夜間固定強制關閉,早上啟動後查線索 關閉前持續保存關聯識別、最後狀態與錯誤;停機結果與證據可讀性分別驗證,不以 run_status=3 代替

完整組合欄位規則見 字典第 6 節,整合錯誤規格見 06 整合與交易時序。

4 索引與並行控制

4-1 索引候選

以下來自現行查詢模式,是待評估的索引設計,不是已部署清單。先查現有索引並使用測試環境的查詢計畫評估,避免重複建立。

用途 表 候選欄位順序 注意事項
公司內找專案 qa_c001 (com_num, project_code) 若要唯一,先清查重複與業務規則
群組案例排序 qa_c004 (suite_num, is_deleted, case_order) 同時考慮 category 篩選,勿直接宣稱排序值唯一
案例步驟排序 qa_c013 (case_num, step_order) 依案例讀完整步驟
計畫選案 qa_c006 (plan_num, case_num) 集合語意可考慮 Unique;目前未證實已部署
排程領取 qa_c007 (is_enabled, next_run_time) 索引只能加速查詢,不能防止兩個 worker 重複領取
單次結果階層 qa_c009/qa_c010/qa_c011 分別 (run_num)/(run_suite_num, case_num)/(run_case_num, step_order) 保留各層執行 PK,不以 case_num 覆蓋歷史結果
Run 清單與保留查詢 qa_c008 (project_num, create_at) 清理政策需另外確認,欄位存在不代表已排程清理
環境設定 qa_c012 (env_num, config_key) 唯一性需先核對實際資料
比對報表 qa_r001/qa_r002 (run_num, case_num, step_num)/(compare_num, row_num, column_name) 同一 hook/步驟多次執行的粒度需額外確認
產物查詢 qa_u001 (source_num);改善後評估 (source_type, source_num) 查詢條件與索引一起調整

4-2 現況與改善邊界

控制項目 已知現況 不可宣稱/後續設計
樂觀鎖 本範圍沒有通用 version 欄位及 compare-and-set 證據 新增版本檢查屬改善,現在仍須測試兩人同時編輯的覆寫風險
悲觀鎖 本範圍未確認使用 SELECT FOR UPDATE 領取排程或鎖環境 若要跨 worker 互斥,需設計持久領取與原子狀態轉移
Trigger 防重 現有流程依 triggerNum 使用快取旗標 不等於同環境不同 Trigger 互斥,也不等於持久佇列
狀態回寫 Run/Case/Step 分別寫入 程序中斷時可能只保存部分結果;不得把缺筆當通過
SQL 比對 JSON 讀取現有檔案、加入步驟結果後覆寫 同一 Run 的並行寫入可能競爭;目前未做壓力與故障測試
資料準備 PRE_SQL/SQL_TRANSFER 可修改測試資料 同環境其他使用者可能受影響;目前沒有每次 Run 的資料分區
重送冪等 有各層識別碼,但不等於所有寫 API 都去重 目標冪等合約見整合規格;不可盲目重送會有副作用的步驟

若後續建立環境使用權與固定版本,需新增相應模型及交易設計。這些提案不能填成目前資料庫已存在的表、欄位或狀態。

5 產物、報表與保留

5-1 現有產物與報表

SQL 比對 handler 目前將結果加入 SqlCompareReport_<runNum>.json。Crystal 同時保有 qa_r001/qa_r002 的寫入介面及報告查詢;兩套儲存的資料來源須分別驗證,不能假設每個新 Run 都自動填滿比對表。

Email 一般案例統計只包含已記錄的 NORMAL RunCase:PASSED 為通過,FAILED/ERROR 合併為失敗,其他狀態以餘數歸入略過。零案例現況回傳 100。必須另外核對原定案例與實際結果筆數,才能判斷測試是否完整。

5-2 固定強制關閉與隔日追查

已確認需求:夜間固定強制關閉,但要留下隔天早上啟動後可查的線索。 因此證據應在執行過程持續送出,不能只依靠正常完成、最後一個 after hook 或關閉時的 finally 才保存。

必須保留的線索 使用既有資料 目標保存與隔日檢查
本次執行範圍 run_num、trigger_num、plan_num、env_num 及既有設定記錄 可定位前一夜的 Run 與執行設定,不靠記憶體 RunContext
最後進度 run_status、run_start_time/run_end_time、run_suite_num、run_case_num、run_step_num 保留實際最後回報;沒有終態或結束時間就顯示未完成/待核對,不算通過
失敗原因 step_error、step_result、post_proc_resp、run_log 及執行日誌 以同一組 Run/Case/Step ID 串起線索;資料尚未回寫時,外部日誌應能補充時間與最後動作
已產生證據 qa_u001 的檔名、remote_file_path、來源識別及比對 JSON 關閉後檔案內容仍可讀;只有 metadata 不足以證明檔案已保存
關閉事件 環境控制與平台日誌中可關聯該夜間 Run 的時間、原因與結果 不新增虛構資料表欄位;需核對實際環境控制提供的紀錄

持久化是目標驗收條件,尚未證實部署已達成。 結果資料庫、日誌及產物必須位於不會隨本次執行容器/節點關閉而遺失的儲存;目前只有寫入邏輯及路徑資訊,尚未查驗磁碟掛載、外部儲存、最後寫入完成或停機後讀取。證據未確認保存是需告警與追查的缺口,不將它解讀為可以取消固定強制關閉。

強制關閉可能來不及更新終態。早上先查前一夜 RUNNING 或缺少結束時間的紀錄,對照最後步驟、日誌與關閉事件,再依實際結果補註中斷原因;不能直接把所有殘留 RUNNING 判成正常完成。狀態整理是目標流程,尚未證實已有自動 reconciliation。保留原本結果與狀態修正線索;人工重跑另建新 Run,不用新結果覆寫前一夜的失敗或不完整證據。

5-3 保留政策

結果與產物保留期限若採既有需求的 90 天,應包含關聯結果、比對明細及檔案清理策略;目前未證實排程清理已實作。本文件不執行刪除,清理前應先驗證保留期間及下游引用。

6 DBA 唯讀核對

本次沒有連線查詢實際資料庫。以下 PostgreSQL metadata 查詢可用於確認測試環境的部署事實;不需讀取 config_value 或實際案例內容。

6-1 欄位與實體型別

SELECT table_name, ordinal_position, column_name,
       data_type, udt_name, character_maximum_length,
       numeric_precision, numeric_scale, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'qa'
  AND table_name IN ('qa_c001','qa_c002','qa_c003','qa_c004','qa_c005',
                     'qa_c006','qa_c007','qa_c008','qa_c009','qa_c010',
                     'qa_c011','qa_c012','qa_c013','qa_r001','qa_r002',
                     'qa_u001','qa_z000')
ORDER BY table_name, ordinal_position;

6-2 完整約束與索引

SELECT t.relname AS table_name, c.conname, c.contype,
       pg_get_constraintdef(c.oid) AS definition
FROM pg_constraint c
JOIN pg_class t ON t.oid = c.conrelid
JOIN pg_namespace n ON n.oid = t.relnamespace
WHERE n.nspname = 'qa'
  AND t.relname IN ('qa_c001','qa_c002','qa_c003','qa_c004','qa_c005',
                    'qa_c006','qa_c007','qa_c008','qa_c009','qa_c010',
                    'qa_c011','qa_c012','qa_c013','qa_r001','qa_r002',
                    'qa_u001','qa_z000')
ORDER BY t.relname, c.conname;

SELECT tablename, indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'qa'
  AND tablename IN ('qa_c001','qa_c002','qa_c003','qa_c004','qa_c005',
                    'qa_c006','qa_c007','qa_c008','qa_c009','qa_c010',
                    'qa_c011','qa_c012','qa_c013','qa_r001','qa_r002',
                    'qa_u001','qa_z000')
ORDER BY tablename, indexname;

6-3 組合鍵重複檢查

SELECT plan_num, case_num, count(*) AS duplicate_count
FROM qa.qa_c006
GROUP BY plan_num, case_num
HAVING count(*) > 1;

SELECT env_num, config_key, count(*) AS duplicate_count
FROM qa.qa_c012
GROUP BY env_num, config_key
HAVING count(*) > 1;

不要對 RunCase 執行 (runNum, caseNum) 去重:BeforeEach/AfterEach 的重複結果可能是正確紀錄。物理約束、資料完整性與並行寫入尚待實測,驗收方式見 08 UAT 與驗證。