Chrono Mock
言語日本語

Windows 向けの libfaketime

短く答えると: libfaketime は Windows では動きませんし、動かせません。Windows にはない LD_PRELOAD の上に作られているからです。Chrono Mock は、同じ発想を Windows で可能な方法で作ったものです。

単純に移植できない理由

libfaketime は、ダイナミックローダーに C ライブラリの前に小さなライブラリを置かせることで動きます。これにより、プログラムの time() 呼び出しが先に置き換え側に届きます。そのフックが、Linux では LD_PRELOAD、macOS では DYLD_INSERT_LIBRARIES です。README に挙げられているのも、まさにこの 2 つのプラットフォームです。

Windows には同等のものがなく、そもそも Windows の時計は 1 つの関数の背後にあるわけでもありません。アプリは Win32 API、その下のネイティブ API、そしてそのどちらかをランタイムがラップしたものを通じて時刻を読みます。したがって、この発想の Windows 版は、1 つのシンボルではなく、エクスポートされた一連の関数をリダイレクトする、対象プロセスにインジェクトされたライブラリになります。

フラグの対応表

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 にはフックすべき場所がもっとあります。壁時計のほかに、タイムゾーン、経過時間の軸、4 系統のタイマー、スリープと待機の関数、プロセス作成があり、合計 44 チャネルです。 そのうち 30 はずらし、ネットワーク接続を含む残りの 14 は数えるだけです。

こちらは自分自身のカバレッジを報告します。すべてのセッションは、判定、アプリが実際に読んだチャネルとそれぞれの回数、取りこぼしたチャネルで終わります。どちらのプラットフォームにも同等のもののない部分です。

libfaketime は古く、自分の領域ではより幅広いです。長年の利用実績があり、C ライブラリの幅広いエントリポイントをカバーしていて、Linux では適切なツールです。ここにあるものがそれに取って代わることはありません。

本物の libfaketime が必要な場合

正直な方法は 2 つあり、どちらもテスト対象のプログラムを Linux に移します。

  • WSL - Linux サブシステム内で libfaketime をビルドして実行します。テストしているのが、たまたま Windows 上で開発している Linux プログラムなら問題ありません。
  • コンテナー - 同じ考え方で、再現性がより高くなります。

どちらも Windows アプリの役には立ちません。このツールはまさにそのケースのために存在します。

試してみる