Chrono Mock
語言繁體中文

Windows 版 libfaketime

簡短的回答:libfaketime 不能在 Windows 上執行,也不可能——它建立在 LD_PRELOAD 之上,而 Windows 沒有這個東西。Chrono Mock 是同樣的想法,只是依 Windows 允許的方式來實作。

為什麼不能直接移植

libfaketime 的運作方式,是讓動態載入器把一個小型程式庫放在 C 程式庫的前面,於是程式對 time() 的呼叫會先到達替代版本。這個掛鉤在 Linux 上是 LD_PRELOAD,在 macOS 上是 DYLD_INSERT_LIBRARIES。它自己的 README 列出的正是這兩個平台。

Windows 沒有對等的機制,而且它的時鐘本來也不是只在某一個函式後面。應用程式透過 Win32 API、透過它下面的原生 API,以及透過執行階段對這兩者的各種封裝來讀取時間——所以這個想法在 Windows 上的版本,是一個注入到目標處理序中的程式庫,重新導向的是一組匯出函式,而不是一個符號。

參數對照

libfaketimeChrono Mock
FAKETIME="2020-12-24 20:30:00" --at 2020-12-24T20:30:00
FAKETIME="+14d" --at +14d
FAKETIME="-10m" --at -10m
FAKETIME="+0 x2" --mode x2
FAKETIME_DONT_FAKE_MONOTONIC=1 這裡的預設行為——見下文
LD_PRELOAD=libfaketime.so.1 無需設定——工具自行注入

所以,同一個測試的兩種寫法如下:

# Linux
FAKETIME="2020-12-24 20:30:00" LD_PRELOAD=/usr/local/lib/libfaketime.so.1 ./test

# Windows
chrono run "C:\apps\test.exe" --at 2020-12-24T20:30:00

兩者真正不同的地方

單調時鐘的處理是反過來的。libfaketime 預設會偽造它們,並提供 FAKETIME_DONT_FAKE_MONOTONIC 來停止。這裡的高解析度計數器預設保持真實,因為在測試中縮放它會讓畫面轉譯不穩定,需要用 --scale-qpc 來啟用。正是這個開關,讓 Python 3.13+ 的 monotonic、.NET 的 Stopwatch 與 Java 的 nanoTime 跟隨工作階段時鐘。

Windows 上可攔截的地方更多。除了掛鐘時間,還有時區、經過時間軸、四類計時器、睡眠與等待函式,以及處理序建立——總共 44 個通道。 其中 30 個被偏移,其餘 14 個(包括網路連線)只計數。

這個工具會回報自己的涵蓋情況。每次工作階段都以一個判定、應用程式實際讀取過的通道及各自的次數,以及被遺漏的通道結束。這是兩個平台上都沒有對應物的部分。

libfaketime 更資深,在它自己的領域裡也更全面。它有多年的使用經驗,涵蓋了 C 程式庫中範圍廣泛的進入點,在 Linux 上它是正確的工具。這裡的任何東西都不會在那裡取代它。

如果你真正想要的是 libfaketime 本身

有兩條實在的路,兩者都是把受測程式挪到 Linux 上:

  • WSL——在 Linux 子系統裡建置並執行 libfaketime。如果受測的是一個恰好在 Windows 上開發的 Linux 程式,這就很合適。
  • 容器——想法相同,可重現性更好。

兩者對 Windows 應用程式都沒有幫助,而這正是這個工具存在的理由。

親自試試