在管線中做日期測試
視窗用來探索,這裡是另一半:一個約 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 位元兩種建置上針對真實應用程式逐一驗證。