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

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

Issue 11417077: Rewrite CancelableTaskTracker unit tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 8 years 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 | Annotate | Revision Log
« 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/cancelable_task_tracker.h" 5 #include "chrome/common/cancelable_task_tracker.h"
6 6
7 #include "base/basictypes.h" 7 #include <cstddef>
8 #include <deque>
9
8 #include "base/bind.h" 10 #include "base/bind.h"
9 #include "base/callback.h" 11 #include "base/bind_helpers.h"
10 #include "base/memory/scoped_ptr.h" 12 #include "base/compiler_specific.h"
11 #include "base/synchronization/waitable_event.h" 13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/message_loop.h"
18 #include "base/run_loop.h"
19 #include "base/task_runner.h"
12 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
13 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
14 22
15 using base::Bind;
16 using base::Closure;
17 using base::Owned;
18 using base::TaskRunner;
19 using base::Thread;
20 using base::Unretained;
21 using base::WaitableEvent;
22
23 namespace { 23 namespace {
24 24
25 class WaitableEventScoper { 25 // Test TaskRunner implementation that simply stores posted tasks in a
26 // queue.
27 //
28 // TOOD(akalin): Pull this out into its own file once something else
29 // needs it.
30 class FakeNonThreadSafeTaskRunner : public base::TaskRunner {
26 public: 31 public:
27 explicit WaitableEventScoper(WaitableEvent* event) : event_(event) {} 32 // base::TaskRunner implementation.
28 ~WaitableEventScoper() { 33 // Stores posted tasks in a FIFO, ignoring |delay|.
29 if (event_) 34 virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
30 event_->Signal(); 35 const base::Closure& task,
31 } 36 base::TimeDelta delay) OVERRIDE {
37 tasks_.push_back(task);
38 return true;
39 }
40
41 virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
42 return true;
43 }
44
45 size_t GetPendingTaskCount() const {
46 return tasks_.size();
47 }
48
49 void RunUntilIdle() {
50 // Use a while loop since a task may post more tasks.
51 while (!tasks_.empty()) {
52 base::Closure task = tasks_.front();
53 tasks_.pop_front();
54 task.Run();
55 }
56 }
57
58 protected:
59 virtual ~FakeNonThreadSafeTaskRunner() {}
60
32 private: 61 private:
33 WaitableEvent* event_; 62 std::deque<base::Closure> tasks_;
34 DISALLOW_COPY_AND_ASSIGN(WaitableEventScoper);
35 }; 63 };
36 64
37 class CancelableTaskTrackerTest : public testing::Test { 65 class CancelableTaskTrackerTest : public testing::Test {
38 protected: 66 protected:
39 CancelableTaskTrackerTest() 67 virtual ~CancelableTaskTrackerTest() {
40 : task_id_(CancelableTaskTracker::kBadTaskId), 68 base::RunLoop run_loop;
41 test_data_(0), 69 run_loop.RunUntilIdle();
42 task_thread_start_event_(true, false) {} 70 }
43 71
44 virtual void SetUp() { 72 CancelableTaskTracker task_tracker_;
45 task_thread_.reset(new Thread("task thread")); 73
46 client_thread_.reset(new Thread("client thread")); 74 private:
47 task_thread_->Start(); 75 // Needed by CancelableTaskTracker methods.
48 client_thread_->Start(); 76 MessageLoop message_loop_;
49 77 };
50 task_thread_runner_ = task_thread_->message_loop_proxy(); 78
51 client_thread_runner_ = client_thread_->message_loop_proxy(); 79 void AddFailureAt(const tracked_objects::Location& location) {
52 80 ADD_FAILURE_AT(location.file_name(), location.line_number());
53 // Create tracker on client thread. 81 }
54 WaitableEvent tracker_created(true, false); 82
55 client_thread_runner_->PostTask( 83 // Returns a closure that fails if run.
56 FROM_HERE, 84 base::Closure MakeExpectedNotRunClosure(
57 Bind(&CancelableTaskTrackerTest::CreateTrackerOnClientThread, 85 const tracked_objects::Location& location) {
58 Unretained(this), &tracker_created)); 86 return base::Bind(&AddFailureAt, location);
59 tracker_created.Wait(); 87 }
60 88
61 // Block server thread so we can prepare the test. 89 // A helper class for MakeExpectedRunClosure() that fails if it is
62 task_thread_runner_->PostTask( 90 // destroyed without Run() having been called. This class may be used
63 FROM_HERE, 91 // from multiple threads as long as Run() is called at most once
64 Bind(&WaitableEvent::Wait, Unretained(&task_thread_start_event_))); 92 // before destruction.
65 } 93 class RunChecker {
66
67 virtual void TearDown() {
68 UnblockTaskThread();
69
70 // Destroy tracker on client thread.
71 WaitableEvent tracker_destroyed(true, false);
72 client_thread_runner_->PostTask(
73 FROM_HERE,
74 Bind(&CancelableTaskTrackerTest::DestroyTrackerOnClientThread,
75 Unretained(this), &tracker_destroyed));
76
77 // This will also wait for any pending tasks on client thread.
78 tracker_destroyed.Wait();
79
80 client_thread_->Stop();
81 task_thread_->Stop();
82 }
83
84 void RunOnClientAndWait(
85 void (*func)(CancelableTaskTrackerTest*, WaitableEvent*)) {
86 WaitableEvent event(true, false);
87 client_thread_runner_->PostTask(FROM_HERE,
88 Bind(func, Unretained(this), &event));
89 event.Wait();
90 }
91
92 public: 94 public:
93 // Client thread posts tasks and runs replies. 95 explicit RunChecker(const tracked_objects::Location& location)
94 scoped_refptr<TaskRunner> client_thread_runner_; 96 : location_(location),
95 97 called_(false) {}
96 // Task thread runs tasks. 98
97 scoped_refptr<TaskRunner> task_thread_runner_; 99 ~RunChecker() {
98 100 if (!called_) {
99 // |tracker_| can only live on client thread. 101 ADD_FAILURE_AT(location_.file_name(), location_.line_number());
100 scoped_ptr<CancelableTaskTracker> tracker_; 102 }
101 103 }
102 CancelableTaskTracker::TaskId task_id_; 104
103 105 void Run() {
104 void UnblockTaskThread() { 106 called_ = true;
105 task_thread_start_event_.Signal();
106 }
107
108 //////////////////////////////////////////////////////////////////////////////
109 // Testing data and related functions
110 int test_data_; // Defaults to 0.
111
112 Closure IncreaseTestDataAndSignalClosure(WaitableEvent* event) {
113 return Bind(&CancelableTaskTrackerTest::IncreaseDataAndSignal,
114 &test_data_, event);
115 }
116
117 Closure IncreaseTestDataIfNotCanceledAndSignalClosure(
118 const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb,
119 WaitableEvent* event) {
120 return Bind(&CancelableTaskTrackerTest::IncreaseDataIfNotCanceledAndSignal,
121 &test_data_, is_canceled_cb, event);
122 }
123
124 Closure DecreaseTestDataClosure(WaitableEvent* event) {
125 return Bind(&CancelableTaskTrackerTest::DecreaseData,
126 Owned(new WaitableEventScoper(event)), &test_data_);
127 } 107 }
128 108
129 private: 109 private:
130 void CreateTrackerOnClientThread(WaitableEvent* event) { 110 tracked_objects::Location location_;
131 tracker_.reset(new CancelableTaskTracker()); 111 bool called_;
132 event->Signal();
133 }
134
135 void DestroyTrackerOnClientThread(WaitableEvent* event) {
136 tracker_.reset();
137 event->Signal();
138 }
139
140 static void IncreaseDataAndSignal(int* data, WaitableEvent* event) {
141 (*data)++;
142 if (event)
143 event->Signal();
144 }
145
146 static void IncreaseDataIfNotCanceledAndSignal(
147 int* data,
148 const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb,
149 WaitableEvent* event) {
150 if (!is_canceled_cb.Run())
151 (*data)++;
152 if (event)
153 event->Signal();
154 }
155
156 static void DecreaseData(WaitableEventScoper* event_scoper, int* data) {
157 (*data) -= 2;
158 }
159
160 scoped_ptr<Thread> client_thread_;
161 scoped_ptr<Thread> task_thread_;
162
163 WaitableEvent task_thread_start_event_;
164 }; 112 };
165 113
166 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST 114 // Returns a closure that fails on destruction if it hasn't been run.
167 115 base::Closure MakeExpectedRunClosure(
168 typedef CancelableTaskTrackerTest CancelableTaskTrackerDeathTest; 116 const tracked_objects::Location& location) {
117 return base::Bind(&RunChecker::Run, base::Owned(new RunChecker(location)));
118 }
119
120 // With the task tracker, post a task, a task with a reply, and get a
121 // new task id without canceling any of them. The tasks and the reply
122 // should run and the "is canceled" callback should return false.
123 TEST_F(CancelableTaskTrackerTest, NoCancel) {
124 base::Thread worker_thread("worker thread");
125 ASSERT_TRUE(worker_thread.Start());
126
127 ignore_result(
128 task_tracker_.PostTask(
129 worker_thread.message_loop_proxy(),
130 FROM_HERE,
131 MakeExpectedRunClosure(FROM_HERE)));
132
133 ignore_result(
134 task_tracker_.PostTaskAndReply(
135 worker_thread.message_loop_proxy(),
136 FROM_HERE,
137 MakeExpectedRunClosure(FROM_HERE),
138 MakeExpectedRunClosure(FROM_HERE)));
139
140 CancelableTaskTracker::IsCanceledCallback is_canceled;
141 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
142
143 worker_thread.Stop();
144
145 base::RunLoop run_loop;
146 run_loop.RunUntilIdle();
147
148 EXPECT_FALSE(is_canceled.Run());
149 }
150
151 // Post a task with the task tracker but cancel it before running the
152 // task runner. The task should not run.
153 TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
154 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
155 new FakeNonThreadSafeTaskRunner());
156
157 CancelableTaskTracker::TaskId task_id =
158 task_tracker_.PostTask(
159 fake_task_runner.get(),
160 FROM_HERE,
161 MakeExpectedNotRunClosure(FROM_HERE));
162 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
163
164 EXPECT_EQ(1U, fake_task_runner->GetPendingTaskCount());
165
166 task_tracker_.TryCancel(task_id);
167
168 fake_task_runner->RunUntilIdle();
169 }
170
171 // Post a task with reply with the task tracker and cancel it before
172 // running the task runner. Neither the task nor the reply should
173 // run.
174 TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
175 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
176 new FakeNonThreadSafeTaskRunner());
177
178 CancelableTaskTracker::TaskId task_id =
179 task_tracker_.PostTaskAndReply(
180 fake_task_runner.get(),
181 FROM_HERE,
182 MakeExpectedNotRunClosure(FROM_HERE),
183 MakeExpectedNotRunClosure(FROM_HERE));
184 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
185
186 task_tracker_.TryCancel(task_id);
187
188 fake_task_runner->RunUntilIdle();
189 }
190
191 // Post a task with reply with the task tracker and cancel it after
192 // running the task runner but before running the current message
193 // loop. The task should run but the reply should not.
194 TEST_F(CancelableTaskTrackerTest, CancelReply) {
195 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
196 new FakeNonThreadSafeTaskRunner());
197
198 CancelableTaskTracker::TaskId task_id =
199 task_tracker_.PostTaskAndReply(
200 fake_task_runner.get(),
201 FROM_HERE,
202 MakeExpectedRunClosure(FROM_HERE),
203 MakeExpectedNotRunClosure(FROM_HERE));
204 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
205
206 fake_task_runner->RunUntilIdle();
207
208 task_tracker_.TryCancel(task_id);
209 }
210
211 // Post a task with reply with the task tracker on a worker thread and
212 // cancel it before running the current message loop. The task should
213 // run but the reply should not.
214 TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
215 base::Thread worker_thread("worker thread");
216 ASSERT_TRUE(worker_thread.Start());
217
218 CancelableTaskTracker::TaskId task_id =
219 task_tracker_.PostTaskAndReply(
220 worker_thread.message_loop_proxy(),
221 FROM_HERE,
222 base::Bind(&base::DoNothing),
223 MakeExpectedNotRunClosure(FROM_HERE));
224 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
225
226 task_tracker_.TryCancel(task_id);
227
228 worker_thread.Stop();
229 }
230
231 void ExpectIsCanceled(
232 const CancelableTaskTracker::IsCanceledCallback& is_canceled,
233 bool expected_is_canceled) {
234 EXPECT_EQ(expected_is_canceled, is_canceled.Run());
235 }
236
237 // Create a new task ID and check its status on a separate thread
238 // before and after canceling. The is-canceled callback should be
239 // thread-safe (i.e., nothing should blow up).
240 TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
241 CancelableTaskTracker::IsCanceledCallback is_canceled;
242 CancelableTaskTracker::TaskId task_id =
243 task_tracker_.NewTrackedTaskId(&is_canceled);
244
245 EXPECT_FALSE(is_canceled.Run());
246
247 base::Thread other_thread("other thread");
248 ASSERT_TRUE(other_thread.Start());
249 other_thread.message_loop_proxy()->PostTask(
250 FROM_HERE,
251 base::Bind(&ExpectIsCanceled, is_canceled, false));
252 other_thread.Stop();
253
254 task_tracker_.TryCancel(task_id);
255
256 ASSERT_TRUE(other_thread.Start());
257 other_thread.message_loop_proxy()->PostTask(
258 FROM_HERE,
259 base::Bind(&ExpectIsCanceled, is_canceled, true));
260 other_thread.Stop();
261 }
262
263 // With the task tracker, post a task, a task with a reply, get a new
264 // task id, and then cancel all of them. None of the tasks nor the
265 // reply should run and the "is canceled" callback should return
266 // true.
267 TEST_F(CancelableTaskTrackerTest, CancelAll) {
268 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
269 new FakeNonThreadSafeTaskRunner());
270
271 ignore_result(
272 task_tracker_.PostTask(
273 fake_task_runner,
274 FROM_HERE,
275 MakeExpectedNotRunClosure(FROM_HERE)));
276
277 ignore_result(
278 task_tracker_.PostTaskAndReply(
279 fake_task_runner,
280 FROM_HERE,
281 MakeExpectedNotRunClosure(FROM_HERE),
282 MakeExpectedNotRunClosure(FROM_HERE)));
283
284 CancelableTaskTracker::IsCanceledCallback is_canceled;
285 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
286
287 task_tracker_.TryCancelAll();
288
289 fake_task_runner->RunUntilIdle();
290
291 base::RunLoop run_loop;
292 run_loop.RunUntilIdle();
293
294 EXPECT_TRUE(is_canceled.Run());
295 }
296
297 // With the task tracker, post a task, a task with a reply, get a new
298 // task id, and then cancel all of them. None of the tasks nor the
299 // reply should run and the "is canceled" callback should return
300 // true.
301 TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
302 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
303 new FakeNonThreadSafeTaskRunner());
304
305 CancelableTaskTracker::IsCanceledCallback is_canceled;
306
307 {
308 // Create another task tracker with a smaller scope.
309 CancelableTaskTracker task_tracker;
310
311 ignore_result(
312 task_tracker.PostTask(
313 fake_task_runner,
314 FROM_HERE,
315 MakeExpectedNotRunClosure(FROM_HERE)));
316
317 ignore_result(
318 task_tracker.PostTaskAndReply(
319 fake_task_runner,
320 FROM_HERE,
321 MakeExpectedNotRunClosure(FROM_HERE),
322 MakeExpectedNotRunClosure(FROM_HERE)));
323
324 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
325 }
326
327 fake_task_runner->RunUntilIdle();
328
329 base::RunLoop run_loop;
330 run_loop.RunUntilIdle();
331
332 EXPECT_FALSE(is_canceled.Run());
333 }
334
335 // The death tests below make sure that calling task tracker member
336 // functions from a thread different from its owner thread DCHECKs in
337 // debug mode.
338
339 class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
340 protected:
341 CancelableTaskTrackerDeathTest() {
342 // The default style "fast" does not support multi-threaded tests.
343 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
344 }
345
346 virtual ~CancelableTaskTrackerDeathTest() {}
347 };
348
349 // Duplicated from base/threading/thread_checker.h so that we can be
350 // good citizens there and undef the macro.
351 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
352 #define ENABLE_THREAD_CHECKER 1
353 #else
354 #define ENABLE_THREAD_CHECKER 0
355 #endif
356
357 // Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
358 void MaybeRunDeadlyTaskTrackerMemberFunction(
359 CancelableTaskTracker* task_tracker,
360 const base::Callback<void(CancelableTaskTracker*)>& fn) {
361 // CancelableTask uses DCHECKs with its ThreadChecker (itself only
362 // enabled in debug mode).
363 #if ENABLE_THREAD_CHECKER
364 EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
365 #endif
366 }
367
368 void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
369 ignore_result(
370 task_tracker->PostTask(
371 scoped_refptr<FakeNonThreadSafeTaskRunner>(
372 new FakeNonThreadSafeTaskRunner()),
373 FROM_HERE, base::Bind(&base::DoNothing)));
374 }
169 375
170 TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) { 376 TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
171 // The default style "fast" does not support multi-threaded tests. 377 base::Thread bad_thread("bad thread");
172 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 378 ASSERT_TRUE(bad_thread.Start());
173 379
174 EXPECT_DEATH( 380 bad_thread.message_loop_proxy()->PostTask(
175 tracker_->PostTask(task_thread_runner_,
176 FROM_HERE,
177 DecreaseTestDataClosure(NULL)),
178 "");
179 }
180
181 void CancelOnDifferentThread_Test(CancelableTaskTrackerTest* test,
182 WaitableEvent* event) {
183 test->task_id_ = test->tracker_->PostTask(
184 test->task_thread_runner_,
185 FROM_HERE, 381 FROM_HERE,
186 test->DecreaseTestDataClosure(event)); 382 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
187 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_); 383 base::Unretained(&task_tracker_),
188 384 base::Bind(&PostDoNothingTask)));
189 // Canceling a non-existed task is noop. 385 }
190 test->tracker_->TryCancel(test->task_id_ + 1); 386
191 387 void TryCancel(CancelableTaskTracker::TaskId task_id,
192 test->UnblockTaskThread(); 388 CancelableTaskTracker* task_tracker) {
389 task_tracker->TryCancel(task_id);
193 } 390 }
194 391
195 TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) { 392 TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
196 // The default style "fast" does not support multi-threaded tests. 393 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
197 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 394 new FakeNonThreadSafeTaskRunner());
198 395
199 // Post a task and we'll try canceling it on a different thread. 396 base::Thread bad_thread("bad thread");
200 RunOnClientAndWait(&CancelOnDifferentThread_Test); 397 ASSERT_TRUE(bad_thread.Start());
201 398
202 // Canceling on the wrong thread. 399 CancelableTaskTracker::TaskId task_id =
203 EXPECT_DEATH(tracker_->TryCancel(task_id_), ""); 400 task_tracker_.PostTask(
204 401 fake_task_runner.get(),
205 // Even canceling a non-existant task will crash. 402 FROM_HERE,
206 EXPECT_DEATH(tracker_->TryCancel(task_id_ + 1), ""); 403 base::Bind(&base::DoNothing));
207 } 404 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
208 405
209 void TrackerCancelAllOnDifferentThread_Test( 406 bad_thread.message_loop_proxy()->PostTask(
210 CancelableTaskTrackerTest* test, WaitableEvent* event) {
211 test->task_id_ = test->tracker_->PostTask(
212 test->task_thread_runner_,
213 FROM_HERE, 407 FROM_HERE,
214 test->DecreaseTestDataClosure(event)); 408 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
215 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_); 409 base::Unretained(&task_tracker_),
216 test->UnblockTaskThread(); 410 base::Bind(&TryCancel, task_id)));
217 } 411
218 412 fake_task_runner->RunUntilIdle();
219 TEST_F(CancelableTaskTrackerDeathTest, TrackerCancelAllOnDifferentThread) { 413 }
220 // The default style "fast" does not support multi-threaded tests. 414
221 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 415 TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
222 416 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
223 // |tracker_| can only live on client thread. 417 new FakeNonThreadSafeTaskRunner());
224 EXPECT_DEATH(tracker_.reset(), ""); 418
225 419 base::Thread bad_thread("bad thread");
226 RunOnClientAndWait(&TrackerCancelAllOnDifferentThread_Test); 420 ASSERT_TRUE(bad_thread.Start());
227 421
228 EXPECT_DEATH(tracker_->TryCancelAll(), ""); 422 CancelableTaskTracker::TaskId task_id =
229 EXPECT_DEATH(tracker_.reset(), ""); 423 task_tracker_.PostTask(
230 } 424 fake_task_runner.get(),
231 425 FROM_HERE,
232 #endif // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && 426 base::Bind(&base::DoNothing));
233 // GTEST_HAS_DEATH_TEST 427 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
234 428
235 void Canceled_Test(CancelableTaskTrackerTest* test, WaitableEvent* event) { 429 bad_thread.message_loop_proxy()->PostTask(
236 test->task_id_ = test->tracker_->PostTask(
237 test->task_thread_runner_,
238 FROM_HERE, 430 FROM_HERE,
239 test->DecreaseTestDataClosure(event)); 431 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
240 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_); 432 base::Unretained(&task_tracker_),
241 433 base::Bind(&CancelableTaskTracker::TryCancelAll)));
242 test->tracker_->TryCancel(test->task_id_); 434
243 test->UnblockTaskThread(); 435 fake_task_runner->RunUntilIdle();
244 }
245
246 TEST_F(CancelableTaskTrackerTest, Canceled) {
247 RunOnClientAndWait(&Canceled_Test);
248 EXPECT_EQ(0, test_data_);
249 }
250
251 void SignalAndWaitThenIncrease(WaitableEvent* start_event,
252 WaitableEvent* continue_event,
253 int* data) {
254 start_event->Signal();
255 continue_event->Wait();
256 (*data)++;
257 }
258
259 void CancelWhileTaskRunning_Test(CancelableTaskTrackerTest* test,
260 WaitableEvent* event) {
261 WaitableEvent task_start_event(true, false);
262 WaitableEvent* task_continue_event = new WaitableEvent(true, false);
263
264 test->task_id_ = test->tracker_->PostTaskAndReply(
265 test->task_thread_runner_,
266 FROM_HERE,
267 Bind(&SignalAndWaitThenIncrease,
268 &task_start_event, Owned(task_continue_event), &test->test_data_),
269 test->DecreaseTestDataClosure(event));
270 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
271
272 test->UnblockTaskThread();
273 task_start_event.Wait();
274
275 // Now task is running. Let's try to cancel.
276 test->tracker_->TryCancel(test->task_id_);
277
278 // Let task continue.
279 task_continue_event->Signal();
280 }
281
282 TEST_F(CancelableTaskTrackerTest, CancelWhileTaskRunning) {
283 RunOnClientAndWait(&CancelWhileTaskRunning_Test);
284
285 // Task will continue running but reply will be canceled.
286 EXPECT_EQ(1, test_data_);
287 }
288
289 void NotCanceled_Test(CancelableTaskTrackerTest* test, WaitableEvent* event) {
290 test->task_id_ = test->tracker_->PostTaskAndReply(
291 test->task_thread_runner_,
292 FROM_HERE,
293 test->IncreaseTestDataAndSignalClosure(NULL),
294 test->DecreaseTestDataClosure(event));
295 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
296
297 test->UnblockTaskThread();
298 }
299
300 TEST_F(CancelableTaskTrackerTest, NotCanceled) {
301 RunOnClientAndWait(&NotCanceled_Test);
302 EXPECT_EQ(-1, test_data_);
303 }
304
305 void TrackerDestructed_Test(CancelableTaskTrackerTest* test,
306 WaitableEvent* event) {
307 test->task_id_ = test->tracker_->PostTaskAndReply(
308 test->task_thread_runner_,
309 FROM_HERE,
310 test->IncreaseTestDataAndSignalClosure(NULL),
311 test->DecreaseTestDataClosure(event));
312 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
313
314 test->tracker_.reset();
315 test->UnblockTaskThread();
316 }
317
318 TEST_F(CancelableTaskTrackerTest, TrackerDestructed) {
319 RunOnClientAndWait(&TrackerDestructed_Test);
320 EXPECT_EQ(0, test_data_);
321 }
322
323 void TrackerDestructedAfterTask_Test(CancelableTaskTrackerTest* test,
324 WaitableEvent* event) {
325 WaitableEvent task_done_event(true, false);
326 test->task_id_ = test->tracker_->PostTaskAndReply(
327 test->task_thread_runner_,
328 FROM_HERE,
329 test->IncreaseTestDataAndSignalClosure(&task_done_event),
330 test->DecreaseTestDataClosure(event));
331 ASSERT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
332
333 test->UnblockTaskThread();
334
335 task_done_event.Wait();
336
337 // At this point, task is already finished on task thread but reply has not
338 // started yet (because this function is still running on client thread).
339 // Now delete the tracker to cancel reply.
340 test->tracker_.reset();
341 }
342
343 TEST_F(CancelableTaskTrackerTest, TrackerDestructedAfterTask) {
344 RunOnClientAndWait(&TrackerDestructedAfterTask_Test);
345 EXPECT_EQ(1, test_data_);
346 }
347
348 void CheckTrackedTaskIdOnSameThread_Test(CancelableTaskTrackerTest* test,
349 WaitableEvent* event) {
350 CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
351 test->task_id_ = test->tracker_->NewTrackedTaskId(&is_canceled_cb);
352 ASSERT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
353
354 EXPECT_FALSE(is_canceled_cb.Run());
355
356 test->tracker_->TryCancel(test->task_id_);
357 EXPECT_TRUE(is_canceled_cb.Run());
358
359 test->task_id_ = test->tracker_->NewTrackedTaskId(&is_canceled_cb);
360 EXPECT_FALSE(is_canceled_cb.Run());
361
362 // Destroy tracker will cancel all tasks.
363 test->tracker_.reset();
364 EXPECT_TRUE(is_canceled_cb.Run());
365
366 event->Signal();
367 }
368
369 TEST_F(CancelableTaskTrackerTest, CheckTrackedTaskIdOnSameThread) {
370 RunOnClientAndWait(&CheckTrackedTaskIdOnSameThread_Test);
371 }
372
373 void CheckTrackedTaskIdOnDifferentThread_Test(CancelableTaskTrackerTest* test,
374 WaitableEvent* event) {
375 CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
376 test->task_id_ = test->tracker_->NewTrackedTaskId(&is_canceled_cb);
377 ASSERT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
378
379 // Post task to task thread.
380 test->task_thread_runner_->PostTask(
381 FROM_HERE,
382 test->IncreaseTestDataIfNotCanceledAndSignalClosure(is_canceled_cb,
383 event));
384 is_canceled_cb.Reset(); // So the one in task thread runner is the last ref,
385 // and will be destroyed on task thread.
386
387 test->tracker_->TryCancel(test->task_id_);
388 test->UnblockTaskThread();
389 }
390
391 TEST_F(CancelableTaskTrackerTest, CheckTrackedTaskIdOnDifferentThread) {
392 RunOnClientAndWait(&CheckTrackedTaskIdOnDifferentThread_Test);
393 EXPECT_EQ(0, test_data_);
394 } 436 }
395 437
396 } // namespace 438 } // 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