1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "platform/test/fake_task_runner.h" 6 7 #include <utility> 8 9 #include "util/osp_logging.h" 10 11 namespace openscreen { 12 FakeTaskRunner(FakeClock * clock)13FakeTaskRunner::FakeTaskRunner(FakeClock* clock) : clock_(clock) { 14 OSP_CHECK(clock_); 15 clock_->SubscribeToTimeChanges(this); 16 } 17 ~FakeTaskRunner()18FakeTaskRunner::~FakeTaskRunner() { 19 clock_->UnsubscribeFromTimeChanges(this); 20 } 21 RunTasksUntilIdle()22void FakeTaskRunner::RunTasksUntilIdle() { 23 // If there is bad code that posts tasks indefinitely, this loop will never 24 // break. However, that also means there is a code path spinning a CPU core at 25 // 100% all the time. Rather than mitigate this problem scenario, purposely 26 // let it manifest here in the hopes that unit testing will reveal it (e.g., a 27 // unit test that never finishes running). 28 for (;;) { 29 const auto current_time = FakeClock::now(); 30 const auto end_of_range = delayed_tasks_.upper_bound(current_time); 31 for (auto it = delayed_tasks_.begin(); it != end_of_range; ++it) { 32 ready_to_run_tasks_.push_back(std::move(it->second)); 33 } 34 delayed_tasks_.erase(delayed_tasks_.begin(), end_of_range); 35 36 if (ready_to_run_tasks_.empty()) { 37 break; 38 } 39 40 std::vector<Task> running_tasks; 41 running_tasks.swap(ready_to_run_tasks_); 42 for (Task& running_task : running_tasks) { 43 // Move the task out of the vector and onto the stack so that it destroys 44 // just after being run. This helps catch "dangling reference/pointer" 45 // bugs. 46 Task task = std::move(running_task); 47 task(); 48 } 49 } 50 } 51 PostPackagedTask(Task task)52void FakeTaskRunner::PostPackagedTask(Task task) { 53 ready_to_run_tasks_.push_back(std::move(task)); 54 } 55 PostPackagedTaskWithDelay(Task task,Clock::duration delay)56void FakeTaskRunner::PostPackagedTaskWithDelay(Task task, 57 Clock::duration delay) { 58 delayed_tasks_.emplace( 59 std::make_pair(FakeClock::now() + delay, std::move(task))); 60 } 61 IsRunningOnTaskRunner()62bool FakeTaskRunner::IsRunningOnTaskRunner() { 63 return true; 64 } 65 GetResumeTime() const66Clock::time_point FakeTaskRunner::GetResumeTime() const { 67 if (!ready_to_run_tasks_.empty()) { 68 return FakeClock::now(); 69 } 70 if (!delayed_tasks_.empty()) { 71 return delayed_tasks_.begin()->first; 72 } 73 return Clock::time_point::max(); 74 } 75 76 } // namespace openscreen 77