| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "base/task_scheduler/scheduler_service_thread.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/location.h" | |
| 12 #include "base/macros.h" | |
| 13 #include "base/memory/ptr_util.h" | |
| 14 #include "base/memory/ref_counted.h" | |
| 15 #include "base/synchronization/waitable_event.h" | |
| 16 #include "base/task_scheduler/delayed_task_manager.h" | |
| 17 #include "base/task_scheduler/scheduler_worker_pool_impl.h" | |
| 18 #include "base/task_scheduler/scheduler_worker_pool_params.h" | |
| 19 #include "base/task_scheduler/sequence.h" | |
| 20 #include "base/task_scheduler/task.h" | |
| 21 #include "base/task_scheduler/task_tracker.h" | |
| 22 #include "base/task_scheduler/task_traits.h" | |
| 23 #include "base/time/time.h" | |
| 24 #include "testing/gtest/include/gtest/gtest.h" | |
| 25 | |
| 26 namespace base { | |
| 27 namespace internal { | |
| 28 namespace { | |
| 29 | |
| 30 // The goal of the tests here is to verify the behavior of the Service Thread. | |
| 31 // Some tests may be better part of DelayedTaskManager unit tests depending on | |
| 32 // the nature of the test. | |
| 33 // | |
| 34 // Timed waits are inherent in the service thread because one of its main | |
| 35 // purposes is to tell the delayed task manager when to post ready tasks. | |
| 36 // This also makes writing tests tricky since the goal isn't to test if | |
| 37 // WaitableEvent works but rather do the correct callbacks occur at the right | |
| 38 // time. | |
| 39 // | |
| 40 // As a result, there are a few assumptions that are made in the test: | |
| 41 // 1) Tests execute with balanced context switching. This means that there isn't | |
| 42 // an adversary that context switches test main thread for an extended period | |
| 43 // of time when the test main thread isn't waiting. | |
| 44 // 2) Time proceeds normally. Since timed waits determine how long the service | |
| 45 // thread will wait, and timed waits is currently not mockable, time needs to | |
| 46 // proceed in a forward fashion. If time is frozen (e.g. TimeTicks::Now() | |
| 47 // doesn't advance), some tests below may fail. | |
| 48 // 3) Short waits sufficiently cover longer waits. Having tests run quickly is | |
| 49 // desirable. Since the tests can't change the behavior of timed waiting, the | |
| 50 // delay durations should be reasonably short on the order of hundreds of | |
| 51 // milliseconds. | |
| 52 class TaskSchedulerServiceThreadTest : public testing::Test { | |
| 53 protected: | |
| 54 TaskSchedulerServiceThreadTest() : delayed_task_manager_(Bind(&DoNothing)) {} | |
| 55 | |
| 56 void SetUp() override { | |
| 57 scheduler_worker_pool_ = SchedulerWorkerPoolImpl::Create( | |
| 58 SchedulerWorkerPoolParams("TestWorkerPoolForSchedulerServiceThread", | |
| 59 ThreadPriority::BACKGROUND, | |
| 60 SchedulerWorkerPoolParams::IORestriction:: | |
| 61 DISALLOWED, | |
| 62 1u, | |
| 63 TimeDelta::Max()), | |
| 64 Bind(&ReEnqueueSequenceCallback), &task_tracker_, | |
| 65 &delayed_task_manager_); | |
| 66 ASSERT_TRUE(scheduler_worker_pool_); | |
| 67 service_thread_ = SchedulerServiceThread::Create( | |
| 68 &task_tracker_, &delayed_task_manager_); | |
| 69 ASSERT_TRUE(service_thread_); | |
| 70 } | |
| 71 | |
| 72 void TearDown() override { | |
| 73 scheduler_worker_pool_->JoinForTesting(); | |
| 74 service_thread_->JoinForTesting(); | |
| 75 } | |
| 76 | |
| 77 SchedulerServiceThread* service_thread() { | |
| 78 return service_thread_.get(); | |
| 79 } | |
| 80 | |
| 81 DelayedTaskManager& delayed_task_manager() { | |
| 82 return delayed_task_manager_; | |
| 83 } | |
| 84 | |
| 85 SchedulerWorkerPoolImpl* worker_pool() { | |
| 86 return scheduler_worker_pool_.get(); | |
| 87 } | |
| 88 | |
| 89 private: | |
| 90 static void ReEnqueueSequenceCallback(scoped_refptr<Sequence> sequence) { | |
| 91 ADD_FAILURE() << "This test only expects one task per sequence."; | |
| 92 } | |
| 93 | |
| 94 DelayedTaskManager delayed_task_manager_; | |
| 95 TaskTracker task_tracker_; | |
| 96 std::unique_ptr<SchedulerWorkerPoolImpl> scheduler_worker_pool_; | |
| 97 std::unique_ptr<SchedulerServiceThread> service_thread_; | |
| 98 | |
| 99 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerServiceThreadTest); | |
| 100 }; | |
| 101 | |
| 102 } // namespace | |
| 103 | |
| 104 // Tests that the service thread can handle a single delayed task. | |
| 105 TEST_F(TaskSchedulerServiceThreadTest, RunSingleDelayedTask) { | |
| 106 WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, | |
| 107 WaitableEvent::InitialState::NOT_SIGNALED); | |
| 108 delayed_task_manager().AddDelayedTask( | |
| 109 WrapUnique(new Task(FROM_HERE, | |
| 110 Bind(&WaitableEvent::Signal, Unretained(&event)), | |
| 111 TaskTraits(), TimeDelta::FromMilliseconds(100))), | |
| 112 make_scoped_refptr(new Sequence), nullptr, worker_pool()); | |
| 113 // Waking the service thread shouldn't cause the task to be executed per its | |
| 114 // delay not having expired (racy in theory, see test-fixture meta-comment). | |
| 115 service_thread()->WakeUp(); | |
| 116 // Yield to increase the likelihood of catching a bug where these tasks would | |
| 117 // be released before their delay is passed. | |
| 118 PlatformThread::YieldCurrentThread(); | |
| 119 EXPECT_FALSE(event.IsSignaled()); | |
| 120 // When the delay expires, the delayed task is posted, signaling |event|. | |
| 121 event.Wait(); | |
| 122 } | |
| 123 | |
| 124 // Tests that the service thread can handle more than one delayed task with | |
| 125 // different delays. | |
| 126 TEST_F(TaskSchedulerServiceThreadTest, RunMultipleDelayedTasks) { | |
| 127 const TimeTicks test_begin_time = TimeTicks::Now(); | |
| 128 const TimeDelta delay1 = TimeDelta::FromMilliseconds(100); | |
| 129 const TimeDelta delay2 = TimeDelta::FromMilliseconds(200); | |
| 130 | |
| 131 WaitableEvent event1(WaitableEvent::ResetPolicy::MANUAL, | |
| 132 WaitableEvent::InitialState::NOT_SIGNALED); | |
| 133 delayed_task_manager().AddDelayedTask( | |
| 134 WrapUnique(new Task(FROM_HERE, | |
| 135 Bind(&WaitableEvent::Signal, Unretained(&event1)), | |
| 136 TaskTraits(), delay1)), | |
| 137 make_scoped_refptr(new Sequence), nullptr, worker_pool()); | |
| 138 | |
| 139 WaitableEvent event2(WaitableEvent::ResetPolicy::MANUAL, | |
| 140 WaitableEvent::InitialState::NOT_SIGNALED); | |
| 141 delayed_task_manager().AddDelayedTask( | |
| 142 WrapUnique(new Task(FROM_HERE, | |
| 143 Bind(&WaitableEvent::Signal, Unretained(&event2)), | |
| 144 TaskTraits(), delay2)), | |
| 145 make_scoped_refptr(new Sequence), nullptr, worker_pool()); | |
| 146 | |
| 147 // Adding the task shouldn't have caused them to be executed. | |
| 148 EXPECT_FALSE(event1.IsSignaled()); | |
| 149 EXPECT_FALSE(event2.IsSignaled()); | |
| 150 | |
| 151 // Waking the service thread shouldn't cause the tasks to be executed per | |
| 152 // their delays not having expired (note: this is racy if the delay somehow | |
| 153 // expires before this runs but 100ms is a long time in a unittest...). It | |
| 154 // should instead cause the service thread to schedule itself for wakeup when | |
| 155 // |delay1| expires. | |
| 156 service_thread()->WakeUp(); | |
| 157 // Yield to increase the likelihood of catching a bug where these tasks would | |
| 158 // be released before their delay is passed. | |
| 159 PlatformThread::YieldCurrentThread(); | |
| 160 EXPECT_FALSE(event1.IsSignaled()); | |
| 161 EXPECT_FALSE(event2.IsSignaled()); | |
| 162 | |
| 163 // Confirm the above assumption about the evolution of time in the test. | |
| 164 EXPECT_LT(TimeTicks::Now() - test_begin_time, delay1); | |
| 165 | |
| 166 // Wait until |delay1| expires and service thread wakes up to schedule the | |
| 167 // first task, signalling |event1|. | |
| 168 event1.Wait(); | |
| 169 | |
| 170 // Only the first task should have been released. | |
| 171 EXPECT_TRUE(event1.IsSignaled()); | |
| 172 EXPECT_FALSE(event2.IsSignaled()); | |
| 173 | |
| 174 // At least |delay1| should have passed for |event1| to fire. | |
| 175 EXPECT_GE(TimeTicks::Now() - test_begin_time, delay1); | |
| 176 | |
| 177 // And assuming a sane test timeline |delay2| shouldn't have expired yet. | |
| 178 EXPECT_LT(TimeTicks::Now() - test_begin_time, delay2); | |
| 179 | |
| 180 // Now wait for the second task to be fired. | |
| 181 event2.Wait(); | |
| 182 | |
| 183 // Which should only have fired after |delay2| was expired. | |
| 184 EXPECT_GE(TimeTicks::Now() - test_begin_time, delay2); | |
| 185 } | |
| 186 | |
| 187 } // namespace internal | |
| 188 } // namespace base | |
| OLD | NEW |