Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(531)

Side by Side Diff: base/task_scheduler/scheduler_service_thread_unittest.cc

Issue 2405243003: TaskScheduler: Replace the SchedulerServiceThread with a base::Thread. (Closed)
Patch Set: CR robliao #9 Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698