---
# System prepended metadata

title: Mock Time in TaskEnvironment
tags: [Chromium-General, elkurin-daily-note]

---

# Mock Time in TaskEnvironment

以前[TaskEnvironment](https://github.com/elkurin/elkurin-daily-notes/blob/main/docs/day29.md)について読んだことがある。  
これはテスト中にPostTaskなどをできるようにするためのセッティングをラップしているクラス。  
この中で「時間」がどう扱われているかを確認する。

## MOCK_TIME
[TaskEnvironment](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.h;l=204;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)のコンストラクタでいろんなtraitsを指定できる。  
その中に[TimeSource](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.h;l=100;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)というenumがある。  
デフォルトは[SYSTEM_TIME](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.h;l=102;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)に指定されており、一方[MOCK_TIME](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.h;l=121;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)というのもある。  
こいつらは何かというと、DelayedTaskをどのタイミングで走らせるかが変わってくる。  
[PostDelayedTask](https://source.chromium.org/chromium/chromium/src/+/main:base/task/task_runner.h;l=73;drc=915d2556484c2d799cdc79d3df0a312834a04482)を投げると、指定した`delay`の時間だけ待ってからタスクを走らせることができるが、その際の時計を指定しているのがTimeSource。SYSTEM_TIMEなら実際の時間を使用するproducetion挙動と同じになるが、MOCK＿TIMEの場合、時間を操作することができる。race conditionのテストを書くときとかに便利そう。

もしMOCK_TIMEで初期化されると[`mock_time_domain_`](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.h;l=489;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)がセットされる(SYSTEM_TIMEの場合nullptr)。  
これが時間をMockするヘルパークラスになる。

このMock Timeを使用したテストは例えば[ProxyManagerTest](https://source.chromium.org/chromium/chromium/src/+/main:chrome/services/cups_proxy/proxy_manager_unittest.cc;l=30;drc=e672a665ffa8fe4901184f03922e2cc548399da5)で確認できる。  
ここではFastForwardByを呼ぶことで擬似的に時間を勧めている。

## Mock Time Domain
[MockTimeDomain](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=189;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)は時計の動きを操作できるAPIを持っている。  

[NowTicks](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=271;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)は`now_ticks_`という時間を返すが、これは最初はTime::Now()から始まるものの勝手には進まない。  
[AdvanceClock](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=218;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)を呼ぶと`delta`分時間が進む。  
あるいは[FastForwardToNextTaskOrCap](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=312;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)を呼ぶと、次のタスクが走る時間orキャップの時間まで進む。  
次のタスクの時間は[ThreadPool::NextScheduledRunTimeForTesting](https://source.chromium.org/chromium/chromium/src/+/main:base/task/thread_pool/thread_pool_impl.cc;l=320;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)から取得することができる。[DelayedTaskManager::NextScheduledRunTime](https://source.chromium.org/chromium/chromium/src/+/main:base/task/thread_pool/delayed_task_manager.cc;l=165;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)が帰ってくる。  
このnext task timeがキャップより小さければ、[AdvanceTimesToNextTaskTimeOrCap](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=294;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)で`now_ticks_`を更新。そして[DelayedTaskManager::ProcessRipeTasks](https://source.chromium.org/chromium/chromium/src/+/main:base/task/thread_pool/thread_pool_impl.cc;l=327;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)を呼びNowTicksまでに走るべきqueueされたtaskたちをdelayed taskたちを[Run](https://source.chromium.org/chromium/chromium/src/+/main:base/task/thread_pool/delayed_task_manager.cc;l=161;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)する。

## 時を進める
先のセクションでは内部実装としてどうやって時間が管理されているかの話だった。  
ではTaskEnvironmentを使うテスト側はどうやって時間を制御できるかを確認する。

[FastForwardBy](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=788;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)をTaskEnvironmentに対して呼ぶと、時が進む。  
```cpp=
const TimeTicks fast_forward_until = mock_time_domain_->NowTicks() + delta;
do {
  RunUntilIdle();
  // ReclaimMemory sweeps canceled delayed tasks, making sure
  // FastForwardToNextTaskOrCap isn't affected by canceled tasks.
  sequence_manager_->ReclaimMemory();
} while (mock_time_domain_->FastForwardToNextTaskOrCap(
             sequence_manager_->GetNextDelayedWakeUp(), fast_forward_until,
             advance_live_ticks) != MockTimeDomain::NextTaskSource::kNone);

if (task_tracker_ && !could_run_tasks) {
  task_tracker_->DisallowRunTasks();
}
```
すでに定義されている`mock_time_domain_`に対し、先のセクションで紹介した[FastForwardToNextTaskOrCap](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=312;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)が呼ばれている。  
[GetNextDelayedWakeUp](https://source.chromium.org/chromium/chromium/src/+/main:base/task/sequence_manager/sequence_manager.h;l=250;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)は直近のdelayed taskの時間を獲得する。

他にも[AdvanceClock](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=825;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)で直接時計を動かすこともできる。これもMockTimeDomainの[AdvanceClock](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=218;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)を呼ぶ。

[NextMainThreadPendingTaskDelay](https://source.chromium.org/chromium/chromium/src/+/main:base/test/task_environment.cc;l=867;drc=54b5f6dcc0e51751aec186771b4012ef663b538b)はテスト側が次のタスクの時間を知りたいときに教えてくれるAPI.