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

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

Issue 1705943002: TaskScheduler [5/9] Task Tracker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s_3_pq
Patch Set: CR gab #19 Created 4 years, 9 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/task_tracker.h"
6
7 #include <queue>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task_scheduler/task.h"
15 #include "base/task_scheduler/task_traits.h"
16 #include "base/threading/platform_thread.h"
17 #include "base/threading/simple_thread.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace base {
21 namespace internal {
22
23 namespace {
24
25 class ThreadCallingShutdown : public SimpleThread {
26 public:
27 explicit ThreadCallingShutdown(TaskTracker* tracker)
28 : SimpleThread("ThreadCallingShutdown"), tracker_(tracker) {}
29
30 // Returns true once the call to Shutdown() has returned.
31 bool has_returned() const { return has_returned_; }
32
33 private:
34 void Run() override {
35 tracker_->Shutdown();
36 has_returned_ = true;
37 }
38
39 TaskTracker* const tracker_;
40 bool has_returned_ = false;
41
42 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown);
43 };
44
45 class TaskSchedulerTaskTrackerTest
46 : public testing::TestWithParam<TaskShutdownBehavior> {
47 public:
48 TaskSchedulerTaskTrackerTest() = default;
49
50 void RunNextPostedTaskViaTracker() {
51 ASSERT_FALSE(posted_tasks_.empty());
52 tracker_.RunTask(posted_tasks_.front().get());
53 posted_tasks_.pop();
54 }
55
56 protected:
57 // Creates a task with |shutdown_behavior|.
58 scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) {
59 return make_scoped_ptr(new Task(
60 FROM_HERE,
61 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)),
62 TaskTraits().WithShutdownBehavior(shutdown_behavior)));
63 }
64
65 // Tries to post |task| via |tracker_|. If |tracker_| approves the operation,
66 // |task| is added to |posted_tasks_|.
67 void PostTaskViaTracker(scoped_ptr<Task> task) {
68 tracker_.PostTask(
69 Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, Unretained(this)),
70 std::move(task));
71 }
72
73 // Calls tracker_->Shutdown() on a new thread. When this returns, the
74 // Shutdown() method has been entered on the new thread, but it hasn't
75 // necessarily returned.
76 void CallShutdownAsync() {
77 DCHECK(!thread_calling_shutdown_.get());
78 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_));
79 thread_calling_shutdown_->Start();
80 while (!tracker_.is_shutting_down_for_testing() &&
81 !tracker_.shutdown_completed()) {
82 PlatformThread::YieldCurrentThread();
83 }
84 }
85
86 void WaitForAsyncShutdownCompleted() {
87 DCHECK(thread_calling_shutdown_.get());
88 thread_calling_shutdown_->Join();
89 EXPECT_TRUE(thread_calling_shutdown_->has_returned());
90 EXPECT_TRUE(tracker_.shutdown_completed());
91 }
92
93 void VerifyAsyncShutdownInProgress() {
94 DCHECK(thread_calling_shutdown_.get());
95 EXPECT_FALSE(thread_calling_shutdown_->has_returned());
96 EXPECT_FALSE(tracker_.shutdown_completed());
97 EXPECT_TRUE(tracker_.is_shutting_down_for_testing());
98 }
99
100 TaskTracker tracker_;
101 size_t num_tasks_executed_ = 0;
102 std::queue<scoped_ptr<Task>> posted_tasks_;
103
104 private:
105 void PostTaskCallback(scoped_ptr<Task> task) {
106 posted_tasks_.push(std::move(task));
107 }
108
109 void RunTaskCallback() { ++num_tasks_executed_; }
110
111 scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_;
112
113 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
114 };
115
116 // A thread which calls
117 // TaskSchedulerTaskTrackerTest::RunNextPostedTaskViaTracker() asynchronously.
118 class ThreadRunningNextPostedTask : public SimpleThread {
119 public:
120 explicit ThreadRunningNextPostedTask(TaskSchedulerTaskTrackerTest* test)
121 : SimpleThread("ThreadRunningNextPostedTask"), test_(test) {}
122
123 private:
124 void Run() override { test_->RunNextPostedTaskViaTracker(); }
125
126 TaskSchedulerTaskTrackerTest* const test_;
127
128 DISALLOW_COPY_AND_ASSIGN(ThreadRunningNextPostedTask);
129 };
130
131 } // namespace
132
133 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown) {
134 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
135 const Task* task_to_post_raw = task_to_post.get();
136
137 // Post the task.
138 EXPECT_TRUE(posted_tasks_.empty());
139 PostTaskViaTracker(std::move(task_to_post));
140 ASSERT_EQ(1, posted_tasks_.size());
gab 2016/03/17 01:42:12 1U (prefer explicitly unsigned constants to compar
fdoray 2016/03/17 20:12:16 Done.
141 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
142
143 // Run the posted task.
144 EXPECT_EQ(0U, num_tasks_executed_);
145 RunNextPostedTaskViaTracker();
146 EXPECT_EQ(1U, num_tasks_executed_);
147
148 // Shutdown() shouldn't block.
149 tracker_.Shutdown();
150 }
151
152 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunLongTaskBeforeShutdown) {
153 // Post a task that will block until |event| is signaled.
154 EXPECT_TRUE(posted_tasks_.empty());
155 WaitableEvent event(false, false);
156 PostTaskViaTracker(make_scoped_ptr(
157 new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
158 TaskTraits().WithShutdownBehavior(GetParam()))));
159 ASSERT_EQ(1, posted_tasks_.size());
160
161 // Run the task asynchronouly.
162 ThreadRunningNextPostedTask thread(this);
163 thread.Start();
164
165 // Initiate shutdown while the task is running.
166 CallShutdownAsync();
167
168 if (GetParam() == TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) {
169 // Shutdown should complete even with a CONTINUE_ON_SHUTDOWN in progress.
170 WaitForAsyncShutdownCompleted();
171 } else {
172 // Shutdown should block with any non CONTINUE_ON_SHUTDOWN task in progress.
173 VerifyAsyncShutdownInProgress();
174 }
175
176 // Unblock the task.
177 event.Signal();
178 thread.Join();
179
180 if (GetParam() != TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)
181 WaitForAsyncShutdownCompleted();
182 }
183
184 TEST_P(TaskSchedulerTaskTrackerTest, PostBeforeShutdownRunDuringShutdown) {
185 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
186 const Task* task_to_post_raw = task_to_post.get();
187
188 // Post the task.
189 EXPECT_TRUE(posted_tasks_.empty());
190 PostTaskViaTracker(std::move(task_to_post));
191 ASSERT_EQ(1, posted_tasks_.size());
192 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
193
194 // Post a BLOCK_SHUTDOWN task just to block shutdown.
195 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
196
197 // Call Shutdown() asynchronously.
198 CallShutdownAsync();
199 VerifyAsyncShutdownInProgress();
200
201 // Try to run task posted at the beginning of this test. It should only
202 // succeed for a BLOCK_SHUTDOWN task.
gab 2016/03/17 01:42:13 s/It should only succeed for a BLOCK_SHUTDOWN task
fdoray 2016/03/17 20:12:16 Done.
203 EXPECT_EQ(0U, num_tasks_executed_);
204 RunNextPostedTaskViaTracker();
205 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 1U : 0U,
206 num_tasks_executed_);
207 VerifyAsyncShutdownInProgress();
208
209 // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task.
210 RunNextPostedTaskViaTracker();
211 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U,
212 num_tasks_executed_);
213 WaitForAsyncShutdownCompleted();
214 }
215
216 TEST_P(TaskSchedulerTaskTrackerTest, PostBeforeShutdownRunAfterShutdown) {
217 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
218 const Task* task_to_post_raw = task_to_post.get();
219
220 // Post the task.
221 EXPECT_TRUE(posted_tasks_.empty());
222 PostTaskViaTracker(std::move(task_to_post));
223 ASSERT_EQ(1, posted_tasks_.size());
224 ASSERT_EQ(task_to_post_raw, posted_tasks_.front().get());
225
226 // Call Shutdown() asynchronously.
227 CallShutdownAsync();
228 EXPECT_EQ(0U, num_tasks_executed_);
229
230 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
231 VerifyAsyncShutdownInProgress();
232
233 // Run the task to unblock shutdown.
234 RunNextPostedTaskViaTracker();
235 EXPECT_EQ(1U, num_tasks_executed_);
236 WaitForAsyncShutdownCompleted();
237
238 // Running a BLOCK_SHUTDOWN task after shutdown should fail.
239 if (DCHECK_IS_ON()) {
240 EXPECT_DEATH(
gab 2016/03/17 01:42:13 Use EXPECT_DCHECK_DEATH macro from Rob's Scheduler
fdoray 2016/03/17 20:12:16 Done.
241 {
242 tracker_.RunTask(
243 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN).get());
gab 2016/03/17 01:42:12 Since that task was never posted to the tracker, i
fdoray 2016/03/17 20:12:16 There is no way to test running after shutdown a B
244 },
245 "");
246 }
247 } else {
248 WaitForAsyncShutdownCompleted();
249
250 // The task shouldn't be allowed to run after shutdown.
251 RunNextPostedTaskViaTracker();
252 EXPECT_EQ(0U, num_tasks_executed_);
253 }
254 }
255
256 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown) {
257 // Post a BLOCK_SHUTDOWN task just to block shutdown.
258 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
259 scoped_ptr<Task> block_shutdown_task = std::move(posted_tasks_.front());
260 posted_tasks_.pop();
261
262 // Call Shutdown() asynchronously.
263 CallShutdownAsync();
264 VerifyAsyncShutdownInProgress();
265
266 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
267 // Post a task. This should succeed.
268 EXPECT_TRUE(posted_tasks_.empty());
269 PostTaskViaTracker(CreateTask(GetParam()));
270 EXPECT_EQ(1U, posted_tasks_.size());
271
272 // Run the task. This should succeed.
273 EXPECT_EQ(0U, num_tasks_executed_);
274 RunNextPostedTaskViaTracker();
275 EXPECT_EQ(1U, num_tasks_executed_);
276 } else {
277 // It shouldn't be possible to post a task which isn't BLOCK_SHUTDOWN.
278 PostTaskViaTracker(CreateTask(GetParam()));
279 EXPECT_TRUE(posted_tasks_.empty());
280
281 // Don't try to run the task, because it hasn't been posted successfully.
282 }
283
284 // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning
285 // of the test.
286 VerifyAsyncShutdownInProgress();
287 tracker_.RunTask(block_shutdown_task.get());
288 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U,
289 num_tasks_executed_);
290 WaitForAsyncShutdownCompleted();
291 }
292
293 TEST_P(TaskSchedulerTaskTrackerTest, PostAfterShutdown) {
294 // It is not possible to post a task after shutdown.
295 tracker_.Shutdown();
296 EXPECT_TRUE(posted_tasks_.empty());
297 PostTaskViaTracker(CreateTask(GetParam()));
298 EXPECT_TRUE(posted_tasks_.empty());
299 }
300
301 INSTANTIATE_TEST_CASE_P(
302 ContinueOnShutdown,
303 TaskSchedulerTaskTrackerTest,
304 ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
305 INSTANTIATE_TEST_CASE_P(
306 SkipOnShutdown,
307 TaskSchedulerTaskTrackerTest,
308 ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
309 INSTANTIATE_TEST_CASE_P(
310 BlockShutdown,
311 TaskSchedulerTaskTrackerTest,
312 ::testing::Values(TaskShutdownBehavior::BLOCK_SHUTDOWN));
313
314 } // namespace internal
315 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698