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

Side by Side Diff: chrome/common/cancelable_task_tracker_unittest.cc

Issue 137263007: Move CancelableTaskTracker to //base/task/CancelableTaskTracker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move to base/task/cancelable_task_tracker* Created 6 years, 10 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
« no previous file with comments | « chrome/common/cancelable_task_tracker.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/common/cancelable_task_tracker.h"
6
7 #include <cstddef>
8 #include <deque>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/run_loop.h"
18 #include "base/test/test_simple_task_runner.h"
19 #include "base/threading/thread.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace {
23
24 class CancelableTaskTrackerTest : public testing::Test {
25 protected:
26 virtual ~CancelableTaskTrackerTest() {
27 RunCurrentLoopUntilIdle();
28 }
29
30 void RunCurrentLoopUntilIdle() {
31 base::RunLoop run_loop;
32 run_loop.RunUntilIdle();
33 }
34
35 CancelableTaskTracker task_tracker_;
36
37 private:
38 // Needed by CancelableTaskTracker methods.
39 base::MessageLoop message_loop_;
40 };
41
42 void AddFailureAt(const tracked_objects::Location& location) {
43 ADD_FAILURE_AT(location.file_name(), location.line_number());
44 }
45
46 // Returns a closure that fails if run.
47 base::Closure MakeExpectedNotRunClosure(
48 const tracked_objects::Location& location) {
49 return base::Bind(&AddFailureAt, location);
50 }
51
52 // A helper class for MakeExpectedRunClosure() that fails if it is
53 // destroyed without Run() having been called. This class may be used
54 // from multiple threads as long as Run() is called at most once
55 // before destruction.
56 class RunChecker {
57 public:
58 explicit RunChecker(const tracked_objects::Location& location)
59 : location_(location),
60 called_(false) {}
61
62 ~RunChecker() {
63 if (!called_) {
64 ADD_FAILURE_AT(location_.file_name(), location_.line_number());
65 }
66 }
67
68 void Run() {
69 called_ = true;
70 }
71
72 private:
73 tracked_objects::Location location_;
74 bool called_;
75 };
76
77 // Returns a closure that fails on destruction if it hasn't been run.
78 base::Closure MakeExpectedRunClosure(
79 const tracked_objects::Location& location) {
80 return base::Bind(&RunChecker::Run, base::Owned(new RunChecker(location)));
81 }
82
83 // With the task tracker, post a task, a task with a reply, and get a
84 // new task id without canceling any of them. The tasks and the reply
85 // should run and the "is canceled" callback should return false.
86 TEST_F(CancelableTaskTrackerTest, NoCancel) {
87 base::Thread worker_thread("worker thread");
88 ASSERT_TRUE(worker_thread.Start());
89
90 ignore_result(task_tracker_.PostTask(worker_thread.message_loop_proxy().get(),
91 FROM_HERE,
92 MakeExpectedRunClosure(FROM_HERE)));
93
94 ignore_result(
95 task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
96 FROM_HERE,
97 MakeExpectedRunClosure(FROM_HERE),
98 MakeExpectedRunClosure(FROM_HERE)));
99
100 CancelableTaskTracker::IsCanceledCallback is_canceled;
101 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
102
103 worker_thread.Stop();
104
105 RunCurrentLoopUntilIdle();
106
107 EXPECT_FALSE(is_canceled.Run());
108 }
109
110 // Post a task with the task tracker but cancel it before running the
111 // task runner. The task should not run.
112 TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
113 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
114 new base::TestSimpleTaskRunner());
115
116 CancelableTaskTracker::TaskId task_id =
117 task_tracker_.PostTask(
118 test_task_runner.get(),
119 FROM_HERE,
120 MakeExpectedNotRunClosure(FROM_HERE));
121 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
122
123 EXPECT_EQ(1U, test_task_runner->GetPendingTasks().size());
124
125 task_tracker_.TryCancel(task_id);
126
127 test_task_runner->RunUntilIdle();
128 }
129
130 // Post a task with reply with the task tracker and cancel it before
131 // running the task runner. Neither the task nor the reply should
132 // run.
133 TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
134 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
135 new base::TestSimpleTaskRunner());
136
137 CancelableTaskTracker::TaskId task_id =
138 task_tracker_.PostTaskAndReply(
139 test_task_runner.get(),
140 FROM_HERE,
141 MakeExpectedNotRunClosure(FROM_HERE),
142 MakeExpectedNotRunClosure(FROM_HERE));
143 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
144
145 task_tracker_.TryCancel(task_id);
146
147 test_task_runner->RunUntilIdle();
148 }
149
150 // Post a task with reply with the task tracker and cancel it after
151 // running the task runner but before running the current message
152 // loop. The task should run but the reply should not.
153 TEST_F(CancelableTaskTrackerTest, CancelReply) {
154 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
155 new base::TestSimpleTaskRunner());
156
157 CancelableTaskTracker::TaskId task_id =
158 task_tracker_.PostTaskAndReply(
159 test_task_runner.get(),
160 FROM_HERE,
161 MakeExpectedRunClosure(FROM_HERE),
162 MakeExpectedNotRunClosure(FROM_HERE));
163 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
164
165 test_task_runner->RunUntilIdle();
166
167 task_tracker_.TryCancel(task_id);
168 }
169
170 // Post a task with reply with the task tracker on a worker thread and
171 // cancel it before running the current message loop. The task should
172 // run but the reply should not.
173 TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
174 base::Thread worker_thread("worker thread");
175 ASSERT_TRUE(worker_thread.Start());
176
177 CancelableTaskTracker::TaskId task_id =
178 task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
179 FROM_HERE,
180 base::Bind(&base::DoNothing),
181 MakeExpectedNotRunClosure(FROM_HERE));
182 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
183
184 task_tracker_.TryCancel(task_id);
185
186 worker_thread.Stop();
187 }
188
189 void ExpectIsCanceled(
190 const CancelableTaskTracker::IsCanceledCallback& is_canceled,
191 bool expected_is_canceled) {
192 EXPECT_EQ(expected_is_canceled, is_canceled.Run());
193 }
194
195 // Create a new task ID and check its status on a separate thread
196 // before and after canceling. The is-canceled callback should be
197 // thread-safe (i.e., nothing should blow up).
198 TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
199 CancelableTaskTracker::IsCanceledCallback is_canceled;
200 CancelableTaskTracker::TaskId task_id =
201 task_tracker_.NewTrackedTaskId(&is_canceled);
202
203 EXPECT_FALSE(is_canceled.Run());
204
205 base::Thread other_thread("other thread");
206 ASSERT_TRUE(other_thread.Start());
207 other_thread.message_loop_proxy()->PostTask(
208 FROM_HERE,
209 base::Bind(&ExpectIsCanceled, is_canceled, false));
210 other_thread.Stop();
211
212 task_tracker_.TryCancel(task_id);
213
214 ASSERT_TRUE(other_thread.Start());
215 other_thread.message_loop_proxy()->PostTask(
216 FROM_HERE,
217 base::Bind(&ExpectIsCanceled, is_canceled, true));
218 other_thread.Stop();
219 }
220
221 // With the task tracker, post a task, a task with a reply, get a new
222 // task id, and then cancel all of them. None of the tasks nor the
223 // reply should run and the "is canceled" callback should return
224 // true.
225 TEST_F(CancelableTaskTrackerTest, CancelAll) {
226 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
227 new base::TestSimpleTaskRunner());
228
229 ignore_result(task_tracker_.PostTask(
230 test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
231
232 ignore_result(
233 task_tracker_.PostTaskAndReply(test_task_runner.get(),
234 FROM_HERE,
235 MakeExpectedNotRunClosure(FROM_HERE),
236 MakeExpectedNotRunClosure(FROM_HERE)));
237
238 CancelableTaskTracker::IsCanceledCallback is_canceled;
239 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
240
241 task_tracker_.TryCancelAll();
242
243 test_task_runner->RunUntilIdle();
244
245 RunCurrentLoopUntilIdle();
246
247 EXPECT_TRUE(is_canceled.Run());
248 }
249
250 // With the task tracker, post a task, a task with a reply, get a new
251 // task id, and then cancel all of them. None of the tasks nor the
252 // reply should run and the "is canceled" callback should return
253 // true.
254 TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
255 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
256 new base::TestSimpleTaskRunner());
257
258 CancelableTaskTracker::IsCanceledCallback is_canceled;
259
260 {
261 // Create another task tracker with a smaller scope.
262 CancelableTaskTracker task_tracker;
263
264 ignore_result(task_tracker.PostTask(test_task_runner.get(),
265 FROM_HERE,
266 MakeExpectedNotRunClosure(FROM_HERE)));
267
268 ignore_result(
269 task_tracker.PostTaskAndReply(test_task_runner.get(),
270 FROM_HERE,
271 MakeExpectedNotRunClosure(FROM_HERE),
272 MakeExpectedNotRunClosure(FROM_HERE)));
273
274 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
275 }
276
277 test_task_runner->RunUntilIdle();
278
279 RunCurrentLoopUntilIdle();
280
281 EXPECT_FALSE(is_canceled.Run());
282 }
283
284 // Post a task and cancel it. HasTrackedTasks() should return true
285 // from when the task is posted until the (do-nothing) reply task is
286 // flushed.
287 TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPost) {
288 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
289 new base::TestSimpleTaskRunner());
290
291 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
292
293 ignore_result(task_tracker_.PostTask(
294 test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
295
296 task_tracker_.TryCancelAll();
297
298 test_task_runner->RunUntilIdle();
299
300 EXPECT_TRUE(task_tracker_.HasTrackedTasks());
301
302 RunCurrentLoopUntilIdle();
303
304 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
305 }
306
307 // Post a task with a reply and cancel it. HasTrackedTasks() should
308 // return true from when the task is posted until it is canceled.
309 TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostWithReply) {
310 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
311 new base::TestSimpleTaskRunner());
312
313 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
314
315 ignore_result(
316 task_tracker_.PostTaskAndReply(test_task_runner.get(),
317 FROM_HERE,
318 MakeExpectedNotRunClosure(FROM_HERE),
319 MakeExpectedNotRunClosure(FROM_HERE)));
320
321 task_tracker_.TryCancelAll();
322
323 test_task_runner->RunUntilIdle();
324
325 EXPECT_TRUE(task_tracker_.HasTrackedTasks());
326
327 RunCurrentLoopUntilIdle();
328
329 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
330 }
331
332 // Create a new tracked task ID. HasTrackedTasks() should return true
333 // until the IsCanceledCallback is destroyed.
334 TEST_F(CancelableTaskTrackerTest, HasTrackedTasksIsCancelled) {
335 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
336
337 CancelableTaskTracker::IsCanceledCallback is_canceled;
338 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
339
340 task_tracker_.TryCancelAll();
341
342 EXPECT_TRUE(task_tracker_.HasTrackedTasks());
343
344 is_canceled.Reset();
345
346 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
347 }
348
349 // The death tests below make sure that calling task tracker member
350 // functions from a thread different from its owner thread DCHECKs in
351 // debug mode.
352
353 class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
354 protected:
355 CancelableTaskTrackerDeathTest() {
356 // The default style "fast" does not support multi-threaded tests.
357 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
358 }
359
360 virtual ~CancelableTaskTrackerDeathTest() {}
361 };
362
363 // Duplicated from base/threading/thread_checker.h so that we can be
364 // good citizens there and undef the macro.
365 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
366 #define ENABLE_THREAD_CHECKER 1
367 #else
368 #define ENABLE_THREAD_CHECKER 0
369 #endif
370
371 // Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
372 void MaybeRunDeadlyTaskTrackerMemberFunction(
373 CancelableTaskTracker* task_tracker,
374 const base::Callback<void(CancelableTaskTracker*)>& fn) {
375 // CancelableTask uses DCHECKs with its ThreadChecker (itself only
376 // enabled in debug mode).
377 #if ENABLE_THREAD_CHECKER
378 EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
379 #endif
380 }
381
382 void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
383 ignore_result(
384 task_tracker->PostTask(scoped_refptr<base::TestSimpleTaskRunner>(
385 new base::TestSimpleTaskRunner())
386 .get(),
387 FROM_HERE,
388 base::Bind(&base::DoNothing)));
389 }
390
391 TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
392 base::Thread bad_thread("bad thread");
393 ASSERT_TRUE(bad_thread.Start());
394
395 bad_thread.message_loop_proxy()->PostTask(
396 FROM_HERE,
397 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
398 base::Unretained(&task_tracker_),
399 base::Bind(&PostDoNothingTask)));
400 }
401
402 void TryCancel(CancelableTaskTracker::TaskId task_id,
403 CancelableTaskTracker* task_tracker) {
404 task_tracker->TryCancel(task_id);
405 }
406
407 TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
408 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
409 new base::TestSimpleTaskRunner());
410
411 base::Thread bad_thread("bad thread");
412 ASSERT_TRUE(bad_thread.Start());
413
414 CancelableTaskTracker::TaskId task_id =
415 task_tracker_.PostTask(
416 test_task_runner.get(),
417 FROM_HERE,
418 base::Bind(&base::DoNothing));
419 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
420
421 bad_thread.message_loop_proxy()->PostTask(
422 FROM_HERE,
423 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
424 base::Unretained(&task_tracker_),
425 base::Bind(&TryCancel, task_id)));
426
427 test_task_runner->RunUntilIdle();
428 }
429
430 TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
431 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
432 new base::TestSimpleTaskRunner());
433
434 base::Thread bad_thread("bad thread");
435 ASSERT_TRUE(bad_thread.Start());
436
437 CancelableTaskTracker::TaskId task_id =
438 task_tracker_.PostTask(
439 test_task_runner.get(),
440 FROM_HERE,
441 base::Bind(&base::DoNothing));
442 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
443
444 bad_thread.message_loop_proxy()->PostTask(
445 FROM_HERE,
446 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
447 base::Unretained(&task_tracker_),
448 base::Bind(&CancelableTaskTracker::TryCancelAll)));
449
450 test_task_runner->RunUntilIdle();
451 }
452
453 } // namespace
OLDNEW
« no previous file with comments | « chrome/common/cancelable_task_tracker.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698