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

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

Powered by Google App Engine
This is Rietveld 408576698