test_task_runner: Implement AdvanceTimeAndRunUntilIdle()

This is useful to fake time in tests, to quickly simulate long timeouts.

It requires touching the UnixTaskRunner implementation.

Change-Id: I53eb71a90194abecc7008342601711124b8889cb
diff --git a/include/perfetto/ext/base/unix_task_runner.h b/include/perfetto/ext/base/unix_task_runner.h
index ecde733..9ca6638 100644
--- a/include/perfetto/ext/base/unix_task_runner.h
+++ b/include/perfetto/ext/base/unix_task_runner.h
@@ -69,6 +69,10 @@
   // delayed tasks don't count even if they are due to run.
   bool IsIdleForTesting();
 
+  // Pretends (for the purposes of running delayed tasks) that time advanced by
+  // `ms`.
+  void AdvanceTimeForTesting(uint32_t ms);
+
   // TaskRunner implementation:
   void PostTask(std::function<void()>) override;
   void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
@@ -108,6 +112,7 @@
   std::deque<std::function<void()>> immediate_tasks_;
   std::multimap<TimeMillis, std::function<void()>> delayed_tasks_;
   bool quit_ = false;
+  TimeMillis advanced_time_for_testing_ = TimeMillis(0);
 
   struct WatchTask {
     std::function<void()> callback;
diff --git a/src/base/test/test_task_runner.cc b/src/base/test/test_task_runner.cc
index 3576996..51d6d52 100644
--- a/src/base/test/test_task_runner.cc
+++ b/src/base/test/test_task_runner.cc
@@ -88,6 +88,14 @@
   };
 }
 
+void TestTaskRunner::AdvanceTimeAndRunUntilIdle(uint32_t ms) {
+  PERFETTO_DCHECK_THREAD(thread_checker_);
+  task_runner_.PostDelayedTask(std::bind(&TestTaskRunner::QuitIfIdle, this),
+                               ms);
+  task_runner_.AdvanceTimeForTesting(ms);
+  task_runner_.Run();
+}
+
 // TaskRunner implementation.
 void TestTaskRunner::PostTask(std::function<void()> closure) {
   task_runner_.PostTask(std::move(closure));
diff --git a/src/base/test/test_task_runner.h b/src/base/test/test_task_runner.h
index a7c5784..142970d 100644
--- a/src/base/test/test_task_runner.h
+++ b/src/base/test/test_task_runner.h
@@ -42,6 +42,10 @@
   void RunUntilCheckpoint(const std::string& checkpoint,
                           uint32_t timeout_ms = 5000);
 
+  // Pretends (for the purposes of running delayed tasks) that time advanced by
+  // `ms`. Run until then.
+  void AdvanceTimeAndRunUntilIdle(uint32_t ms);
+
   // TaskRunner implementation.
   void PostTask(std::function<void()> closure) override;
   void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
diff --git a/src/base/unix_task_runner.cc b/src/base/unix_task_runner.cc
index ba2828f..4288f20 100644
--- a/src/base/unix_task_runner.cc
+++ b/src/base/unix_task_runner.cc
@@ -108,6 +108,11 @@
   return immediate_tasks_.empty();
 }
 
+void UnixTaskRunner::AdvanceTimeForTesting(uint32_t ms) {
+  std::lock_guard<std::mutex> lock(lock_);
+  advanced_time_for_testing_ += TimeMillis(ms);
+}
+
 void UnixTaskRunner::UpdateWatchTasksLocked() {
   PERFETTO_DCHECK_THREAD(thread_checker_);
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
@@ -142,7 +147,7 @@
     }
     if (!delayed_tasks_.empty()) {
       auto it = delayed_tasks_.begin();
-      if (now >= it->first) {
+      if (now + advanced_time_for_testing_ >= it->first) {
         delayed_task = std::move(it->second);
         delayed_tasks_.erase(it);
       }
@@ -242,7 +247,8 @@
   if (!immediate_tasks_.empty())
     return 0;
   if (!delayed_tasks_.empty()) {
-    TimeMillis diff = delayed_tasks_.begin()->first - GetWallTimeMs();
+    TimeMillis diff = delayed_tasks_.begin()->first - GetWallTimeMs() -
+                      advanced_time_for_testing_;
     return std::max(0, static_cast<int>(diff.count()));
   }
   return -1;
@@ -264,7 +270,8 @@
   TimeMillis runtime = GetWallTimeMs() + TimeMillis(delay_ms);
   {
     std::lock_guard<std::mutex> lock(lock_);
-    delayed_tasks_.insert(std::make_pair(runtime, std::move(task)));
+    delayed_tasks_.insert(
+        std::make_pair(runtime + advanced_time_for_testing_, std::move(task)));
   }
   WakeUp();
 }