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

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/asvitkine #31-35 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/task_scheduler/test_utils.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/threading/simple_thread.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace base {
22 namespace internal {
23
24 namespace {
25
26 // Calls TaskTracker::Shutdown() asynchronously.
27 class ThreadCallingShutdown : public SimpleThread {
28 public:
29 explicit ThreadCallingShutdown(TaskTracker* tracker)
30 : SimpleThread("ThreadCallingShutdown"),
31 tracker_(tracker),
32 has_returned_(true, false) {}
33
34 // Returns true once the async call to Shutdown() has returned.
35 bool has_returned() { return has_returned_.IsSignaled(); }
36
37 private:
38 void Run() override {
39 tracker_->Shutdown();
40 has_returned_.Signal();
41 }
42
43 TaskTracker* const tracker_;
44 WaitableEvent has_returned_;
45
46 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown);
47 };
48
49 // Runs a task asynchronously.
50 class ThreadRunningTask : public SimpleThread {
51 public:
52 explicit ThreadRunningTask(TaskTracker* tracker, const Task* task)
53 : SimpleThread("ThreadRunningTask"), tracker_(tracker), task_(task) {}
54
55 private:
56 void Run() override { tracker_->RunTask(task_); }
57
58 TaskTracker* const tracker_;
59 const Task* const task_;
60
61 DISALLOW_COPY_AND_ASSIGN(ThreadRunningTask);
62 };
63
64 class TaskSchedulerTaskTrackerTest
65 : public testing::TestWithParam<TaskShutdownBehavior> {
66 protected:
67 TaskSchedulerTaskTrackerTest() = default;
68
69 // Creates a task with |shutdown_behavior|.
70 scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) {
71 return make_scoped_ptr(new Task(
72 FROM_HERE,
73 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)),
74 TaskTraits().WithShutdownBehavior(shutdown_behavior)));
75 }
76
77 // Tries to post |task| via |tracker_|. If |tracker_| approves the operation,
78 // |task| is added to |posted_tasks_|.
79 void PostTaskViaTracker(scoped_ptr<Task> task) {
80 tracker_.PostTask(
81 Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, Unretained(this)),
82 std::move(task));
83 }
84
85 // Tries to run the next task in |posted_tasks_| via |tracker_|.
86 void RunNextPostedTaskViaTracker() {
87 ASSERT_FALSE(posted_tasks_.empty());
88 tracker_.RunTask(posted_tasks_.front().get());
89 posted_tasks_.pop();
90 }
91
92 // Calls tracker_->Shutdown() on a new thread. When this returns, Shutdown()
93 // method has been entered on the new thread, but it hasn't necessarily
94 // returned.
95 void CallShutdownAsync() {
96 ASSERT_FALSE(thread_calling_shutdown_);
97 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_));
98 thread_calling_shutdown_->Start();
99 while (!tracker_.IsShuttingDownForTesting() &&
100 !tracker_.shutdown_completed()) {
101 PlatformThread::YieldCurrentThread();
102 }
103 }
104
105 void WaitForAsyncShutdownCompleted() {
106 ASSERT_TRUE(thread_calling_shutdown_);
107 thread_calling_shutdown_->Join();
108 EXPECT_TRUE(thread_calling_shutdown_->has_returned());
109 EXPECT_TRUE(tracker_.shutdown_completed());
110 }
111
112 void VerifyAsyncShutdownInProgress() {
113 ASSERT_TRUE(thread_calling_shutdown_);
114 EXPECT_FALSE(thread_calling_shutdown_->has_returned());
115 EXPECT_FALSE(tracker_.shutdown_completed());
116 EXPECT_TRUE(tracker_.IsShuttingDownForTesting());
117 }
118
119 TaskTracker tracker_;
120 size_t num_tasks_executed_ = 0;
121 std::queue<scoped_ptr<Task>> posted_tasks_;
122
123 private:
124 void PostTaskCallback(scoped_ptr<Task> task) {
125 posted_tasks_.push(std::move(task));
126 }
127
128 void RunTaskCallback() { ++num_tasks_executed_; }
129
130 scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_;
131
132 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
133 };
134
135 #define WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED() \
136 do { \
137 SCOPED_TRACE(""); \
138 WaitForAsyncShutdownCompleted(); \
139 } while (false)
140
141 #define VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS() \
142 do { \
143 SCOPED_TRACE(""); \
gab 2016/03/21 19:53:25 What's the purpose of having this in a macro?
fdoray 2016/03/22 20:19:43 With this macro, the line number of the call to VE
144 VerifyAsyncShutdownInProgress(); \
145 } while (false)
146
147 } // namespace
148
149 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown) {
150 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
151 const Task* task_to_post_raw = task_to_post.get();
152
153 // Post the task.
154 EXPECT_TRUE(posted_tasks_.empty());
155 PostTaskViaTracker(std::move(task_to_post));
156 EXPECT_EQ(1U, posted_tasks_.size());
157 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
158
159 // Run the posted task.
160 EXPECT_EQ(0U, num_tasks_executed_);
161 RunNextPostedTaskViaTracker();
162 EXPECT_EQ(1U, num_tasks_executed_);
163
164 // Shutdown() shouldn't block.
165 tracker_.Shutdown();
166 }
167
168 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunLongTaskBeforeShutdown) {
169 // Post a task that will block until |event| is signaled.
170 EXPECT_TRUE(posted_tasks_.empty());
171 WaitableEvent event(false, false);
172 PostTaskViaTracker(make_scoped_ptr(
173 new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
174 TaskTraits().WithShutdownBehavior(GetParam()))));
175 EXPECT_EQ(1U, posted_tasks_.size());
176
177 // Run the task asynchronouly.
178 ThreadRunningTask thread_running_task(&tracker_, posted_tasks_.front().get());
179 thread_running_task.Start();
180
181 // Initiate shutdown while the task is running.
182 CallShutdownAsync();
183
184 if (GetParam() == TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) {
185 // Shutdown should complete even with a CONTINUE_ON_SHUTDOWN in progress.
186 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
187 } else {
188 // Shutdown should block with any non CONTINUE_ON_SHUTDOWN task in progress.
189 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
190 }
191
192 // Unblock the task.
193 event.Signal();
194 thread_running_task.Join();
195
196 // Shutdown should now complete for a non CONTINUE_ON_SHUTDOWN task.
197 if (GetParam() != TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)
198 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
199 }
200
201 TEST_P(TaskSchedulerTaskTrackerTest, PostBeforeShutdownRunDuringShutdown) {
202 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
203 const Task* task_to_post_raw = task_to_post.get();
204
205 // Post the task.
206 EXPECT_TRUE(posted_tasks_.empty());
207 PostTaskViaTracker(std::move(task_to_post));
208 EXPECT_EQ(1U, posted_tasks_.size());
209 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
210
211 // Post a BLOCK_SHUTDOWN task just to block shutdown.
212 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
213
214 // Call Shutdown() asynchronously.
215 CallShutdownAsync();
216 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
217
218 // Try to run the first posted task. Only BLOCK_SHUTDOWN tasks should run,
219 // others should be discarded.
220 EXPECT_EQ(0U, num_tasks_executed_);
221 RunNextPostedTaskViaTracker();
222 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 1U : 0U,
223 num_tasks_executed_);
224 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
225
226 // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task.
227 RunNextPostedTaskViaTracker();
228 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U,
229 num_tasks_executed_);
230 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
231 }
232
233 TEST_P(TaskSchedulerTaskTrackerTest, PostBeforeShutdownRunAfterShutdown) {
234 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
235 const Task* task_to_post_raw = task_to_post.get();
236
237 // Post the task.
238 EXPECT_TRUE(posted_tasks_.empty());
239 PostTaskViaTracker(std::move(task_to_post));
240 EXPECT_EQ(1U, posted_tasks_.size());
241 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
242
243 // Call Shutdown() asynchronously.
244 CallShutdownAsync();
245 EXPECT_EQ(0U, num_tasks_executed_);
246
247 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
248 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
249
250 // Run the task to unblock shutdown.
251 RunNextPostedTaskViaTracker();
252 EXPECT_EQ(1U, num_tasks_executed_);
253 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
254
255 // It is not possible to test running after shutdown a BLOCK_SHUTDOWN task
256 // posted before shutdown because Shutdown() won't return if there are
257 // pending BLOCK_SHUTDOWN tasks.
258
259 // Test that a BLOCK_SHUTDOWN task cannot run after shutdown (the task has
gab 2016/03/21 19:53:25 Actually looking at this again, it seems wrong to
fdoray 2016/03/22 20:19:43 Done.
260 // necessarily never been posted).
261 EXPECT_DCHECK_DEATH(
262 {
263 tracker_.RunTask(
264 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN).get());
265 },
266 "");
267 } else {
268 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
269
270 // The task shouldn't be allowed to run after shutdown.
271 RunNextPostedTaskViaTracker();
272 EXPECT_EQ(0U, num_tasks_executed_);
273 }
274 }
275
276 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown) {
277 // Post a BLOCK_SHUTDOWN task just to block shutdown.
278 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
279 scoped_ptr<Task> block_shutdown_task = std::move(posted_tasks_.front());
280 posted_tasks_.pop();
281
282 // Call Shutdown() asynchronously.
283 CallShutdownAsync();
284 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
285
286 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
287 // Post a BLOCK_SHUTDOWN task. This should succeed.
288 EXPECT_TRUE(posted_tasks_.empty());
289 PostTaskViaTracker(CreateTask(GetParam()));
290 EXPECT_EQ(1U, posted_tasks_.size());
291
292 // Run the BLOCK_SHUTDOWN task. This should succeed.
293 EXPECT_EQ(0U, num_tasks_executed_);
294 RunNextPostedTaskViaTracker();
295 EXPECT_EQ(1U, num_tasks_executed_);
296 } else {
297 // It shouldn't be possible to post a non BLOCK_SHUTDOWN task.
298 PostTaskViaTracker(CreateTask(GetParam()));
299 EXPECT_TRUE(posted_tasks_.empty());
300
301 // Don't try to run the task, because it hasn't been posted successfully.
302 }
303
304 // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning
305 // of the test.
306 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
307 tracker_.RunTask(block_shutdown_task.get());
308 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U,
309 num_tasks_executed_);
310 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
311 }
312
313 TEST_P(TaskSchedulerTaskTrackerTest, PostAfterShutdown) {
314 // It is not possible to post a task after shutdown.
315 tracker_.Shutdown();
316 EXPECT_TRUE(posted_tasks_.empty());
317
318 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN)
319 EXPECT_DCHECK_DEATH({ PostTaskViaTracker(CreateTask(GetParam())); }, "");
320 else
321 PostTaskViaTracker(CreateTask(GetParam()));
322
323 EXPECT_TRUE(posted_tasks_.empty());
324 }
325
326 INSTANTIATE_TEST_CASE_P(
327 ContinueOnShutdown,
328 TaskSchedulerTaskTrackerTest,
329 ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
330 INSTANTIATE_TEST_CASE_P(
331 SkipOnShutdown,
332 TaskSchedulerTaskTrackerTest,
333 ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
334 INSTANTIATE_TEST_CASE_P(
335 BlockShutdown,
336 TaskSchedulerTaskTrackerTest,
337 ::testing::Values(TaskShutdownBehavior::BLOCK_SHUTDOWN));
338
339 } // namespace internal
340 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698