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

Side by Side Diff: mojo/public/cpp/bindings/tests/sync_method_unittest.cc

Issue 1723673002: Reland "Mojo C++ bindings: support sync methods - part 2" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months 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
OLDNEW
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
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 void set_ping_notification(const Closure& closure) { 33 using PingHandler = Callback<void(const PingCallback&)>;
34 ping_notification_ = closure; 34 void set_ping_handler(const PingHandler& handler) { ping_handler_ = handler; }
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;
35 } 42 }
36 43
37 // TestSync implementation: 44 // 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 }
42 void Ping(const PingCallback& callback) override { 45 void Ping(const PingCallback& callback) override {
43 ping_notification_.Run(); 46 if (ping_handler_.is_null()) {
44 callback.Run(); 47 callback.Run();
48 return;
49 }
50 ping_handler_.Run(callback);
45 } 51 }
46 void Echo(int32_t value, const EchoCallback& callback) override { 52 void Echo(int32_t value, const EchoCallback& callback) override {
47 callback.Run(value); 53 if (echo_handler_.is_null()) {
54 callback.Run(value);
55 return;
56 }
57 echo_handler_.Run(value, callback);
48 } 58 }
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_; }
49 68
50 private: 69 private:
51 Binding<TestSync> binding_; 70 Binding<TestSync> binding_;
52 Closure ping_notification_; 71 PingHandler ping_handler_;
72 EchoHandler echo_handler_;
73 AsyncEchoHandler async_echo_handler_;
53 74
54 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl); 75 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl);
55 }; 76 };
56 77
57 class TestSyncServiceThread { 78 class TestSyncServiceThread {
58 public: 79 public:
59 TestSyncServiceThread() 80 TestSyncServiceThread()
60 : thread_("TestSyncServiceThread"), ping_called_(false) { 81 : thread_("TestSyncServiceThread"), ping_called_(false) {
61 base::Thread::Options thread_options; 82 base::Thread::Options thread_options;
62 thread_options.message_pump_factory = 83 thread_options.message_pump_factory =
63 base::Bind(&common::MessagePumpMojo::Create); 84 base::Bind(&common::MessagePumpMojo::Create);
64 thread_.StartWithOptions(thread_options); 85 thread_.StartWithOptions(thread_options);
65 } 86 }
66 87
67 void SetUp(TestSyncRequest request) { 88 void SetUp(TestSyncRequest request) {
68 CHECK(thread_.task_runner()->BelongsToCurrentThread()); 89 CHECK(thread_.task_runner()->BelongsToCurrentThread());
69 impl_.reset(new TestSyncImpl(std::move(request))); 90 impl_.reset(new TestSyncImpl(std::move(request)));
70 impl_->set_ping_notification([this]() { 91 impl_->set_ping_handler([this](const TestSync::PingCallback& callback) {
71 base::AutoLock locker(lock_); 92 {
72 ping_called_ = true; 93 base::AutoLock locker(lock_);
94 ping_called_ = true;
95 }
96 callback.Run();
73 }); 97 });
74 } 98 }
75 99
76 void TearDown() { 100 void TearDown() {
77 CHECK(thread_.task_runner()->BelongsToCurrentThread()); 101 CHECK(thread_.task_runner()->BelongsToCurrentThread());
78 impl_.reset(); 102 impl_.reset();
79 } 103 }
80 104
81 base::Thread* thread() { return &thread_; } 105 base::Thread* thread() { return &thread_; }
82 bool ping_called() const { 106 bool ping_called() const {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 ASSERT_EQ(42, output_value); 147 ASSERT_EQ(42, output_value);
124 148
125 base::RunLoop run_loop; 149 base::RunLoop run_loop;
126 service_thread.thread()->task_runner()->PostTaskAndReply( 150 service_thread.thread()->task_runner()->PostTaskAndReply(
127 FROM_HERE, base::Bind(&TestSyncServiceThread::TearDown, 151 FROM_HERE, base::Bind(&TestSyncServiceThread::TearDown,
128 base::Unretained(&service_thread)), 152 base::Unretained(&service_thread)),
129 run_loop.QuitClosure()); 153 run_loop.QuitClosure());
130 run_loop.Run(); 154 run_loop.Run();
131 } 155 }
132 156
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
133 } // namespace 348 } // namespace
134 } // namespace test 349 } // namespace test
135 } // namespace mojo 350 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/tests/router_unittest.cc ('k') | mojo/public/interfaces/bindings/tests/test_sync_methods.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698