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

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: Add comment Created 8 years, 1 month 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|.p
kaiwang 2012/11/22 02:05:54 Remove trailing p
akalin 2012/11/22 07:00:26 Done.
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 private:
45 task_thread_.reset(new Thread("task thread")); 73 // Needs to be initialized before |task_tracker_|.
kaiwang 2012/11/22 02:05:54 Why?
akalin 2012/11/22 07:00:26 Oops, looks like that's wrong. Only the methods n
46 client_thread_.reset(new Thread("client thread")); 74 MessageLoop message_loop_;
47 task_thread_->Start(); 75
48 client_thread_->Start(); 76 protected:
49 77 CancelableTaskTracker task_tracker_;
50 task_thread_runner_ = task_thread_->message_loop_proxy(); 78 };
51 client_thread_runner_ = client_thread_->message_loop_proxy(); 79
52 80 void AddFailureAt(const tracked_objects::Location& location) {
53 // Create tracker on client thread. 81 ADD_FAILURE_AT(location.file_name(), location.line_number());
54 WaitableEvent tracker_created(true, false); 82 }
55 client_thread_runner_->PostTask( 83
56 FROM_HERE, 84 // Returns a closure that fails if run.
57 Bind(&CancelableTaskTrackerTest::CreateTrackerOnClientThread, 85 base::Closure MakeExpectedNotRunClosure(
58 Unretained(this), &tracker_created)); 86 const tracked_objects::Location& location) {
59 tracker_created.Wait(); 87 return base::Bind(&AddFailureAt, location);
60 88 }
61 // Block server thread so we can prepare the test. 89
62 task_thread_runner_->PostTask( 90 // A helper class for MakeExpectedRunClosure() that fails if it is
63 FROM_HERE, 91 // destroyed without Run() having been called. This class may be used
64 Bind(&WaitableEvent::Wait, Unretained(&task_thread_start_event_))); 92 // from multiple threads as long as Run() is called at most once
65 } 93 // before destruction.
66 94 class RunChecker {
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: 95 public:
93 // Client thread posts tasks and runs replies. 96 explicit RunChecker(const tracked_objects::Location& location)
94 scoped_refptr<TaskRunner> client_thread_runner_; 97 : location_(location),
95 98 called_(false) {}
96 // Task thread runs tasks. 99
97 scoped_refptr<TaskRunner> task_thread_runner_; 100 ~RunChecker() {
98 101 if (!called_) {
99 // |tracker_| can only live on client thread. 102 ADD_FAILURE_AT(location_.file_name(), location_.line_number());
100 scoped_ptr<CancelableTaskTracker> tracker_; 103 }
101 104 }
102 CancelableTaskTracker::TaskId task_id_; 105
103 106 void Run() {
104 void UnblockTaskThread() { 107 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 } 108 }
128 109
129 private: 110 private:
130 void CreateTrackerOnClientThread(WaitableEvent* event) { 111 tracked_objects::Location location_;
131 tracker_.reset(new CancelableTaskTracker()); 112 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 }; 113 };
165 114
166 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST 115 // Returns a closure that fails on destruction if it hasn't been run.
167 116 base::Closure MakeExpectedRunClosure(
168 typedef CancelableTaskTrackerTest CancelableTaskTrackerDeathTest; 117 const tracked_objects::Location& location) {
118 return base::Bind(&RunChecker::Run, base::Owned(new RunChecker(location)));
119 }
120
121 // With the task tracker, post a task, a task with a reply, and get a
122 // new task id without canceling any of them. The tasks and the reply
123 // should run and the "is canceled" callback should return false.
124 TEST_F(CancelableTaskTrackerTest, NoCancel) {
125 base::Thread worker_thread("worker thread");
126 ASSERT_TRUE(worker_thread.Start());
127
128 ignore_result(
129 task_tracker_.PostTask(
130 worker_thread.message_loop_proxy(),
131 FROM_HERE,
132 MakeExpectedRunClosure(FROM_HERE)));
133
134 ignore_result(
135 task_tracker_.PostTaskAndReply(
136 worker_thread.message_loop_proxy(),
137 FROM_HERE,
138 MakeExpectedRunClosure(FROM_HERE),
139 MakeExpectedRunClosure(FROM_HERE)));
140
141 CancelableTaskTracker::IsCanceledCallback is_canceled;
142 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
143
144 worker_thread.Stop();
145
146 base::RunLoop run_loop;
147 run_loop.RunUntilIdle();
kaiwang 2012/11/22 02:05:54 already have this in Test destructor, necessary to
akalin 2012/11/22 07:00:26 This one is necessary (since the EXPECT below depe
148
149 EXPECT_FALSE(is_canceled.Run());
150 }
151
152 // Post a task with the task tracker but cancel it before running the
153 // task runner. The task should not run.
154 TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
155 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
156 new FakeNonThreadSafeTaskRunner());
157
158 CancelableTaskTracker::TaskId task_id =
159 task_tracker_.PostTask(
160 fake_task_runner.get(),
161 FROM_HERE,
162 MakeExpectedNotRunClosure(FROM_HERE));
163 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
164
165 EXPECT_EQ(1U, fake_task_runner->GetPendingTaskCount());
166
167 task_tracker_.TryCancel(task_id);
168
169 fake_task_runner->RunUntilIdle();
170 }
171
172 // Post a task with reply with the task tracker and cancel it before
173 // running the task runner. Neither the task nor the reply should
174 // run.
175 TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
176 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
177 new FakeNonThreadSafeTaskRunner());
178
179 CancelableTaskTracker::TaskId task_id =
180 task_tracker_.PostTaskAndReply(
181 fake_task_runner.get(),
182 FROM_HERE,
183 MakeExpectedNotRunClosure(FROM_HERE),
184 MakeExpectedNotRunClosure(FROM_HERE));
185 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
186
187 task_tracker_.TryCancel(task_id);
188
189 fake_task_runner->RunUntilIdle();
190 }
191
192 // Post a task with reply with the task tracker and cancel it after
193 // running the task runner but before running the current message
194 // loop. The task should run but the reply should not.
195 TEST_F(CancelableTaskTrackerTest, CancelReply) {
196 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
197 new FakeNonThreadSafeTaskRunner());
198
199 CancelableTaskTracker::TaskId task_id =
200 task_tracker_.PostTaskAndReply(
201 fake_task_runner.get(),
202 FROM_HERE,
203 MakeExpectedRunClosure(FROM_HERE),
204 MakeExpectedNotRunClosure(FROM_HERE));
205 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
206
207 fake_task_runner->RunUntilIdle();
208
209 task_tracker_.TryCancel(task_id);
210
211 base::RunLoop run_loop;
212 run_loop.RunUntilIdle();
kaiwang 2012/11/22 02:05:54 same here
akalin 2012/11/22 07:00:26 Done.
213 }
214
215 // Post a task with reply with the task tracker on a worker thread and
216 // cancel it before running the current message loop. The task should
217 // run but the reply should not.
218 TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
219 base::Thread worker_thread("worker thread");
220 ASSERT_TRUE(worker_thread.Start());
221
222 CancelableTaskTracker::TaskId task_id =
223 task_tracker_.PostTaskAndReply(
224 worker_thread.message_loop_proxy(),
225 FROM_HERE,
226 base::Bind(&base::DoNothing),
227 MakeExpectedNotRunClosure(FROM_HERE));
228 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
229
230 task_tracker_.TryCancel(task_id);
231
232 worker_thread.Stop();
233
234 base::RunLoop run_loop;
235 run_loop.RunUntilIdle();
236 }
237
238 void ExpectIsCanceled(
239 const CancelableTaskTracker::IsCanceledCallback& is_canceled,
240 bool expected_is_canceled) {
241 EXPECT_EQ(expected_is_canceled, is_canceled.Run());
242 }
243
244 // Create a new task ID and check its status on a separate thread
245 // before and after canceling. The is-canceled callback should be
246 // thread-safe (i.e., nothing should blow up).
247 TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
248 CancelableTaskTracker::IsCanceledCallback is_canceled;
249 CancelableTaskTracker::TaskId task_id =
250 task_tracker_.NewTrackedTaskId(&is_canceled);
251
252 EXPECT_FALSE(is_canceled.Run());
253
254 base::Thread other_thread("other thread");
255 ASSERT_TRUE(other_thread.Start());
256 other_thread.message_loop_proxy()->PostTask(
257 FROM_HERE,
258 base::Bind(&ExpectIsCanceled, is_canceled, false));
259 other_thread.Stop();
260
261 task_tracker_.TryCancel(task_id);
262
263 ASSERT_TRUE(other_thread.Start());
264 other_thread.message_loop_proxy()->PostTask(
265 FROM_HERE,
266 base::Bind(&ExpectIsCanceled, is_canceled, true));
267 other_thread.Stop();
268 }
269
270 // With the task tracker, post a task, a task with a reply, get a new
271 // task id, and then cancel all of them. None of the tasks nor the
272 // reply should run and the "is canceled" callback should return
273 // true.
274 TEST_F(CancelableTaskTrackerTest, CancelAll) {
275 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
276 new FakeNonThreadSafeTaskRunner());
277
278 ignore_result(
279 task_tracker_.PostTask(
280 fake_task_runner,
281 FROM_HERE,
282 MakeExpectedNotRunClosure(FROM_HERE)));
283
284 ignore_result(
285 task_tracker_.PostTaskAndReply(
286 fake_task_runner,
287 FROM_HERE,
288 MakeExpectedNotRunClosure(FROM_HERE),
289 MakeExpectedNotRunClosure(FROM_HERE)));
290
291 CancelableTaskTracker::IsCanceledCallback is_canceled;
292 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
293
294 task_tracker_.TryCancelAll();
295
296 fake_task_runner->RunUntilIdle();
297
298 base::RunLoop run_loop;
299 run_loop.RunUntilIdle();
300
301 EXPECT_TRUE(is_canceled.Run());
302 }
303
304 // With the task tracker, post a task, a task with a reply, get a new
305 // task id, and then cancel all of them. None of the tasks nor the
306 // reply should run and the "is canceled" callback should return
307 // true.
308 TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
309 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
310 new FakeNonThreadSafeTaskRunner());
311
312 CancelableTaskTracker::IsCanceledCallback is_canceled;
313
314 {
315 // Create another task tracker with a smaller scope.
316 CancelableTaskTracker task_tracker;
317
318 ignore_result(
319 task_tracker.PostTask(
320 fake_task_runner,
321 FROM_HERE,
322 MakeExpectedNotRunClosure(FROM_HERE)));
323
324 ignore_result(
325 task_tracker.PostTaskAndReply(
326 fake_task_runner,
327 FROM_HERE,
328 MakeExpectedNotRunClosure(FROM_HERE),
329 MakeExpectedNotRunClosure(FROM_HERE)));
330
331 ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
332 }
333
334 fake_task_runner->RunUntilIdle();
335
336 base::RunLoop run_loop;
337 run_loop.RunUntilIdle();
338
339 EXPECT_FALSE(is_canceled.Run());
340 }
341
342 // The death tests below make sure that calling task tracker member
343 // functions from a thread different from its owner thread DCHECKs in
344 // debug mode.
345
346 class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
347 protected:
348 CancelableTaskTrackerDeathTest() {
349 // The default style "fast" does not support multi-threaded tests.
350 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
351 }
352
353 virtual ~CancelableTaskTrackerDeathTest() {}
354 };
355
356 // Duplicated from base/threading/thread_checker.h so that we can be
357 // good citizens there and undef the macro.
358 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
359 #define ENABLE_THREAD_CHECKER 1
360 #else
361 #define ENABLE_THREAD_CHECKER 0
362 #endif
kaiwang 2012/11/22 02:05:54 I suggest to directly use ENABLE_THREAD_CHECKER an
akalin 2012/11/22 07:00:26 Can't; note that ENABLE_THREAD_CHECKER is #undef'e
363
364 // Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
365 void MaybeRunDeadlyTaskTrackerMemberFunction(
366 CancelableTaskTracker* task_tracker,
367 const base::Callback<void(CancelableTaskTracker*)>& fn) {
368 // CancelableTask uses DCHECKs with its ThreadChecker (itself only
369 // enabled in debug mode).
370 #if ENABLE_THREAD_CHECKER
371 EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
372 #endif
373 }
374
375 void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
376 ignore_result(
377 task_tracker->PostTask(
378 scoped_refptr<FakeNonThreadSafeTaskRunner>(
379 new FakeNonThreadSafeTaskRunner()),
380 FROM_HERE, base::Bind(&base::DoNothing)));
381 }
169 382
170 TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) { 383 TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
171 // The default style "fast" does not support multi-threaded tests. 384 base::Thread bad_thread("bad thread");
172 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 385 ASSERT_TRUE(bad_thread.Start());
173 386
174 EXPECT_DEATH( 387 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, 388 FROM_HERE,
186 test->DecreaseTestDataClosure(event)); 389 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
187 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_); 390 base::Unretained(&task_tracker_),
188 391 base::Bind(&PostDoNothingTask)));
189 // Canceling a non-existed task is noop. 392 }
190 test->tracker_->TryCancel(test->task_id_ + 1); 393
191 394 void TryCancel(CancelableTaskTracker::TaskId task_id,
192 test->UnblockTaskThread(); 395 CancelableTaskTracker* task_tracker) {
396 task_tracker->TryCancel(task_id);
193 } 397 }
194 398
195 TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) { 399 TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
196 // The default style "fast" does not support multi-threaded tests. 400 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
197 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 401 new FakeNonThreadSafeTaskRunner());
198 402
199 // Post a task and we'll try canceling it on a different thread. 403 base::Thread bad_thread("bad thread");
200 RunOnClientAndWait(&CancelOnDifferentThread_Test); 404 ASSERT_TRUE(bad_thread.Start());
201 405
202 // Canceling on the wrong thread. 406 CancelableTaskTracker::TaskId task_id =
203 EXPECT_DEATH(tracker_->TryCancel(task_id_), ""); 407 task_tracker_.PostTask(
204 408 fake_task_runner.get(),
205 // Even canceling a non-existant task will crash. 409 FROM_HERE,
206 EXPECT_DEATH(tracker_->TryCancel(task_id_ + 1), ""); 410 base::Bind(&base::DoNothing));
207 } 411 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
208 412
209 void TrackerCancelAllOnDifferentThread_Test( 413 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, 414 FROM_HERE,
214 test->DecreaseTestDataClosure(event)); 415 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
215 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_); 416 base::Unretained(&task_tracker_),
216 test->UnblockTaskThread(); 417 base::Bind(&TryCancel, task_id)));
217 } 418
218 419 fake_task_runner->RunUntilIdle();
219 TEST_F(CancelableTaskTrackerDeathTest, TrackerCancelAllOnDifferentThread) { 420 }
220 // The default style "fast" does not support multi-threaded tests. 421
221 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 422 TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
222 423 scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
223 // |tracker_| can only live on client thread. 424 new FakeNonThreadSafeTaskRunner());
224 EXPECT_DEATH(tracker_.reset(), ""); 425
225 426 base::Thread bad_thread("bad thread");
226 RunOnClientAndWait(&TrackerCancelAllOnDifferentThread_Test); 427 ASSERT_TRUE(bad_thread.Start());
227 428
228 EXPECT_DEATH(tracker_->TryCancelAll(), ""); 429 CancelableTaskTracker::TaskId task_id =
229 EXPECT_DEATH(tracker_.reset(), ""); 430 task_tracker_.PostTask(
230 } 431 fake_task_runner.get(),
231 432 FROM_HERE,
232 #endif // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && 433 base::Bind(&base::DoNothing));
233 // GTEST_HAS_DEATH_TEST 434 EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
234 435
235 void Canceled_Test(CancelableTaskTrackerTest* test, WaitableEvent* event) { 436 bad_thread.message_loop_proxy()->PostTask(
236 test->task_id_ = test->tracker_->PostTask(
237 test->task_thread_runner_,
238 FROM_HERE, 437 FROM_HERE,
239 test->DecreaseTestDataClosure(event)); 438 base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
240 EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_); 439 base::Unretained(&task_tracker_),
241 440 base::Bind(&CancelableTaskTracker::TryCancelAll)));
242 test->tracker_->TryCancel(test->task_id_); 441
243 test->UnblockTaskThread(); 442 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 } 443 }
395 444
396 } // namespace 445 } // 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