Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / base / message_loop / message_loop_proxy_unittest.cc
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.
4
5 #include "base/message_loop/message_loop_proxy.h"
6
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"
16
17 namespace base {
18
19 namespace {
20
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) {
27   }
28
29   void DeleteCurrentMessageLoop() {
30     current_loop_.reset();
31   }
32
33  protected:
34   virtual 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();
38
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)));
43   }
44
45   virtual 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();
52   }
53
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) {
63     }
64
65     void RecordRun() {
66       *run_on_ = MessageLoop::current();
67     }
68
69    private:
70     friend class RefCountedThreadSafe<LoopRecorder>;
71     ~LoopRecorder() {
72       *deleted_on_ = MessageLoop::current();
73       *destruct_order_ = g_order.GetNext();
74     }
75
76     MessageLoop** run_on_;
77     MessageLoop** deleted_on_;
78     int* destruct_order_;
79   };
80
81   static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
82     recorder->RecordRun();
83   }
84
85   static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
86     recorder->RecordRun();
87     MessageLoop::current()->QuitWhenIdle();
88   }
89
90   void UnblockTaskThread() {
91     thread_sync_.Signal();
92   }
93
94   void BlockTaskThreadHelper() {
95     thread_sync_.Wait();
96   }
97
98   static StaticAtomicSequenceNumber g_order;
99
100   scoped_ptr<MessageLoop> current_loop_;
101   Thread task_thread_;
102
103  private:
104   base::WaitableEvent thread_sync_;
105 };
106
107 StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
108
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;
116
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);
121
122   ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
123       FROM_HERE,
124       Bind(&RecordLoop, task_recoder),
125       Bind(&RecordLoopAndQuit, reply_recoder)));
126
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);
132
133   UnblockTaskThread();
134   current_loop_->Run();
135
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);
141 }
142
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;
150
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);
155
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();
161
162   ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
163       FROM_HERE,
164       Bind(&RecordLoop, task_recoder),
165       Bind(&RecordLoopAndQuit, reply_recoder)));
166
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());
172
173   // Nothing should have run though.
174   EXPECT_FALSE(task_run_on);
175   EXPECT_FALSE(reply_run_on);
176 }
177
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;
185
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);
190
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)));
196
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);
202
203   current_loop_->Run();
204
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);
210 }
211
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;
221
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);
226
227   // Enqueue the relay.
228   task_thread_.message_loop_proxy()->PostTaskAndReply(
229       FROM_HERE,
230       Bind(&RecordLoop, task_recoder),
231       Bind(&RecordLoopAndQuit, reply_recoder));
232
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);
238
239   UnblockTaskThread();
240
241   // Mercilessly whack the current loop before |reply| gets to run.
242   current_loop_.reset();
243
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();
249
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);
255
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.
262 }
263
264 }  // namespace
265
266 }  // namespace base