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

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

Issue 1465293002: Mojo C++ bindings: introduce public associated-interface-related types. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month 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
(Empty)
1 // Copyright 2015 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 <algorithm>
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/threading/thread.h"
11 #include "mojo/message_pump/message_pump_mojo.h"
12 #include "mojo/public/cpp/bindings/associated_binding.h"
13 #include "mojo/public/cpp/bindings/associated_group.h"
14 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
15 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
16 #include "mojo/public/cpp/bindings/associated_interface_request.h"
17 #include "mojo/public/cpp/bindings/binding.h"
18 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
19 #include "mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom .h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace mojo {
23 namespace test {
24 namespace {
25
26 using mojo::internal::AssociatedInterfacePtrInfoHelper;
27 using mojo::internal::AssociatedInterfaceRequestHelper;
28 using mojo::internal::MultiplexRouter;
29 using mojo::internal::ScopedInterfaceEndpointHandle;
30
31 class IntegerSenderImpl : public IntegerSender {
32 public:
33 explicit IntegerSenderImpl(AssociatedInterfaceRequest<IntegerSender> request)
34 : binding_(this, request.Pass()) {}
35
36 ~IntegerSenderImpl() override {}
37
38 void set_notify_send_method_called(
39 const base::Callback<void(int32_t)>& callback) {
40 notify_send_method_called_ = callback;
41 }
42
43 void Echo(int32_t value, const EchoCallback& callback) override {
44 callback.Run(value);
45 }
46 void Send(int32_t value) override { notify_send_method_called_.Run(value); }
47
48 AssociatedBinding<IntegerSender>* binding() { return &binding_; }
49
50 void set_connection_error_handler(const Closure& handler) {
51 binding_.set_connection_error_handler(handler);
52 }
53
54 private:
55 AssociatedBinding<IntegerSender> binding_;
56 base::Callback<void(int32_t)> notify_send_method_called_;
57 };
58
59 class AssociatedInterfaceTest : public testing::Test {
60 public:
61 AssociatedInterfaceTest() : loop_(common::MessagePumpMojo::Create()) {}
62 ~AssociatedInterfaceTest() override { loop_.RunUntilIdle(); }
63
64 void PumpMessages() { loop_.RunUntilIdle(); }
65
66 template <typename T>
67 AssociatedInterfacePtrInfo<T> EmulatePassingAssociatedPtrInfo(
68 AssociatedInterfacePtrInfo<T> ptr_info,
69 scoped_refptr<MultiplexRouter> target) {
70 ScopedInterfaceEndpointHandle handle =
71 AssociatedInterfacePtrInfoHelper::PassHandle(&ptr_info);
72 CHECK(!handle.is_local());
73
74 ScopedInterfaceEndpointHandle new_handle =
75 target->CreateLocalEndpointHandle(handle.release());
76
77 AssociatedInterfacePtrInfo<T> result;
78 AssociatedInterfacePtrInfoHelper::SetHandle(&result, new_handle.Pass());
79 result.set_version(ptr_info.version());
80 return result.Pass();
81 }
82
83 template <typename T>
84 AssociatedInterfaceRequest<T> EmulatePassingAssociatedRequest(
85 AssociatedInterfaceRequest<T> request,
86 scoped_refptr<MultiplexRouter> target) {
87 ScopedInterfaceEndpointHandle handle =
88 AssociatedInterfaceRequestHelper::PassHandle(&request);
89 CHECK(!handle.is_local());
90
91 ScopedInterfaceEndpointHandle new_handle =
92 target->CreateLocalEndpointHandle(handle.release());
93
94 AssociatedInterfaceRequest<T> result;
95 AssociatedInterfaceRequestHelper::SetHandle(&result, new_handle.Pass());
96 return result.Pass();
97 }
98
99 // Okay to call from any thread.
100 void QuitRunLoop(base::RunLoop* run_loop) {
101 if (loop_.task_runner()->BelongsToCurrentThread()) {
102 run_loop->Quit();
103 } else {
104 loop_.PostTask(
105 FROM_HERE,
106 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
107 base::Unretained(this), base::Unretained(run_loop)));
108 }
109 }
110
111 private:
112 base::MessageLoop loop_;
113 };
114
115 TEST_F(AssociatedInterfaceTest, InterfacesAtBothEnds) {
116 // Bind to the same pipe two associated interfaces, whose implementation lives
117 // at different ends. Test that the two don't interfere with each other.
118
119 MessagePipe pipe;
120 scoped_refptr<MultiplexRouter> router0(
121 new MultiplexRouter(true, pipe.handle0.Pass()));
122 scoped_refptr<MultiplexRouter> router1(
123 new MultiplexRouter(false, pipe.handle1.Pass()));
124
125 AssociatedInterfaceRequest<IntegerSender> request;
126 AssociatedInterfacePtrInfo<IntegerSender> ptr_info;
127
128 router0->CreateAssociatedGroup()->CreateAssociatedInterface(
129 AssociatedGroup::WILL_PASS_PTR, &ptr_info, &request);
130 ptr_info = EmulatePassingAssociatedPtrInfo(ptr_info.Pass(), router1);
131
132 IntegerSenderImpl impl0(request.Pass());
133 AssociatedInterfacePtr<IntegerSender> ptr0;
134 ptr0.Bind(ptr_info.Pass());
135
136 router0->CreateAssociatedGroup()->CreateAssociatedInterface(
137 AssociatedGroup::WILL_PASS_REQUEST, &ptr_info, &request);
138 request = EmulatePassingAssociatedRequest(request.Pass(), router1);
139
140 IntegerSenderImpl impl1(request.Pass());
141 AssociatedInterfacePtr<IntegerSender> ptr1;
142 ptr1.Bind(ptr_info.Pass());
143
144 bool ptr0_callback_run = false;
145 ptr0->Echo(123, [&ptr0_callback_run](int32_t value) {
146 EXPECT_EQ(123, value);
147 ptr0_callback_run = true;
148 });
149
150 bool ptr1_callback_run = false;
151 ptr1->Echo(456, [&ptr1_callback_run](int32_t value) {
152 EXPECT_EQ(456, value);
153 ptr1_callback_run = true;
154 });
155
156 PumpMessages();
157 EXPECT_TRUE(ptr0_callback_run);
158 EXPECT_TRUE(ptr1_callback_run);
159
160 bool ptr0_error_callback_run = false;
161 ptr0.set_connection_error_handler(
162 [&ptr0_error_callback_run]() { ptr0_error_callback_run = true; });
163
164 impl0.binding()->Close();
165 PumpMessages();
166 EXPECT_TRUE(ptr0_error_callback_run);
167
168 bool impl1_error_callback_run = false;
169 impl1.binding()->set_connection_error_handler(
170 [&impl1_error_callback_run]() { impl1_error_callback_run = true; });
171
172 ptr1.reset();
173 PumpMessages();
174 EXPECT_TRUE(impl1_error_callback_run);
175 }
176
177 class TestSender {
178 public:
179 TestSender()
180 : sender_thread_("TestSender"),
181 next_sender_(nullptr),
182 max_value_to_send_(-1) {
183 base::Thread::Options thread_options;
184 thread_options.message_pump_factory =
185 base::Bind(&common::MessagePumpMojo::Create);
186 sender_thread_.StartWithOptions(thread_options);
187 }
188
189 // The following three methods are called on the corresponding sender thread.
190 void SetUp(AssociatedInterfacePtrInfo<IntegerSender> ptr_info,
191 TestSender* next_sender,
192 int32_t max_value_to_send) {
193 CHECK(sender_thread_.task_runner()->BelongsToCurrentThread());
194
195 ptr_.Bind(ptr_info.Pass());
196 next_sender_ = next_sender ? next_sender : this;
197 max_value_to_send_ = max_value_to_send;
198 }
199
200 void Send(int32_t value) {
201 CHECK(sender_thread_.task_runner()->BelongsToCurrentThread());
202
203 if (value > max_value_to_send_)
204 return;
205
206 ptr_->Send(value);
207
208 next_sender_->sender_thread()->task_runner()->PostTask(
209 FROM_HERE,
210 base::Bind(&TestSender::Send, base::Unretained(next_sender_), ++value));
211 }
212
213 void TearDown() {
214 CHECK(sender_thread_.task_runner()->BelongsToCurrentThread());
215
216 ptr_.reset();
217 }
218
219 base::Thread* sender_thread() { return &sender_thread_; }
220
221 private:
222 base::Thread sender_thread_;
223 TestSender* next_sender_;
224 int32_t max_value_to_send_;
225
226 AssociatedInterfacePtr<IntegerSender> ptr_;
227 };
228
229 class TestReceiver {
230 public:
231 TestReceiver() : receiver_thread_("TestReceiver"), max_value_to_receive_(-1) {
232 base::Thread::Options thread_options;
233 thread_options.message_pump_factory =
234 base::Bind(&common::MessagePumpMojo::Create);
235 receiver_thread_.StartWithOptions(thread_options);
236 }
237
238 void SetUp(AssociatedInterfaceRequest<IntegerSender> request0,
239 AssociatedInterfaceRequest<IntegerSender> request1,
240 int32_t max_value_to_receive,
241 const base::Closure& notify_finish) {
242 CHECK(receiver_thread_.task_runner()->BelongsToCurrentThread());
243
244 impl0_.reset(new IntegerSenderImpl(request0.Pass()));
245 impl0_->set_notify_send_method_called(
246 base::Bind(&TestReceiver::SendMethodCalled, base::Unretained(this)));
247 impl1_.reset(new IntegerSenderImpl(request1.Pass()));
248 impl1_->set_notify_send_method_called(
249 base::Bind(&TestReceiver::SendMethodCalled, base::Unretained(this)));
250
251 max_value_to_receive_ = max_value_to_receive;
252 notify_finish_ = notify_finish;
253 }
254
255 void TearDown() {
256 CHECK(receiver_thread_.task_runner()->BelongsToCurrentThread());
257
258 impl0_.reset();
259 impl1_.reset();
260 }
261
262 base::Thread* receiver_thread() { return &receiver_thread_; }
263 const std::vector<int32_t>& values() const { return values_; }
264
265 private:
266 void SendMethodCalled(int32_t value) {
267 values_.push_back(value);
268
269 if (value >= max_value_to_receive_)
270 notify_finish_.Run();
271 }
272
273 base::Thread receiver_thread_;
274 int32_t max_value_to_receive_;
275
276 scoped_ptr<IntegerSenderImpl> impl0_;
277 scoped_ptr<IntegerSenderImpl> impl1_;
278
279 std::vector<int32_t> values_;
280
281 base::Closure notify_finish_;
282 };
283
284 TEST_F(AssociatedInterfaceTest, MultiThreadAccess) {
285 // Set up four associated interfaces on a message pipe. Use the inteface
286 // pointers on four threads in parallel; run the interface implementations on
287 // two threads. Test that multi-threaded access works.
288
289 const int32_t kMaxValue = 1000;
290 MessagePipe pipe;
291 scoped_refptr<MultiplexRouter> router0(
292 new MultiplexRouter(true, pipe.handle0.Pass()));
293 scoped_refptr<MultiplexRouter> router1(
294 new MultiplexRouter(false, pipe.handle1.Pass()));
295
296 AssociatedInterfaceRequest<IntegerSender> requests[4];
297 AssociatedInterfacePtrInfo<IntegerSender> ptr_infos[4];
298
299 for (size_t i = 0; i < 4; ++i) {
300 router0->CreateAssociatedGroup()->CreateAssociatedInterface(
301 AssociatedGroup::WILL_PASS_PTR, &ptr_infos[i], &requests[i]);
302 ptr_infos[i] =
303 EmulatePassingAssociatedPtrInfo(ptr_infos[i].Pass(), router1);
304 }
305
306 TestSender senders[4];
307 for (size_t i = 0; i < 4; ++i) {
308 senders[i].sender_thread()->task_runner()->PostTask(
309 FROM_HERE, base::Bind(&TestSender::SetUp, base::Unretained(&senders[i]),
310 base::Passed(&ptr_infos[i]), nullptr,
311 static_cast<int32_t>(kMaxValue * (i + 1) / 4)));
312 }
313
314 base::RunLoop run_loop;
315 TestReceiver receivers[2];
316 for (size_t i = 0; i < 2; ++i) {
317 receivers[i].receiver_thread()->task_runner()->PostTask(
318 FROM_HERE,
319 base::Bind(
320 &TestReceiver::SetUp, base::Unretained(&receivers[i]),
321 base::Passed(&requests[2 * i]), base::Passed(&requests[2 * i + 1]),
322 kMaxValue,
323 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
324 base::Unretained(this), base::Unretained(&run_loop))));
325 }
326
327 for (size_t i = 0; i < 4; ++i) {
328 senders[i].sender_thread()->task_runner()->PostTask(
329 FROM_HERE, base::Bind(&TestSender::Send, base::Unretained(&senders[i]),
330 static_cast<int32_t>(kMaxValue * i / 4 + 1)));
331 }
332
333 run_loop.Run();
334
335 for (size_t i = 0; i < 4; ++i) {
336 base::RunLoop run_loop;
337 senders[i].sender_thread()->task_runner()->PostTaskAndReply(
338 FROM_HERE,
339 base::Bind(&TestSender::TearDown, base::Unretained(&senders[i])),
340 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
341 base::Unretained(this), base::Unretained(&run_loop)));
342 run_loop.Run();
343 }
344
345 for (size_t i = 0; i < 2; ++i) {
346 base::RunLoop run_loop;
347 receivers[i].receiver_thread()->task_runner()->PostTaskAndReply(
348 FROM_HERE,
349 base::Bind(&TestReceiver::TearDown, base::Unretained(&receivers[i])),
350 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
351 base::Unretained(this), base::Unretained(&run_loop)));
352 run_loop.Run();
353 }
354
355 EXPECT_EQ(static_cast<size_t>(kMaxValue / 2), receivers[0].values().size());
356 EXPECT_EQ(static_cast<size_t>(kMaxValue / 2), receivers[1].values().size());
357
358 std::vector<int32_t> all_values;
359 all_values.insert(all_values.end(), receivers[0].values().begin(),
360 receivers[0].values().end());
361 all_values.insert(all_values.end(), receivers[1].values().begin(),
362 receivers[1].values().end());
363
364 std::sort(all_values.begin(), all_values.end());
365 for (size_t i = 0; i < all_values.size(); ++i)
366 ASSERT_EQ(static_cast<int32_t>(i + 1), all_values[i]);
367 }
368
369 TEST_F(AssociatedInterfaceTest, FIFO) {
370 // Set up four associated interfaces on a message pipe. Use the inteface
371 // pointers on four threads; run the interface implementations on two threads.
372 // Take turns to make calls using the four pointers. Test that FIFO-ness is
373 // preserved.
374
375 const int32_t kMaxValue = 100;
376 MessagePipe pipe;
377 scoped_refptr<MultiplexRouter> router0(
378 new MultiplexRouter(true, pipe.handle0.Pass()));
379 scoped_refptr<MultiplexRouter> router1(
380 new MultiplexRouter(false, pipe.handle1.Pass()));
381
382 AssociatedInterfaceRequest<IntegerSender> requests[4];
383 AssociatedInterfacePtrInfo<IntegerSender> ptr_infos[4];
384
385 for (size_t i = 0; i < 4; ++i) {
386 router0->CreateAssociatedGroup()->CreateAssociatedInterface(
387 AssociatedGroup::WILL_PASS_PTR, &ptr_infos[i], &requests[i]);
388 ptr_infos[i] =
389 EmulatePassingAssociatedPtrInfo(ptr_infos[i].Pass(), router1);
390 }
391
392 TestSender senders[4];
393 for (size_t i = 0; i < 4; ++i) {
394 senders[i].sender_thread()->task_runner()->PostTask(
395 FROM_HERE,
396 base::Bind(&TestSender::SetUp, base::Unretained(&senders[i]),
397 base::Passed(&ptr_infos[i]),
398 base::Unretained(&senders[(i + 1) % 4]), kMaxValue));
399 }
400
401 base::RunLoop run_loop;
402 TestReceiver receivers[2];
403 for (size_t i = 0; i < 2; ++i) {
404 receivers[i].receiver_thread()->task_runner()->PostTask(
405 FROM_HERE,
406 base::Bind(
407 &TestReceiver::SetUp, base::Unretained(&receivers[i]),
408 base::Passed(&requests[2 * i]), base::Passed(&requests[2 * i + 1]),
409 kMaxValue,
410 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
411 base::Unretained(this), base::Unretained(&run_loop))));
412 }
413
414 senders[0].sender_thread()->task_runner()->PostTask(
415 FROM_HERE,
416 base::Bind(&TestSender::Send, base::Unretained(&senders[0]), 1));
417
418 run_loop.Run();
419
420 for (size_t i = 0; i < 4; ++i) {
421 base::RunLoop run_loop;
422 senders[i].sender_thread()->task_runner()->PostTaskAndReply(
423 FROM_HERE,
424 base::Bind(&TestSender::TearDown, base::Unretained(&senders[i])),
425 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
426 base::Unretained(this), base::Unretained(&run_loop)));
427 run_loop.Run();
428 }
429
430 for (size_t i = 0; i < 2; ++i) {
431 base::RunLoop run_loop;
432 receivers[i].receiver_thread()->task_runner()->PostTaskAndReply(
433 FROM_HERE,
434 base::Bind(&TestReceiver::TearDown, base::Unretained(&receivers[i])),
435 base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
436 base::Unretained(this), base::Unretained(&run_loop)));
437 run_loop.Run();
438 }
439
440 EXPECT_EQ(static_cast<size_t>(kMaxValue / 2), receivers[0].values().size());
441 EXPECT_EQ(static_cast<size_t>(kMaxValue / 2), receivers[1].values().size());
442
443 for (size_t i = 0; i < 2; ++i) {
444 for (size_t j = 1; j < receivers[i].values().size(); ++j)
445 EXPECT_LT(receivers[i].values()[j - 1], receivers[i].values()[j]);
446 }
447 }
448
449 } // namespace
450 } // namespace test
451 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/tests/BUILD.gn ('k') | mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698