By moving the call to Load() up in SearchProvider::Start(), we are giving a chance...
[chromium-blink-merge.git] / chrome / common / cancelable_task_tracker_unittest.cc
blob8b79ee905b8a0482269c56114f56c6558e011d33
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.
5 #include "chrome/common/cancelable_task_tracker.h"
7 #include <cstddef>
8 #include <deque>
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.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"
22 namespace {
24 class CancelableTaskTrackerTest : public testing::Test {
25 protected:
26 virtual ~CancelableTaskTrackerTest() {
27 RunCurrentLoopUntilIdle();
30 void RunCurrentLoopUntilIdle() {
31 base::RunLoop run_loop;
32 run_loop.RunUntilIdle();
35 CancelableTaskTracker task_tracker_;
37 private:
38 // Needed by CancelableTaskTracker methods.
39 MessageLoop message_loop_;
42 void AddFailureAt(const tracked_objects::Location& location) {
43 ADD_FAILURE_AT(location.file_name(), location.line_number());
46 // Returns a closure that fails if run.
47 base::Closure MakeExpectedNotRunClosure(
48 const tracked_objects::Location& location) {
49 return base::Bind(&AddFailureAt, location);
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) {}
62 ~RunChecker() {
63 if (!called_) {
64 ADD_FAILURE_AT(location_.file_name(), location_.line_number());
68 void Run() {
69 called_ = true;
72 private:
73 tracked_objects::Location location_;
74 bool called_;
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)));
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());
90 ignore_result(
91 task_tracker_.PostTask(
92 worker_thread.message_loop_proxy(),
93 FROM_HERE,
94 MakeExpectedRunClosure(FROM_HERE)));
96 ignore_result(
97 task_tracker_.PostTaskAndReply(
98 worker_thread.message_loop_proxy(),
99 FROM_HERE,
100 MakeExpectedRunClosure(FROM_HERE),
101 MakeExpectedRunClosure(FROM_HERE)));
103 CancelableTaskTracker::IsCanceledCallback is_canceled;
104 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
106 worker_thread.Stop();
108 RunCurrentLoopUntilIdle();
110 EXPECT_FALSE(is_canceled.Run());
113 // Post a task with the task tracker but cancel it before running the
114 // task runner. The task should not run.
115 TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
116 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
117 new base::TestSimpleTaskRunner());
119 CancelableTaskTracker::TaskId task_id =
120 task_tracker_.PostTask(
121 test_task_runner.get(),
122 FROM_HERE,
123 MakeExpectedNotRunClosure(FROM_HERE));
124 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
126 EXPECT_EQ(1U, test_task_runner->GetPendingTasks().size());
128 task_tracker_.TryCancel(task_id);
130 test_task_runner->RunUntilIdle();
133 // Post a task with reply with the task tracker and cancel it before
134 // running the task runner. Neither the task nor the reply should
135 // run.
136 TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
137 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
138 new base::TestSimpleTaskRunner());
140 CancelableTaskTracker::TaskId task_id =
141 task_tracker_.PostTaskAndReply(
142 test_task_runner.get(),
143 FROM_HERE,
144 MakeExpectedNotRunClosure(FROM_HERE),
145 MakeExpectedNotRunClosure(FROM_HERE));
146 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
148 task_tracker_.TryCancel(task_id);
150 test_task_runner->RunUntilIdle();
153 // Post a task with reply with the task tracker and cancel it after
154 // running the task runner but before running the current message
155 // loop. The task should run but the reply should not.
156 TEST_F(CancelableTaskTrackerTest, CancelReply) {
157 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
158 new base::TestSimpleTaskRunner());
160 CancelableTaskTracker::TaskId task_id =
161 task_tracker_.PostTaskAndReply(
162 test_task_runner.get(),
163 FROM_HERE,
164 MakeExpectedRunClosure(FROM_HERE),
165 MakeExpectedNotRunClosure(FROM_HERE));
166 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
168 test_task_runner->RunUntilIdle();
170 task_tracker_.TryCancel(task_id);
173 // Post a task with reply with the task tracker on a worker thread and
174 // cancel it before running the current message loop. The task should
175 // run but the reply should not.
176 TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
177 base::Thread worker_thread("worker thread");
178 ASSERT_TRUE(worker_thread.Start());
180 CancelableTaskTracker::TaskId task_id =
181 task_tracker_.PostTaskAndReply(
182 worker_thread.message_loop_proxy(),
183 FROM_HERE,
184 base::Bind(&base::DoNothing),
185 MakeExpectedNotRunClosure(FROM_HERE));
186 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
188 task_tracker_.TryCancel(task_id);
190 worker_thread.Stop();
193 void ExpectIsCanceled(
194 const CancelableTaskTracker::IsCanceledCallback& is_canceled,
195 bool expected_is_canceled) {
196 EXPECT_EQ(expected_is_canceled, is_canceled.Run());
199 // Create a new task ID and check its status on a separate thread
200 // before and after canceling. The is-canceled callback should be
201 // thread-safe (i.e., nothing should blow up).
202 TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
203 CancelableTaskTracker::IsCanceledCallback is_canceled;
204 CancelableTaskTracker::TaskId task_id =
205 task_tracker_.NewTrackedTaskId(&is_canceled);
207 EXPECT_FALSE(is_canceled.Run());
209 base::Thread other_thread("other thread");
210 ASSERT_TRUE(other_thread.Start());
211 other_thread.message_loop_proxy()->PostTask(
212 FROM_HERE,
213 base::Bind(&ExpectIsCanceled, is_canceled, false));
214 other_thread.Stop();
216 task_tracker_.TryCancel(task_id);
218 ASSERT_TRUE(other_thread.Start());
219 other_thread.message_loop_proxy()->PostTask(
220 FROM_HERE,
221 base::Bind(&ExpectIsCanceled, is_canceled, true));
222 other_thread.Stop();
225 // With the task tracker, post a task, a task with a reply, get a new
226 // task id, and then cancel all of them. None of the tasks nor the
227 // reply should run and the "is canceled" callback should return
228 // true.
229 TEST_F(CancelableTaskTrackerTest, CancelAll) {
230 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
231 new base::TestSimpleTaskRunner());
233 ignore_result(
234 task_tracker_.PostTask(
235 test_task_runner,
236 FROM_HERE,
237 MakeExpectedNotRunClosure(FROM_HERE)));
239 ignore_result(
240 task_tracker_.PostTaskAndReply(
241 test_task_runner,
242 FROM_HERE,
243 MakeExpectedNotRunClosure(FROM_HERE),
244 MakeExpectedNotRunClosure(FROM_HERE)));
246 CancelableTaskTracker::IsCanceledCallback is_canceled;
247 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
249 task_tracker_.TryCancelAll();
251 test_task_runner->RunUntilIdle();
253 RunCurrentLoopUntilIdle();
255 EXPECT_TRUE(is_canceled.Run());
258 // With the task tracker, post a task, a task with a reply, get a new
259 // task id, and then cancel all of them. None of the tasks nor the
260 // reply should run and the "is canceled" callback should return
261 // true.
262 TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
263 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
264 new base::TestSimpleTaskRunner());
266 CancelableTaskTracker::IsCanceledCallback is_canceled;
269 // Create another task tracker with a smaller scope.
270 CancelableTaskTracker task_tracker;
272 ignore_result(
273 task_tracker.PostTask(
274 test_task_runner,
275 FROM_HERE,
276 MakeExpectedNotRunClosure(FROM_HERE)));
278 ignore_result(
279 task_tracker.PostTaskAndReply(
280 test_task_runner,
281 FROM_HERE,
282 MakeExpectedNotRunClosure(FROM_HERE),
283 MakeExpectedNotRunClosure(FROM_HERE)));
285 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
288 test_task_runner->RunUntilIdle();
290 RunCurrentLoopUntilIdle();
292 EXPECT_FALSE(is_canceled.Run());
295 // Post a task and cancel it. HasTrackedTasks() should return true
296 // from when the task is posted until the (do-nothing) reply task is
297 // flushed.
298 TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPost) {
299 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
300 new base::TestSimpleTaskRunner());
302 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
304 ignore_result(
305 task_tracker_.PostTask(
306 test_task_runner,
307 FROM_HERE,
308 MakeExpectedNotRunClosure(FROM_HERE)));
310 task_tracker_.TryCancelAll();
312 test_task_runner->RunUntilIdle();
314 EXPECT_TRUE(task_tracker_.HasTrackedTasks());
316 RunCurrentLoopUntilIdle();
318 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
321 // Post a task with a reply and cancel it. HasTrackedTasks() should
322 // return true from when the task is posted until it is canceled.
323 TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostWithReply) {
324 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
325 new base::TestSimpleTaskRunner());
327 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
329 ignore_result(
330 task_tracker_.PostTaskAndReply(
331 test_task_runner,
332 FROM_HERE,
333 MakeExpectedNotRunClosure(FROM_HERE),
334 MakeExpectedNotRunClosure(FROM_HERE)));
336 task_tracker_.TryCancelAll();
338 test_task_runner->RunUntilIdle();
340 EXPECT_TRUE(task_tracker_.HasTrackedTasks());
342 RunCurrentLoopUntilIdle();
344 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
347 // Create a new tracked task ID. HasTrackedTasks() should return true
348 // until the IsCanceledCallback is destroyed.
349 TEST_F(CancelableTaskTrackerTest, HasTrackedTasksIsCancelled) {
350 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
352 CancelableTaskTracker::IsCanceledCallback is_canceled;
353 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
355 task_tracker_.TryCancelAll();
357 EXPECT_TRUE(task_tracker_.HasTrackedTasks());
359 is_canceled.Reset();
361 EXPECT_FALSE(task_tracker_.HasTrackedTasks());
364 // The death tests below make sure that calling task tracker member
365 // functions from a thread different from its owner thread DCHECKs in
366 // debug mode.
368 class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
369 protected:
370 CancelableTaskTrackerDeathTest() {
371 // The default style "fast" does not support multi-threaded tests.
372 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
375 virtual ~CancelableTaskTrackerDeathTest() {}
378 // Duplicated from base/threading/thread_checker.h so that we can be
379 // good citizens there and undef the macro.
380 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
381 #define ENABLE_THREAD_CHECKER 1
382 #else
383 #define ENABLE_THREAD_CHECKER 0
384 #endif
386 // Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
387 void MaybeRunDeadlyTaskTrackerMemberFunction(
388 CancelableTaskTracker* task_tracker,
389 const base::Callback<void(CancelableTaskTracker*)>& fn) {
390 // CancelableTask uses DCHECKs with its ThreadChecker (itself only
391 // enabled in debug mode).
392 #if ENABLE_THREAD_CHECKER
393 EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
394 #endif
397 void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
398 ignore_result(
399 task_tracker->PostTask(
400 scoped_refptr<base::TestSimpleTaskRunner>(
401 new base::TestSimpleTaskRunner()),
402 FROM_HERE, base::Bind(&base::DoNothing)));
405 TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
406 base::Thread bad_thread("bad thread");
407 ASSERT_TRUE(bad_thread.Start());
409 bad_thread.message_loop_proxy()->PostTask(
410 FROM_HERE,
411 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
412 base::Unretained(&task_tracker_),
413 base::Bind(&PostDoNothingTask)));
416 void TryCancel(CancelableTaskTracker::TaskId task_id,
417 CancelableTaskTracker* task_tracker) {
418 task_tracker->TryCancel(task_id);
421 TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
422 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
423 new base::TestSimpleTaskRunner());
425 base::Thread bad_thread("bad thread");
426 ASSERT_TRUE(bad_thread.Start());
428 CancelableTaskTracker::TaskId task_id =
429 task_tracker_.PostTask(
430 test_task_runner.get(),
431 FROM_HERE,
432 base::Bind(&base::DoNothing));
433 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
435 bad_thread.message_loop_proxy()->PostTask(
436 FROM_HERE,
437 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
438 base::Unretained(&task_tracker_),
439 base::Bind(&TryCancel, task_id)));
441 test_task_runner->RunUntilIdle();
444 TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
445 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
446 new base::TestSimpleTaskRunner());
448 base::Thread bad_thread("bad thread");
449 ASSERT_TRUE(bad_thread.Start());
451 CancelableTaskTracker::TaskId task_id =
452 task_tracker_.PostTask(
453 test_task_runner.get(),
454 FROM_HERE,
455 base::Bind(&base::DoNothing));
456 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
458 bad_thread.message_loop_proxy()->PostTask(
459 FROM_HERE,
460 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
461 base::Unretained(&task_tracker_),
462 base::Bind(&CancelableTaskTracker::TryCancelAll)));
464 test_task_runner->RunUntilIdle();
467 } // namespace