Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / chrome / common / cancelable_task_tracker_unittest.cc
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