Fix for Hyperlinks do not open in new tab by Print preview window.
[chromium-blink-merge.git] / base / message_loop / message_loop_proxy_unittest.cc
blob0b0d9f8ad00715ea541636e7d2938d6781f79330
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_proxy.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/debug/leak_annotations.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace base {
19 namespace {
21 class MessageLoopProxyTest : public testing::Test {
22 public:
23 MessageLoopProxyTest()
24 : current_loop_(new MessageLoop()),
25 task_thread_("task_thread"),
26 thread_sync_(true, false) {
29 void DeleteCurrentMessageLoop() {
30 current_loop_.reset();
33 protected:
34 void SetUp() override {
35 // Use SetUp() instead of the constructor to avoid posting a task to a
36 // partialy constructed object.
37 task_thread_.Start();
39 // Allow us to pause the |task_thread_|'s MessageLoop.
40 task_thread_.message_loop()->PostTask(
41 FROM_HERE,
42 Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
45 void TearDown() override {
46 // Make sure the |task_thread_| is not blocked, and stop the thread
47 // fully before destuction because its tasks may still depend on the
48 // |thread_sync_| event.
49 thread_sync_.Signal();
50 task_thread_.Stop();
51 DeleteCurrentMessageLoop();
54 // Make LoopRecorder threadsafe so that there is defined behavior even if a
55 // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
56 class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
57 public:
58 LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
59 int* destruct_order)
60 : run_on_(run_on),
61 deleted_on_(deleted_on),
62 destruct_order_(destruct_order) {
65 void RecordRun() {
66 *run_on_ = MessageLoop::current();
69 private:
70 friend class RefCountedThreadSafe<LoopRecorder>;
71 ~LoopRecorder() {
72 *deleted_on_ = MessageLoop::current();
73 *destruct_order_ = g_order.GetNext();
76 MessageLoop** run_on_;
77 MessageLoop** deleted_on_;
78 int* destruct_order_;
81 static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
82 recorder->RecordRun();
85 static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
86 recorder->RecordRun();
87 MessageLoop::current()->QuitWhenIdle();
90 void UnblockTaskThread() {
91 thread_sync_.Signal();
94 void BlockTaskThreadHelper() {
95 thread_sync_.Wait();
98 static StaticAtomicSequenceNumber g_order;
100 scoped_ptr<MessageLoop> current_loop_;
101 Thread task_thread_;
103 private:
104 base::WaitableEvent thread_sync_;
107 StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
109 TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
110 MessageLoop* task_run_on = NULL;
111 MessageLoop* task_deleted_on = NULL;
112 int task_delete_order = -1;
113 MessageLoop* reply_run_on = NULL;
114 MessageLoop* reply_deleted_on = NULL;
115 int reply_delete_order = -1;
117 scoped_refptr<LoopRecorder> task_recoder =
118 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
119 scoped_refptr<LoopRecorder> reply_recoder =
120 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
122 ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
123 FROM_HERE,
124 Bind(&RecordLoop, task_recoder),
125 Bind(&RecordLoopAndQuit, reply_recoder)));
127 // Die if base::Bind doesn't retain a reference to the recorders.
128 task_recoder = NULL;
129 reply_recoder = NULL;
130 ASSERT_FALSE(task_deleted_on);
131 ASSERT_FALSE(reply_deleted_on);
133 UnblockTaskThread();
134 current_loop_->Run();
136 EXPECT_EQ(task_thread_.message_loop(), task_run_on);
137 EXPECT_EQ(current_loop_.get(), task_deleted_on);
138 EXPECT_EQ(current_loop_.get(), reply_run_on);
139 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
140 EXPECT_LT(task_delete_order, reply_delete_order);
143 TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
144 MessageLoop* task_run_on = NULL;
145 MessageLoop* task_deleted_on = NULL;
146 int task_delete_order = -1;
147 MessageLoop* reply_run_on = NULL;
148 MessageLoop* reply_deleted_on = NULL;
149 int reply_delete_order = -1;
151 scoped_refptr<LoopRecorder> task_recoder =
152 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
153 scoped_refptr<LoopRecorder> reply_recoder =
154 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
156 // Grab a MessageLoopProxy to a dead MessageLoop.
157 scoped_refptr<MessageLoopProxy> task_loop_proxy =
158 task_thread_.message_loop_proxy();
159 UnblockTaskThread();
160 task_thread_.Stop();
162 ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
163 FROM_HERE,
164 Bind(&RecordLoop, task_recoder),
165 Bind(&RecordLoopAndQuit, reply_recoder)));
167 // The relay should have properly deleted its resources leaving us as the only
168 // reference.
169 EXPECT_EQ(task_delete_order, reply_delete_order);
170 ASSERT_TRUE(task_recoder->HasOneRef());
171 ASSERT_TRUE(reply_recoder->HasOneRef());
173 // Nothing should have run though.
174 EXPECT_FALSE(task_run_on);
175 EXPECT_FALSE(reply_run_on);
178 TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
179 MessageLoop* task_run_on = NULL;
180 MessageLoop* task_deleted_on = NULL;
181 int task_delete_order = -1;
182 MessageLoop* reply_run_on = NULL;
183 MessageLoop* reply_deleted_on = NULL;
184 int reply_delete_order = -1;
186 scoped_refptr<LoopRecorder> task_recoder =
187 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
188 scoped_refptr<LoopRecorder> reply_recoder =
189 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
191 // Enqueue the relay.
192 ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
193 FROM_HERE,
194 Bind(&RecordLoop, task_recoder),
195 Bind(&RecordLoopAndQuit, reply_recoder)));
197 // Die if base::Bind doesn't retain a reference to the recorders.
198 task_recoder = NULL;
199 reply_recoder = NULL;
200 ASSERT_FALSE(task_deleted_on);
201 ASSERT_FALSE(reply_deleted_on);
203 current_loop_->Run();
205 EXPECT_EQ(current_loop_.get(), task_run_on);
206 EXPECT_EQ(current_loop_.get(), task_deleted_on);
207 EXPECT_EQ(current_loop_.get(), reply_run_on);
208 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
209 EXPECT_LT(task_delete_order, reply_delete_order);
212 TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
213 // Annotate the scope as having memory leaks to suppress heapchecker reports.
214 ANNOTATE_SCOPED_MEMORY_LEAK;
215 MessageLoop* task_run_on = NULL;
216 MessageLoop* task_deleted_on = NULL;
217 int task_delete_order = -1;
218 MessageLoop* reply_run_on = NULL;
219 MessageLoop* reply_deleted_on = NULL;
220 int reply_delete_order = -1;
222 scoped_refptr<LoopRecorder> task_recoder =
223 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
224 scoped_refptr<LoopRecorder> reply_recoder =
225 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
227 // Enqueue the relay.
228 task_thread_.message_loop_proxy()->PostTaskAndReply(
229 FROM_HERE,
230 Bind(&RecordLoop, task_recoder),
231 Bind(&RecordLoopAndQuit, reply_recoder));
233 // Die if base::Bind doesn't retain a reference to the recorders.
234 task_recoder = NULL;
235 reply_recoder = NULL;
236 ASSERT_FALSE(task_deleted_on);
237 ASSERT_FALSE(reply_deleted_on);
239 UnblockTaskThread();
241 // Mercilessly whack the current loop before |reply| gets to run.
242 current_loop_.reset();
244 // This should ensure the relay has been run. We need to record the
245 // MessageLoop pointer before stopping the thread because Thread::Stop() will
246 // NULL out its own pointer.
247 MessageLoop* task_loop = task_thread_.message_loop();
248 task_thread_.Stop();
250 EXPECT_EQ(task_loop, task_run_on);
251 ASSERT_FALSE(task_deleted_on);
252 EXPECT_FALSE(reply_run_on);
253 ASSERT_FALSE(reply_deleted_on);
254 EXPECT_EQ(task_delete_order, reply_delete_order);
256 // The PostTaskAndReplyRelay is leaked here. Even if we had a reference to
257 // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
258 // checks that MessageLoop::current() is the the same as when the
259 // PostTaskAndReplyRelay object was constructed. However, this loop must have
260 // aleady been deleted in order to perform this test. See
261 // http://crbug.com/86301.
264 } // namespace
266 } // namespace base