Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / base / message_loop / message_loop_task_runner_unittest.cc
bloba0d84b7edb38bd2bfa6bf3417ee70015a0bee0c5
1 // Copyright (c) 2012 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 "base/message_loop/message_loop_task_runner.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/debug/leak_annotations.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_task_runner.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/thread.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
19 namespace base {
21 class MessageLoopTaskRunnerTest : public testing::Test {
22 public:
23 MessageLoopTaskRunnerTest()
24 : current_loop_(new MessageLoop()),
25 task_thread_("task_thread"),
26 thread_sync_(true, false) {}
28 void DeleteCurrentMessageLoop() { current_loop_.reset(); }
30 protected:
31 void SetUp() override {
32 // Use SetUp() instead of the constructor to avoid posting a task to a
33 // partially constructed object.
34 task_thread_.Start();
36 // Allow us to pause the |task_thread_|'s MessageLoop.
37 task_thread_.message_loop()->PostTask(
38 FROM_HERE, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper,
39 Unretained(this)));
42 void TearDown() override {
43 // Make sure the |task_thread_| is not blocked, and stop the thread
44 // fully before destruction because its tasks may still depend on the
45 // |thread_sync_| event.
46 thread_sync_.Signal();
47 task_thread_.Stop();
48 DeleteCurrentMessageLoop();
51 // Make LoopRecorder threadsafe so that there is defined behavior even if a
52 // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
53 class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
54 public:
55 LoopRecorder(MessageLoop** run_on,
56 MessageLoop** deleted_on,
57 int* destruct_order)
58 : run_on_(run_on),
59 deleted_on_(deleted_on),
60 destruct_order_(destruct_order) {}
62 void RecordRun() { *run_on_ = MessageLoop::current(); }
64 private:
65 friend class RefCountedThreadSafe<LoopRecorder>;
66 ~LoopRecorder() {
67 *deleted_on_ = MessageLoop::current();
68 *destruct_order_ = g_order.GetNext();
71 MessageLoop** run_on_;
72 MessageLoop** deleted_on_;
73 int* destruct_order_;
76 static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
77 recorder->RecordRun();
80 static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
81 recorder->RecordRun();
82 MessageLoop::current()->QuitWhenIdle();
85 void UnblockTaskThread() { thread_sync_.Signal(); }
87 void BlockTaskThreadHelper() { thread_sync_.Wait(); }
89 static StaticAtomicSequenceNumber g_order;
91 scoped_ptr<MessageLoop> current_loop_;
92 Thread task_thread_;
94 private:
95 base::WaitableEvent thread_sync_;
98 StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
100 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) {
101 MessageLoop* task_run_on = NULL;
102 MessageLoop* task_deleted_on = NULL;
103 int task_delete_order = -1;
104 MessageLoop* reply_run_on = NULL;
105 MessageLoop* reply_deleted_on = NULL;
106 int reply_delete_order = -1;
108 scoped_refptr<LoopRecorder> task_recoder =
109 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
110 scoped_refptr<LoopRecorder> reply_recoder =
111 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
113 ASSERT_TRUE(task_thread_.task_runner()->PostTaskAndReply(
114 FROM_HERE, Bind(&RecordLoop, task_recoder),
115 Bind(&RecordLoopAndQuit, reply_recoder)));
117 // Die if base::Bind doesn't retain a reference to the recorders.
118 task_recoder = NULL;
119 reply_recoder = NULL;
120 ASSERT_FALSE(task_deleted_on);
121 ASSERT_FALSE(reply_deleted_on);
123 UnblockTaskThread();
124 current_loop_->Run();
126 EXPECT_EQ(task_thread_.message_loop(), task_run_on);
127 EXPECT_EQ(current_loop_.get(), task_deleted_on);
128 EXPECT_EQ(current_loop_.get(), reply_run_on);
129 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
130 EXPECT_LT(task_delete_order, reply_delete_order);
133 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
134 MessageLoop* task_run_on = NULL;
135 MessageLoop* task_deleted_on = NULL;
136 int task_delete_order = -1;
137 MessageLoop* reply_run_on = NULL;
138 MessageLoop* reply_deleted_on = NULL;
139 int reply_delete_order = -1;
141 scoped_refptr<LoopRecorder> task_recoder =
142 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
143 scoped_refptr<LoopRecorder> reply_recoder =
144 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
146 // Grab a task runner to a dead MessageLoop.
147 scoped_refptr<SingleThreadTaskRunner> task_runner =
148 task_thread_.task_runner();
149 UnblockTaskThread();
150 task_thread_.Stop();
152 ASSERT_FALSE(
153 task_runner->PostTaskAndReply(FROM_HERE, Bind(&RecordLoop, task_recoder),
154 Bind(&RecordLoopAndQuit, reply_recoder)));
156 // The relay should have properly deleted its resources leaving us as the only
157 // reference.
158 EXPECT_EQ(task_delete_order, reply_delete_order);
159 ASSERT_TRUE(task_recoder->HasOneRef());
160 ASSERT_TRUE(reply_recoder->HasOneRef());
162 // Nothing should have run though.
163 EXPECT_FALSE(task_run_on);
164 EXPECT_FALSE(reply_run_on);
167 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_SameLoop) {
168 MessageLoop* task_run_on = NULL;
169 MessageLoop* task_deleted_on = NULL;
170 int task_delete_order = -1;
171 MessageLoop* reply_run_on = NULL;
172 MessageLoop* reply_deleted_on = NULL;
173 int reply_delete_order = -1;
175 scoped_refptr<LoopRecorder> task_recoder =
176 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
177 scoped_refptr<LoopRecorder> reply_recoder =
178 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
180 // Enqueue the relay.
181 ASSERT_TRUE(current_loop_->task_runner()->PostTaskAndReply(
182 FROM_HERE, Bind(&RecordLoop, task_recoder),
183 Bind(&RecordLoopAndQuit, reply_recoder)));
185 // Die if base::Bind doesn't retain a reference to the recorders.
186 task_recoder = NULL;
187 reply_recoder = NULL;
188 ASSERT_FALSE(task_deleted_on);
189 ASSERT_FALSE(reply_deleted_on);
191 current_loop_->Run();
193 EXPECT_EQ(current_loop_.get(), task_run_on);
194 EXPECT_EQ(current_loop_.get(), task_deleted_on);
195 EXPECT_EQ(current_loop_.get(), reply_run_on);
196 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
197 EXPECT_LT(task_delete_order, reply_delete_order);
200 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
201 // Annotate the scope as having memory leaks to suppress heapchecker reports.
202 ANNOTATE_SCOPED_MEMORY_LEAK;
203 MessageLoop* task_run_on = NULL;
204 MessageLoop* task_deleted_on = NULL;
205 int task_delete_order = -1;
206 MessageLoop* reply_run_on = NULL;
207 MessageLoop* reply_deleted_on = NULL;
208 int reply_delete_order = -1;
210 scoped_refptr<LoopRecorder> task_recoder =
211 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
212 scoped_refptr<LoopRecorder> reply_recoder =
213 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
215 // Enqueue the relay.
216 task_thread_.task_runner()->PostTaskAndReply(
217 FROM_HERE, Bind(&RecordLoop, task_recoder),
218 Bind(&RecordLoopAndQuit, reply_recoder));
220 // Die if base::Bind doesn't retain a reference to the recorders.
221 task_recoder = NULL;
222 reply_recoder = NULL;
223 ASSERT_FALSE(task_deleted_on);
224 ASSERT_FALSE(reply_deleted_on);
226 UnblockTaskThread();
228 // Mercilessly whack the current loop before |reply| gets to run.
229 current_loop_.reset();
231 // This should ensure the relay has been run. We need to record the
232 // MessageLoop pointer before stopping the thread because Thread::Stop() will
233 // NULL out its own pointer.
234 MessageLoop* task_loop = task_thread_.message_loop();
235 task_thread_.Stop();
237 EXPECT_EQ(task_loop, task_run_on);
238 ASSERT_FALSE(task_deleted_on);
239 EXPECT_FALSE(reply_run_on);
240 ASSERT_FALSE(reply_deleted_on);
241 EXPECT_EQ(task_delete_order, reply_delete_order);
243 // The PostTaskAndReplyRelay is leaked here. Even if we had a reference to
244 // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
245 // checks that MessageLoop::current() is the the same as when the
246 // PostTaskAndReplyRelay object was constructed. However, this loop must have
247 // already been deleted in order to perform this test. See
248 // http://crbug.com/86301.
251 class MessageLoopTaskRunnerThreadingTest : public testing::Test {
252 public:
253 void Release() const {
254 AssertOnIOThread();
255 Quit();
258 void Quit() const {
259 loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
262 void AssertOnIOThread() const {
263 ASSERT_TRUE(io_thread_->task_runner()->BelongsToCurrentThread());
264 ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
267 void AssertOnFileThread() const {
268 ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread());
269 ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
272 protected:
273 void SetUp() override {
274 io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
275 file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
276 io_thread_->Start();
277 file_thread_->Start();
280 void TearDown() override {
281 io_thread_->Stop();
282 file_thread_->Stop();
285 static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) {
286 test->AssertOnFileThread();
287 test->Quit();
290 static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
292 class DeletedOnFile {
293 public:
294 explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test)
295 : test_(test) {}
297 ~DeletedOnFile() {
298 test_->AssertOnFileThread();
299 test_->Quit();
302 private:
303 MessageLoopTaskRunnerThreadingTest* test_;
306 scoped_ptr<Thread> io_thread_;
307 scoped_ptr<Thread> file_thread_;
309 private:
310 mutable MessageLoop loop_;
313 TEST_F(MessageLoopTaskRunnerThreadingTest, Release) {
314 EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this));
315 MessageLoop::current()->Run();
318 TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) {
319 DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
320 EXPECT_TRUE(
321 file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file));
322 MessageLoop::current()->Run();
325 TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) {
326 EXPECT_TRUE(file_thread_->task_runner()->PostTask(
327 FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction,
328 Unretained(this))));
329 MessageLoop::current()->Run();
332 TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) {
333 scoped_ptr<Thread> test_thread(
334 new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
335 test_thread->Start();
336 scoped_refptr<SingleThreadTaskRunner> task_runner =
337 test_thread->task_runner();
338 test_thread->Stop();
340 bool ret = task_runner->PostTask(
341 FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
342 EXPECT_FALSE(ret);
345 TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) {
346 scoped_refptr<SingleThreadTaskRunner> task_runner;
348 scoped_ptr<Thread> test_thread(
349 new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
350 test_thread->Start();
351 task_runner = test_thread->task_runner();
353 bool ret = task_runner->PostTask(
354 FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
355 EXPECT_FALSE(ret);
358 } // namespace base