Chrono Mock
語言繁體中文

在管線中做日期測試

視窗用來探索,這裡是另一半:一個約 2.4 MB 的命令列版本,無需安裝任何執行階段,它的結束代碼是涵蓋情況的判定,而不是目標程式自己的結束代碼。

結束代碼就是判定

這個設計決定讓該工具可以被指令碼呼叫。工作階段結束時,結束代碼回答的是「時間替換有沒有生效」,而不是「應用程式回傳了什麼」。因此,管線可以在替換悄悄沒有發生時直接失敗——這正是值得為之失敗的情形,因為它之後的一切都是什麼也沒證明的測試。

目標程式自己的結束代碼仍然會被回報,記錄在工作階段資料中。

代碼意義
0生效——所有讀取過時間的處理序看到的都是工作階段時鐘
10部分生效——部分通道已涵蓋,部分未涵蓋
11未生效——替換沒有到達關鍵通道
4無法確定——無法確認涵蓋情況
1用法錯誤——參數錯誤或運算式錯誤
2無法啟動目標程式,或無法對其注入
12目標程式消失了,這表示它可能是單一執行個體的應用程式
3內部錯誤——引擎無法啟動、遇到非預期的狀態,或在關閉工作階段之前就停止了(無論目標程式自己的結束代碼是什麼)。這樣的執行不帶判定
5此版本未內建該操作
6執行被中途截斷——--timeout 到期,或是引擎 15 秒沒有回應而被停止。這不是判定:工作階段被中斷了,因此對目標程式無論哪種情況都說明不了什麼
7已有另一個工作階段在執行,一次只能執行一個工作階段。等它結束後重試即可
8工作階段已得出判定,但證據沒有寫入 --report 指定的檔案:磁碟已滿,或另一個程式開著舊檔案,舊檔案因此保持不變。判定仍在命令輸出的報告中

兩個命令的所有參數,以及計算機對應的同一張表,都在命令列參考中。

限定時長的執行

管線不能等人去關閉一個桌面應用程式。--ticks N 會在 N 次心跳(每次一個真實秒)之後結束工作階段,並回報到那一刻為止的發現。涵蓋情況本來就是在處理序啟動的最初階段確定的,所以通常設一個較短的上限就夠了。

# 執行十秒,然後停止並回報
chrono run ".\build\test.exe" --preset year-rollover --ticks 10 --report evidence.txt

機器輸出與證據

  • --json 以機器可讀的記錄輸出工作階段,而不是給人讀的報告——事實完全相同,包括逐個通道的涵蓋情況。
  • --report <path> 把給人讀的報告寫入檔案,作為建置成品很合適。判定不是生效的工作階段,會在該檔案開頭放一條證據不可靠的橫幅,而不是把這個提醒埋在結尾。
  • 計算機同樣支援 --json,所以管線可以算出需要的日期,再把它傳回去使用。
# 先算出日期,再依該日期執行
chrono calc --base today --snap eom --json
chrono run ".\build\test.exe" --preset month-end --ticks 10 --json

一個步驟的大致寫法

- name: Month-end behaviour
  shell: pwsh
  run: |
    .\chrono.exe run ".\build\test.exe" --preset month-end --ticks 10 --report evidence.txt
    # 這裡結束代碼非零,表示替換沒有生效,所以
    # 它後面的測試什麼也證明不了

- name: Keep the evidence
  uses: actions/upload-artifact@v7
  with:
    name: chrono-evidence
    path: evidence.txt

關於執行器的兩點如實說明

  • 它需要 Windows 執行器。沒有 Linux 或 macOS 版本,以後也不會有——在 Linux 上,libfaketime 已經能勝任這件事。
  • 代管執行器上的防毒軟體可能會攔截注入。改變時間需要把一個程式庫注入目標處理序,這是一種有文件記載的 Windows 技術,惡意程式也在使用。被執行器攔截時,你得到的是說明此事的結束代碼,而不是一次虛假的通過——但這是你在依賴它之前就該弄清楚的事。

基於同樣的理由,本專案自己的端對端測試套件在真實機器上執行,而不是在代管執行器上。它的持續整合會建置並對所有內容做單元測試;至於替換本身,則在每次發行之前,由人工在 32 位元與 64 位元兩種建置上針對真實應用程式逐一驗證。

親自試試