OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/logging.h" | 6 #include "base/logging.h" |
7 #include "base/macros.h" | 7 #include "base/macros.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "base/threading/thread.h" | 10 #include "base/threading/thread.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 ~SyncMethodTest() override { loop_.RunUntilIdle(); } | 23 ~SyncMethodTest() override { loop_.RunUntilIdle(); } |
24 | 24 |
25 private: | 25 private: |
26 base::MessageLoop loop_; | 26 base::MessageLoop loop_; |
27 }; | 27 }; |
28 | 28 |
29 class TestSyncImpl : public TestSync { | 29 class TestSyncImpl : public TestSync { |
30 public: | 30 public: |
31 TestSyncImpl(TestSyncRequest request) : binding_(this, std::move(request)) {} | 31 TestSyncImpl(TestSyncRequest request) : binding_(this, std::move(request)) {} |
32 | 32 |
33 using PingHandler = Callback<void(const PingCallback&)>; | 33 void set_ping_notification(const Closure& closure) { |
34 void set_ping_handler(const PingHandler& handler) { ping_handler_ = handler; } | 34 ping_notification_ = closure; |
35 | |
36 using EchoHandler = Callback<void(int32_t, const EchoCallback&)>; | |
37 void set_echo_handler(const EchoHandler& handler) { echo_handler_ = handler; } | |
38 | |
39 using AsyncEchoHandler = Callback<void(int32_t, const AsyncEchoCallback&)>; | |
40 void set_async_echo_handler(const AsyncEchoHandler& handler) { | |
41 async_echo_handler_ = handler; | |
42 } | 35 } |
43 | 36 |
44 // TestSync implementation: | 37 // TestSync implementation: |
| 38 void Get(const GetCallback& callback) override { callback.Run(42); } |
| 39 void Set(int32_t value, const SetCallback& callback) override { |
| 40 callback.Run(); |
| 41 } |
45 void Ping(const PingCallback& callback) override { | 42 void Ping(const PingCallback& callback) override { |
46 if (ping_handler_.is_null()) { | 43 ping_notification_.Run(); |
47 callback.Run(); | 44 callback.Run(); |
48 return; | |
49 } | |
50 ping_handler_.Run(callback); | |
51 } | 45 } |
52 void Echo(int32_t value, const EchoCallback& callback) override { | 46 void Echo(int32_t value, const EchoCallback& callback) override { |
53 if (echo_handler_.is_null()) { | 47 callback.Run(value); |
54 callback.Run(value); | |
55 return; | |
56 } | |
57 echo_handler_.Run(value, callback); | |
58 } | 48 } |
59 void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override { | |
60 if (async_echo_handler_.is_null()) { | |
61 callback.Run(value); | |
62 return; | |
63 } | |
64 async_echo_handler_.Run(value, callback); | |
65 } | |
66 | |
67 Binding<TestSync>* binding() { return &binding_; } | |
68 | 49 |
69 private: | 50 private: |
70 Binding<TestSync> binding_; | 51 Binding<TestSync> binding_; |
71 PingHandler ping_handler_; | 52 Closure ping_notification_; |
72 EchoHandler echo_handler_; | |
73 AsyncEchoHandler async_echo_handler_; | |
74 | 53 |
75 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl); | 54 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl); |
76 }; | 55 }; |
77 | 56 |
78 class TestSyncServiceThread { | 57 class TestSyncServiceThread { |
79 public: | 58 public: |
80 TestSyncServiceThread() | 59 TestSyncServiceThread() |
81 : thread_("TestSyncServiceThread"), ping_called_(false) { | 60 : thread_("TestSyncServiceThread"), ping_called_(false) { |
82 base::Thread::Options thread_options; | 61 base::Thread::Options thread_options; |
83 thread_options.message_pump_factory = | 62 thread_options.message_pump_factory = |
84 base::Bind(&common::MessagePumpMojo::Create); | 63 base::Bind(&common::MessagePumpMojo::Create); |
85 thread_.StartWithOptions(thread_options); | 64 thread_.StartWithOptions(thread_options); |
86 } | 65 } |
87 | 66 |
88 void SetUp(TestSyncRequest request) { | 67 void SetUp(TestSyncRequest request) { |
89 CHECK(thread_.task_runner()->BelongsToCurrentThread()); | 68 CHECK(thread_.task_runner()->BelongsToCurrentThread()); |
90 impl_.reset(new TestSyncImpl(std::move(request))); | 69 impl_.reset(new TestSyncImpl(std::move(request))); |
91 impl_->set_ping_handler([this](const TestSync::PingCallback& callback) { | 70 impl_->set_ping_notification([this]() { |
92 { | 71 base::AutoLock locker(lock_); |
93 base::AutoLock locker(lock_); | 72 ping_called_ = true; |
94 ping_called_ = true; | |
95 } | |
96 callback.Run(); | |
97 }); | 73 }); |
98 } | 74 } |
99 | 75 |
100 void TearDown() { | 76 void TearDown() { |
101 CHECK(thread_.task_runner()->BelongsToCurrentThread()); | 77 CHECK(thread_.task_runner()->BelongsToCurrentThread()); |
102 impl_.reset(); | 78 impl_.reset(); |
103 } | 79 } |
104 | 80 |
105 base::Thread* thread() { return &thread_; } | 81 base::Thread* thread() { return &thread_; } |
106 bool ping_called() const { | 82 bool ping_called() const { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 ASSERT_EQ(42, output_value); | 123 ASSERT_EQ(42, output_value); |
148 | 124 |
149 base::RunLoop run_loop; | 125 base::RunLoop run_loop; |
150 service_thread.thread()->task_runner()->PostTaskAndReply( | 126 service_thread.thread()->task_runner()->PostTaskAndReply( |
151 FROM_HERE, base::Bind(&TestSyncServiceThread::TearDown, | 127 FROM_HERE, base::Bind(&TestSyncServiceThread::TearDown, |
152 base::Unretained(&service_thread)), | 128 base::Unretained(&service_thread)), |
153 run_loop.QuitClosure()); | 129 run_loop.QuitClosure()); |
154 run_loop.Run(); | 130 run_loop.Run(); |
155 } | 131 } |
156 | 132 |
157 TEST_F(SyncMethodTest, ReenteredBySyncMethodBinding) { | |
158 // Test that an interface pointer waiting for a sync call response can be | |
159 // reentered by a binding serving sync methods on the same thread. | |
160 | |
161 TestSyncPtr ptr; | |
162 // The binding lives on the same thread as the interface pointer. | |
163 TestSyncImpl impl(GetProxy(&ptr)); | |
164 int32_t output_value = -1; | |
165 ASSERT_TRUE(ptr->Echo(42, &output_value)); | |
166 EXPECT_EQ(42, output_value); | |
167 } | |
168 | |
169 TEST_F(SyncMethodTest, InterefacePtrDestroyedDuringSyncCall) { | |
170 // Test that it won't result in crash or hang if an interface pointer is | |
171 // destroyed while it is waiting for a sync call response. | |
172 | |
173 TestSyncPtr ptr; | |
174 TestSyncImpl impl(GetProxy(&ptr)); | |
175 impl.set_ping_handler([&ptr](const TestSync::PingCallback& callback) { | |
176 ptr.reset(); | |
177 callback.Run(); | |
178 }); | |
179 ASSERT_FALSE(ptr->Ping()); | |
180 } | |
181 | |
182 TEST_F(SyncMethodTest, BindingDestroyedDuringSyncCall) { | |
183 // Test that it won't result in crash or hang if a binding is | |
184 // closed (and therefore the message pipe handle is closed) while the | |
185 // corresponding interface pointer is waiting for a sync call response. | |
186 | |
187 TestSyncPtr ptr; | |
188 TestSyncImpl impl(GetProxy(&ptr)); | |
189 impl.set_ping_handler([&impl](const TestSync::PingCallback& callback) { | |
190 impl.binding()->Close(); | |
191 callback.Run(); | |
192 }); | |
193 ASSERT_FALSE(ptr->Ping()); | |
194 } | |
195 | |
196 TEST_F(SyncMethodTest, NestedSyncCallsWithInOrderResponses) { | |
197 // Test that we can call a sync method on an interface ptr, while there is | |
198 // already a sync call ongoing. The responses arrive in order. | |
199 | |
200 TestSyncPtr ptr; | |
201 TestSyncImpl impl(GetProxy(&ptr)); | |
202 | |
203 // The same variable is used to store the output of the two sync calls, in | |
204 // order to test that responses are handled in the correct order. | |
205 int32_t result_value = -1; | |
206 | |
207 bool first_call = true; | |
208 impl.set_echo_handler([&first_call, &ptr, &result_value]( | |
209 int32_t value, const TestSync::EchoCallback& callback) { | |
210 if (first_call) { | |
211 first_call = false; | |
212 ASSERT_TRUE(ptr->Echo(456, &result_value)); | |
213 EXPECT_EQ(456, result_value); | |
214 } | |
215 callback.Run(value); | |
216 }); | |
217 | |
218 ASSERT_TRUE(ptr->Echo(123, &result_value)); | |
219 EXPECT_EQ(123, result_value); | |
220 } | |
221 | |
222 TEST_F(SyncMethodTest, NestedSyncCallsWithOutOfOrderResponses) { | |
223 // Test that we can call a sync method on an interface ptr, while there is | |
224 // already a sync call ongoing. The responses arrive out of order. | |
225 | |
226 TestSyncPtr ptr; | |
227 TestSyncImpl impl(GetProxy(&ptr)); | |
228 | |
229 // The same variable is used to store the output of the two sync calls, in | |
230 // order to test that responses are handled in the correct order. | |
231 int32_t result_value = -1; | |
232 | |
233 bool first_call = true; | |
234 impl.set_echo_handler([&first_call, &ptr, &result_value]( | |
235 int32_t value, const TestSync::EchoCallback& callback) { | |
236 callback.Run(value); | |
237 if (first_call) { | |
238 first_call = false; | |
239 ASSERT_TRUE(ptr->Echo(456, &result_value)); | |
240 EXPECT_EQ(456, result_value); | |
241 } | |
242 }); | |
243 | |
244 ASSERT_TRUE(ptr->Echo(123, &result_value)); | |
245 EXPECT_EQ(123, result_value); | |
246 } | |
247 | |
248 TEST_F(SyncMethodTest, AsyncResponseQueuedDuringSyncCall) { | |
249 // Test that while an interface pointer is waiting for the response to a sync | |
250 // call, async responses are queued until the sync call completes. | |
251 | |
252 TestSyncPtr ptr; | |
253 TestSyncImpl impl(GetProxy(&ptr)); | |
254 | |
255 int32_t async_echo_request_value = -1; | |
256 TestSync::AsyncEchoCallback async_echo_request_callback; | |
257 base::RunLoop run_loop1; | |
258 impl.set_async_echo_handler( | |
259 [&async_echo_request_value, &async_echo_request_callback, &run_loop1]( | |
260 int32_t value, const TestSync::AsyncEchoCallback& callback) { | |
261 async_echo_request_value = value; | |
262 async_echo_request_callback = callback; | |
263 run_loop1.Quit(); | |
264 }); | |
265 | |
266 bool async_echo_response_dispatched = false; | |
267 base::RunLoop run_loop2; | |
268 ptr->AsyncEcho(123, | |
269 [&async_echo_response_dispatched, &run_loop2](int32_t result) { | |
270 async_echo_response_dispatched = true; | |
271 EXPECT_EQ(123, result); | |
272 run_loop2.Quit(); | |
273 }); | |
274 // Run until the AsyncEcho request reaches the service side. | |
275 run_loop1.Run(); | |
276 | |
277 impl.set_echo_handler( | |
278 [&async_echo_request_value, &async_echo_request_callback]( | |
279 int32_t value, const TestSync::EchoCallback& callback) { | |
280 // Send back the async response first. | |
281 EXPECT_FALSE(async_echo_request_callback.is_null()); | |
282 async_echo_request_callback.Run(async_echo_request_value); | |
283 | |
284 callback.Run(value); | |
285 }); | |
286 | |
287 int32_t result_value = -1; | |
288 ASSERT_TRUE(ptr->Echo(456, &result_value)); | |
289 EXPECT_EQ(456, result_value); | |
290 | |
291 // Although the AsyncEcho response arrives before the Echo response, it should | |
292 // be queued and not yet dispatched. | |
293 EXPECT_FALSE(async_echo_response_dispatched); | |
294 | |
295 // Run until the AsyncEcho response is dispatched. | |
296 run_loop2.Run(); | |
297 | |
298 EXPECT_TRUE(async_echo_response_dispatched); | |
299 } | |
300 | |
301 TEST_F(SyncMethodTest, AsyncRequestQueuedDuringSyncCall) { | |
302 // Test that while an interface pointer is waiting for the response to a sync | |
303 // call, async requests for a binding running on the same thread are queued | |
304 // until the sync call completes. | |
305 | |
306 TestSyncPtr ptr; | |
307 TestSyncImpl impl(GetProxy(&ptr)); | |
308 | |
309 bool async_echo_request_dispatched = false; | |
310 impl.set_async_echo_handler([&async_echo_request_dispatched]( | |
311 int32_t value, const TestSync::AsyncEchoCallback& callback) { | |
312 async_echo_request_dispatched = true; | |
313 callback.Run(value); | |
314 }); | |
315 | |
316 bool async_echo_response_dispatched = false; | |
317 base::RunLoop run_loop; | |
318 ptr->AsyncEcho(123, | |
319 [&async_echo_response_dispatched, &run_loop](int32_t result) { | |
320 async_echo_response_dispatched = true; | |
321 EXPECT_EQ(123, result); | |
322 run_loop.Quit(); | |
323 }); | |
324 | |
325 impl.set_echo_handler([&async_echo_request_dispatched]( | |
326 int32_t value, const TestSync::EchoCallback& callback) { | |
327 // Although the AsyncEcho request is sent before the Echo request, it | |
328 // shouldn't be dispatched yet at this point, because there is an ongoing | |
329 // sync call on the same thread. | |
330 EXPECT_FALSE(async_echo_request_dispatched); | |
331 callback.Run(value); | |
332 }); | |
333 | |
334 int32_t result_value = -1; | |
335 ASSERT_TRUE(ptr->Echo(456, &result_value)); | |
336 EXPECT_EQ(456, result_value); | |
337 | |
338 // Although the AsyncEcho request is sent before the Echo request, it | |
339 // shouldn't be dispatched yet. | |
340 EXPECT_FALSE(async_echo_request_dispatched); | |
341 | |
342 // Run until the AsyncEcho response is dispatched. | |
343 run_loop.Run(); | |
344 | |
345 EXPECT_TRUE(async_echo_response_dispatched); | |
346 } | |
347 | |
348 } // namespace | 133 } // namespace |
349 } // namespace test | 134 } // namespace test |
350 } // namespace mojo | 135 } // namespace mojo |
OLD | NEW |