1
2 // Copyright 2013 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include <stdint.h>
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/callback_helpers.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/task_scheduler/post_task.h"
18 #include "base/test/scoped_task_environment.h"
19 #include "base/threading/sequenced_task_runner_handle.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_task_runner_handle.h"
22 #include "mojo/public/cpp/bindings/binding.h"
23 #include "mojo/public/cpp/bindings/strong_binding.h"
24 #include "mojo/public/cpp/bindings/tests/bindings_test_base.h"
25 #include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
26 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h"
27 #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h"
28 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
29 #include "mojo/public/interfaces/bindings/tests/scoping.mojom.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31
32 namespace mojo {
33 namespace test {
34 namespace {
35
36 typedef base::Callback<void(double)> CalcCallback;
37
38 class MathCalculatorImpl : public math::Calculator {
39 public:
MathCalculatorImpl(InterfaceRequest<math::Calculator> request)40 explicit MathCalculatorImpl(InterfaceRequest<math::Calculator> request)
41 : total_(0.0), binding_(this, std::move(request)) {}
~MathCalculatorImpl()42 ~MathCalculatorImpl() override {}
43
Clear(const CalcCallback & callback)44 void Clear(const CalcCallback& callback) override {
45 total_ = 0.0;
46 callback.Run(total_);
47 }
48
Add(double value,const CalcCallback & callback)49 void Add(double value, const CalcCallback& callback) override {
50 total_ += value;
51 callback.Run(total_);
52 }
53
Multiply(double value,const CalcCallback & callback)54 void Multiply(double value, const CalcCallback& callback) override {
55 total_ *= value;
56 callback.Run(total_);
57 }
58
binding()59 Binding<math::Calculator>* binding() { return &binding_; }
60
61 private:
62 double total_;
63 Binding<math::Calculator> binding_;
64 };
65
66 class MathCalculatorUI {
67 public:
MathCalculatorUI(math::CalculatorPtr calculator)68 explicit MathCalculatorUI(math::CalculatorPtr calculator)
69 : calculator_(std::move(calculator)),
70 output_(0.0) {}
71
encountered_error() const72 bool encountered_error() const { return calculator_.encountered_error(); }
set_connection_error_handler(const base::Closure & closure)73 void set_connection_error_handler(const base::Closure& closure) {
74 calculator_.set_connection_error_handler(closure);
75 }
76
Add(double value,const base::Closure & closure)77 void Add(double value, const base::Closure& closure) {
78 calculator_->Add(
79 value,
80 base::Bind(&MathCalculatorUI::Output, base::Unretained(this), closure));
81 }
82
Multiply(double value,const base::Closure & closure)83 void Multiply(double value, const base::Closure& closure) {
84 calculator_->Multiply(
85 value,
86 base::Bind(&MathCalculatorUI::Output, base::Unretained(this), closure));
87 }
88
GetOutput() const89 double GetOutput() const { return output_; }
90
GetInterfacePtr()91 math::CalculatorPtr& GetInterfacePtr() { return calculator_; }
92
93 private:
Output(const base::Closure & closure,double output)94 void Output(const base::Closure& closure, double output) {
95 output_ = output;
96 if (!closure.is_null())
97 closure.Run();
98 }
99
100 math::CalculatorPtr calculator_;
101 double output_;
102 base::Closure closure_;
103 };
104
105 class SelfDestructingMathCalculatorUI {
106 public:
SelfDestructingMathCalculatorUI(math::CalculatorPtr calculator)107 explicit SelfDestructingMathCalculatorUI(math::CalculatorPtr calculator)
108 : calculator_(std::move(calculator)), nesting_level_(0) {
109 ++num_instances_;
110 }
111
BeginTest(bool nested,const base::Closure & closure)112 void BeginTest(bool nested, const base::Closure& closure) {
113 nesting_level_ = nested ? 2 : 1;
114 calculator_->Add(
115 1.0,
116 base::Bind(&SelfDestructingMathCalculatorUI::Output,
117 base::Unretained(this), closure));
118 }
119
num_instances()120 static int num_instances() { return num_instances_; }
121
Output(const base::Closure & closure,double value)122 void Output(const base::Closure& closure, double value) {
123 if (--nesting_level_ > 0) {
124 // Add some more and wait for re-entrant call to Output!
125 calculator_->Add(
126 1.0,
127 base::Bind(&SelfDestructingMathCalculatorUI::Output,
128 base::Unretained(this), closure));
129 } else {
130 closure.Run();
131 delete this;
132 }
133 }
134
135 private:
~SelfDestructingMathCalculatorUI()136 ~SelfDestructingMathCalculatorUI() { --num_instances_; }
137
138 math::CalculatorPtr calculator_;
139 int nesting_level_;
140 static int num_instances_;
141 };
142
143 // static
144 int SelfDestructingMathCalculatorUI::num_instances_ = 0;
145
146 class ReentrantServiceImpl : public sample::Service {
147 public:
~ReentrantServiceImpl()148 ~ReentrantServiceImpl() override {}
149
ReentrantServiceImpl(InterfaceRequest<sample::Service> request)150 explicit ReentrantServiceImpl(InterfaceRequest<sample::Service> request)
151 : call_depth_(0),
152 max_call_depth_(0),
153 binding_(this, std::move(request)) {}
154
max_call_depth()155 int max_call_depth() { return max_call_depth_; }
156
Frobinate(sample::FooPtr foo,sample::Service::BazOptions baz,sample::PortPtr port,const sample::Service::FrobinateCallback & callback)157 void Frobinate(sample::FooPtr foo,
158 sample::Service::BazOptions baz,
159 sample::PortPtr port,
160 const sample::Service::FrobinateCallback& callback) override {
161 max_call_depth_ = std::max(++call_depth_, max_call_depth_);
162 if (call_depth_ == 1) {
163 EXPECT_TRUE(binding_.WaitForIncomingMethodCall());
164 }
165 call_depth_--;
166 callback.Run(5);
167 }
168
GetPort(mojo::InterfaceRequest<sample::Port> port)169 void GetPort(mojo::InterfaceRequest<sample::Port> port) override {}
170
171 private:
172 int call_depth_;
173 int max_call_depth_;
174 Binding<sample::Service> binding_;
175 };
176
177 class IntegerAccessorImpl : public sample::IntegerAccessor {
178 public:
IntegerAccessorImpl()179 IntegerAccessorImpl() : integer_(0) {}
~IntegerAccessorImpl()180 ~IntegerAccessorImpl() override {}
181
integer() const182 int64_t integer() const { return integer_; }
183
set_closure(const base::Closure & closure)184 void set_closure(const base::Closure& closure) { closure_ = closure; }
185
186 private:
187 // sample::IntegerAccessor implementation.
GetInteger(const GetIntegerCallback & callback)188 void GetInteger(const GetIntegerCallback& callback) override {
189 callback.Run(integer_, sample::Enum::VALUE);
190 }
SetInteger(int64_t data,sample::Enum type)191 void SetInteger(int64_t data, sample::Enum type) override {
192 integer_ = data;
193 if (!closure_.is_null()) {
194 closure_.Run();
195 closure_.Reset();
196 }
197 }
198
199 int64_t integer_;
200 base::Closure closure_;
201 };
202
203 class InterfacePtrTest : public BindingsTestBase {
204 public:
InterfacePtrTest()205 InterfacePtrTest() {}
~InterfacePtrTest()206 ~InterfacePtrTest() override { base::RunLoop().RunUntilIdle(); }
207
PumpMessages()208 void PumpMessages() { base::RunLoop().RunUntilIdle(); }
209 };
210
SetFlagAndRunClosure(bool * flag,const base::Closure & closure)211 void SetFlagAndRunClosure(bool* flag, const base::Closure& closure) {
212 *flag = true;
213 closure.Run();
214 }
215
IgnoreValueAndRunClosure(const base::Closure & closure,int32_t value)216 void IgnoreValueAndRunClosure(const base::Closure& closure, int32_t value) {
217 closure.Run();
218 }
219
ExpectValueAndRunClosure(uint32_t expected_value,const base::Closure & closure,uint32_t value)220 void ExpectValueAndRunClosure(uint32_t expected_value,
221 const base::Closure& closure,
222 uint32_t value) {
223 EXPECT_EQ(expected_value, value);
224 closure.Run();
225 }
226
TEST_P(InterfacePtrTest,IsBound)227 TEST_P(InterfacePtrTest, IsBound) {
228 math::CalculatorPtr calc;
229 EXPECT_FALSE(calc.is_bound());
230 MathCalculatorImpl calc_impl(MakeRequest(&calc));
231 EXPECT_TRUE(calc.is_bound());
232 }
233
234 class EndToEndInterfacePtrTest : public InterfacePtrTest {
235 public:
RunTest(const scoped_refptr<base::SequencedTaskRunner> runner)236 void RunTest(const scoped_refptr<base::SequencedTaskRunner> runner) {
237 base::RunLoop run_loop;
238 done_closure_ = run_loop.QuitClosure();
239 done_runner_ = base::ThreadTaskRunnerHandle::Get();
240 runner->PostTask(FROM_HERE,
241 base::Bind(&EndToEndInterfacePtrTest::RunTestImpl,
242 base::Unretained(this)));
243 run_loop.Run();
244 }
245
246 private:
RunTestImpl()247 void RunTestImpl() {
248 math::CalculatorPtr calc;
249 calc_impl_ = std::make_unique<MathCalculatorImpl>(MakeRequest(&calc));
250 calculator_ui_ = std::make_unique<MathCalculatorUI>(std::move(calc));
251 calculator_ui_->Add(2.0, base::Bind(&EndToEndInterfacePtrTest::AddDone,
252 base::Unretained(this)));
253 calculator_ui_->Multiply(5.0,
254 base::Bind(&EndToEndInterfacePtrTest::MultiplyDone,
255 base::Unretained(this)));
256 EXPECT_EQ(0.0, calculator_ui_->GetOutput());
257 }
258
AddDone()259 void AddDone() { EXPECT_EQ(2.0, calculator_ui_->GetOutput()); }
260
MultiplyDone()261 void MultiplyDone() {
262 EXPECT_EQ(10.0, calculator_ui_->GetOutput());
263 calculator_ui_.reset();
264 calc_impl_.reset();
265 done_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&done_closure_));
266 }
267
268 base::Closure done_closure_;
269 scoped_refptr<base::SingleThreadTaskRunner> done_runner_;
270 std::unique_ptr<MathCalculatorUI> calculator_ui_;
271 std::unique_ptr<MathCalculatorImpl> calc_impl_;
272 };
273
TEST_P(EndToEndInterfacePtrTest,EndToEnd)274 TEST_P(EndToEndInterfacePtrTest, EndToEnd) {
275 RunTest(base::ThreadTaskRunnerHandle::Get());
276 }
277
TEST_P(EndToEndInterfacePtrTest,EndToEndOnSequence)278 TEST_P(EndToEndInterfacePtrTest, EndToEndOnSequence) {
279 RunTest(base::CreateSequencedTaskRunnerWithTraits({}));
280 }
281
TEST_P(InterfacePtrTest,Movable)282 TEST_P(InterfacePtrTest, Movable) {
283 math::CalculatorPtr a;
284 math::CalculatorPtr b;
285 MathCalculatorImpl calc_impl(MakeRequest(&b));
286
287 EXPECT_TRUE(!a);
288 EXPECT_FALSE(!b);
289
290 a = std::move(b);
291
292 EXPECT_FALSE(!a);
293 EXPECT_TRUE(!b);
294 }
295
TEST_P(InterfacePtrTest,Resettable)296 TEST_P(InterfacePtrTest, Resettable) {
297 math::CalculatorPtr a;
298
299 EXPECT_TRUE(!a);
300
301 MessagePipe pipe;
302
303 // Save this so we can test it later.
304 Handle handle = pipe.handle0.get();
305
306 a = MakeProxy(
307 InterfacePtrInfo<math::Calculator>(std::move(pipe.handle0), 0u));
308
309 EXPECT_FALSE(!a);
310
311 a.reset();
312
313 EXPECT_TRUE(!a);
314 EXPECT_FALSE(a.internal_state()->is_bound());
315
316 // Test that handle was closed.
317 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle));
318 }
319
TEST_P(InterfacePtrTest,BindInvalidHandle)320 TEST_P(InterfacePtrTest, BindInvalidHandle) {
321 math::CalculatorPtr ptr;
322 EXPECT_FALSE(ptr.get());
323 EXPECT_FALSE(ptr);
324
325 ptr.Bind(InterfacePtrInfo<math::Calculator>());
326 EXPECT_FALSE(ptr.get());
327 EXPECT_FALSE(ptr);
328 }
329
TEST_P(InterfacePtrTest,EncounteredError)330 TEST_P(InterfacePtrTest, EncounteredError) {
331 math::CalculatorPtr proxy;
332 MathCalculatorImpl calc_impl(MakeRequest(&proxy));
333
334 MathCalculatorUI calculator_ui(std::move(proxy));
335
336 base::RunLoop run_loop;
337 calculator_ui.Add(2.0, run_loop.QuitClosure());
338 run_loop.Run();
339 EXPECT_EQ(2.0, calculator_ui.GetOutput());
340 EXPECT_FALSE(calculator_ui.encountered_error());
341
342 calculator_ui.Multiply(5.0, base::Closure());
343 EXPECT_FALSE(calculator_ui.encountered_error());
344
345 // Close the server.
346 calc_impl.binding()->Close();
347
348 // The state change isn't picked up locally yet.
349 base::RunLoop run_loop2;
350 calculator_ui.set_connection_error_handler(run_loop2.QuitClosure());
351 EXPECT_FALSE(calculator_ui.encountered_error());
352
353 run_loop2.Run();
354
355 // OK, now we see the error.
356 EXPECT_TRUE(calculator_ui.encountered_error());
357 }
358
TEST_P(InterfacePtrTest,EncounteredErrorCallback)359 TEST_P(InterfacePtrTest, EncounteredErrorCallback) {
360 math::CalculatorPtr proxy;
361 MathCalculatorImpl calc_impl(MakeRequest(&proxy));
362
363 bool encountered_error = false;
364 base::RunLoop run_loop;
365 proxy.set_connection_error_handler(
366 base::Bind(&SetFlagAndRunClosure, &encountered_error,
367 run_loop.QuitClosure()));
368
369 MathCalculatorUI calculator_ui(std::move(proxy));
370
371 base::RunLoop run_loop2;
372 calculator_ui.Add(2.0, run_loop2.QuitClosure());
373 run_loop2.Run();
374 EXPECT_EQ(2.0, calculator_ui.GetOutput());
375 EXPECT_FALSE(calculator_ui.encountered_error());
376
377 calculator_ui.Multiply(5.0, base::Closure());
378 EXPECT_FALSE(calculator_ui.encountered_error());
379
380 // Close the server.
381 calc_impl.binding()->Close();
382
383 // The state change isn't picked up locally yet.
384 EXPECT_FALSE(calculator_ui.encountered_error());
385
386 run_loop.Run();
387
388 // OK, now we see the error.
389 EXPECT_TRUE(calculator_ui.encountered_error());
390
391 // We should have also been able to observe the error through the error
392 // handler.
393 EXPECT_TRUE(encountered_error);
394 }
395
TEST_P(InterfacePtrTest,DestroyInterfacePtrOnMethodResponse)396 TEST_P(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) {
397 math::CalculatorPtr proxy;
398 MathCalculatorImpl calc_impl(MakeRequest(&proxy));
399
400 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
401
402 SelfDestructingMathCalculatorUI* impl =
403 new SelfDestructingMathCalculatorUI(std::move(proxy));
404 base::RunLoop run_loop;
405 impl->BeginTest(false, run_loop.QuitClosure());
406 run_loop.Run();
407
408 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
409 }
410
TEST_P(InterfacePtrTest,NestedDestroyInterfacePtrOnMethodResponse)411 TEST_P(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) {
412 math::CalculatorPtr proxy;
413 MathCalculatorImpl calc_impl(MakeRequest(&proxy));
414
415 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
416
417 SelfDestructingMathCalculatorUI* impl =
418 new SelfDestructingMathCalculatorUI(std::move(proxy));
419 base::RunLoop run_loop;
420 impl->BeginTest(true, run_loop.QuitClosure());
421 run_loop.Run();
422
423 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
424 }
425
TEST_P(InterfacePtrTest,ReentrantWaitForIncomingMethodCall)426 TEST_P(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) {
427 sample::ServicePtr proxy;
428 ReentrantServiceImpl impl(MakeRequest(&proxy));
429
430 base::RunLoop run_loop, run_loop2;
431 proxy->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
432 base::Bind(&IgnoreValueAndRunClosure,
433 run_loop.QuitClosure()));
434 proxy->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
435 base::Bind(&IgnoreValueAndRunClosure,
436 run_loop2.QuitClosure()));
437
438 run_loop.Run();
439 run_loop2.Run();
440
441 EXPECT_EQ(2, impl.max_call_depth());
442 }
443
TEST_P(InterfacePtrTest,QueryVersion)444 TEST_P(InterfacePtrTest, QueryVersion) {
445 IntegerAccessorImpl impl;
446 sample::IntegerAccessorPtr ptr;
447 Binding<sample::IntegerAccessor> binding(&impl, MakeRequest(&ptr));
448
449 EXPECT_EQ(0u, ptr.version());
450
451 base::RunLoop run_loop;
452 ptr.QueryVersion(base::Bind(&ExpectValueAndRunClosure, 3u,
453 run_loop.QuitClosure()));
454 run_loop.Run();
455
456 EXPECT_EQ(3u, ptr.version());
457 }
458
TEST_P(InterfacePtrTest,RequireVersion)459 TEST_P(InterfacePtrTest, RequireVersion) {
460 IntegerAccessorImpl impl;
461 sample::IntegerAccessorPtr ptr;
462 Binding<sample::IntegerAccessor> binding(&impl, MakeRequest(&ptr));
463
464 EXPECT_EQ(0u, ptr.version());
465
466 ptr.RequireVersion(1u);
467 EXPECT_EQ(1u, ptr.version());
468 base::RunLoop run_loop;
469 impl.set_closure(run_loop.QuitClosure());
470 ptr->SetInteger(123, sample::Enum::VALUE);
471 run_loop.Run();
472 EXPECT_FALSE(ptr.encountered_error());
473 EXPECT_EQ(123, impl.integer());
474
475 ptr.RequireVersion(3u);
476 EXPECT_EQ(3u, ptr.version());
477 base::RunLoop run_loop2;
478 impl.set_closure(run_loop2.QuitClosure());
479 ptr->SetInteger(456, sample::Enum::VALUE);
480 run_loop2.Run();
481 EXPECT_FALSE(ptr.encountered_error());
482 EXPECT_EQ(456, impl.integer());
483
484 // Require a version that is not supported by the impl side.
485 ptr.RequireVersion(4u);
486 // This value is set to the input of RequireVersion() synchronously.
487 EXPECT_EQ(4u, ptr.version());
488 base::RunLoop run_loop3;
489 ptr.set_connection_error_handler(run_loop3.QuitClosure());
490 ptr->SetInteger(789, sample::Enum::VALUE);
491 run_loop3.Run();
492 EXPECT_TRUE(ptr.encountered_error());
493 // The call to SetInteger() after RequireVersion(4u) is ignored.
494 EXPECT_EQ(456, impl.integer());
495 }
496
497 class StrongMathCalculatorImpl : public math::Calculator {
498 public:
StrongMathCalculatorImpl(bool * destroyed)499 StrongMathCalculatorImpl(bool* destroyed) : destroyed_(destroyed) {}
~StrongMathCalculatorImpl()500 ~StrongMathCalculatorImpl() override { *destroyed_ = true; }
501
502 // math::Calculator implementation.
Clear(const CalcCallback & callback)503 void Clear(const CalcCallback& callback) override { callback.Run(total_); }
504
Add(double value,const CalcCallback & callback)505 void Add(double value, const CalcCallback& callback) override {
506 total_ += value;
507 callback.Run(total_);
508 }
509
Multiply(double value,const CalcCallback & callback)510 void Multiply(double value, const CalcCallback& callback) override {
511 total_ *= value;
512 callback.Run(total_);
513 }
514
515 private:
516 double total_ = 0.0;
517 bool* destroyed_;
518 };
519
TEST(StrongConnectorTest,Math)520 TEST(StrongConnectorTest, Math) {
521 base::MessageLoop loop;
522
523 bool error_received = false;
524 bool destroyed = false;
525 math::CalculatorPtr calc;
526 base::RunLoop run_loop;
527
528 auto binding =
529 MakeStrongBinding(std::make_unique<StrongMathCalculatorImpl>(&destroyed),
530 MakeRequest(&calc));
531 binding->set_connection_error_handler(base::Bind(
532 &SetFlagAndRunClosure, &error_received, run_loop.QuitClosure()));
533
534 {
535 // Suppose this is instantiated in a process that has the other end of the
536 // message pipe.
537 MathCalculatorUI calculator_ui(std::move(calc));
538
539 base::RunLoop run_loop, run_loop2;
540 calculator_ui.Add(2.0, run_loop.QuitClosure());
541 calculator_ui.Multiply(5.0, run_loop2.QuitClosure());
542 run_loop.Run();
543 run_loop2.Run();
544
545 EXPECT_EQ(10.0, calculator_ui.GetOutput());
546 EXPECT_FALSE(error_received);
547 EXPECT_FALSE(destroyed);
548 }
549 // Destroying calculator_ui should close the pipe and generate an error on the
550 // other
551 // end which will destroy the instance since it is strongly bound.
552
553 run_loop.Run();
554 EXPECT_TRUE(error_received);
555 EXPECT_TRUE(destroyed);
556 }
557
558 class WeakMathCalculatorImpl : public math::Calculator {
559 public:
WeakMathCalculatorImpl(math::CalculatorRequest request,bool * error_received,bool * destroyed,const base::Closure & closure)560 WeakMathCalculatorImpl(math::CalculatorRequest request,
561 bool* error_received,
562 bool* destroyed,
563 const base::Closure& closure)
564 : error_received_(error_received),
565 destroyed_(destroyed),
566 closure_(closure),
567 binding_(this, std::move(request)) {
568 binding_.set_connection_error_handler(
569 base::Bind(&SetFlagAndRunClosure, error_received_, closure_));
570 }
~WeakMathCalculatorImpl()571 ~WeakMathCalculatorImpl() override { *destroyed_ = true; }
572
Clear(const CalcCallback & callback)573 void Clear(const CalcCallback& callback) override { callback.Run(total_); }
574
Add(double value,const CalcCallback & callback)575 void Add(double value, const CalcCallback& callback) override {
576 total_ += value;
577 callback.Run(total_);
578 }
579
Multiply(double value,const CalcCallback & callback)580 void Multiply(double value, const CalcCallback& callback) override {
581 total_ *= value;
582 callback.Run(total_);
583 }
584
585 private:
586 double total_ = 0.0;
587 bool* error_received_;
588 bool* destroyed_;
589 base::Closure closure_;
590
591 Binding<math::Calculator> binding_;
592 };
593
TEST(WeakConnectorTest,Math)594 TEST(WeakConnectorTest, Math) {
595 base::MessageLoop loop;
596
597 bool error_received = false;
598 bool destroyed = false;
599 MessagePipe pipe;
600 base::RunLoop run_loop;
601 WeakMathCalculatorImpl impl(math::CalculatorRequest(std::move(pipe.handle0)),
602 &error_received, &destroyed,
603 run_loop.QuitClosure());
604
605 math::CalculatorPtr calc;
606 calc.Bind(InterfacePtrInfo<math::Calculator>(std::move(pipe.handle1), 0u));
607
608 {
609 // Suppose this is instantiated in a process that has the other end of the
610 // message pipe.
611 MathCalculatorUI calculator_ui(std::move(calc));
612
613 base::RunLoop run_loop, run_loop2;
614 calculator_ui.Add(2.0, run_loop.QuitClosure());
615 calculator_ui.Multiply(5.0, run_loop2.QuitClosure());
616 run_loop.Run();
617 run_loop2.Run();
618
619 EXPECT_EQ(10.0, calculator_ui.GetOutput());
620 EXPECT_FALSE(error_received);
621 EXPECT_FALSE(destroyed);
622 // Destroying calculator_ui should close the pipe and generate an error on
623 // the other
624 // end which will destroy the instance since it is strongly bound.
625 }
626
627 run_loop.Run();
628 EXPECT_TRUE(error_received);
629 EXPECT_FALSE(destroyed);
630 }
631
632 class CImpl : public C {
633 public:
CImpl(bool * d_called,const base::Closure & closure)634 CImpl(bool* d_called, const base::Closure& closure)
635 : d_called_(d_called), closure_(closure) {}
~CImpl()636 ~CImpl() override {}
637
638 private:
D()639 void D() override {
640 *d_called_ = true;
641 closure_.Run();
642 }
643
644 bool* d_called_;
645 base::Closure closure_;
646 };
647
648 class BImpl : public B {
649 public:
BImpl(bool * d_called,const base::Closure & closure)650 BImpl(bool* d_called, const base::Closure& closure)
651 : d_called_(d_called), closure_(closure) {}
~BImpl()652 ~BImpl() override {}
653
654 private:
GetC(InterfaceRequest<C> c)655 void GetC(InterfaceRequest<C> c) override {
656 MakeStrongBinding(std::make_unique<CImpl>(d_called_, closure_),
657 std::move(c));
658 }
659
660 bool* d_called_;
661 base::Closure closure_;
662 };
663
664 class AImpl : public A {
665 public:
AImpl(InterfaceRequest<A> request,const base::Closure & closure)666 AImpl(InterfaceRequest<A> request, const base::Closure& closure)
667 : d_called_(false), binding_(this, std::move(request)),
668 closure_(closure) {}
~AImpl()669 ~AImpl() override {}
670
d_called() const671 bool d_called() const { return d_called_; }
672
673 private:
GetB(InterfaceRequest<B> b)674 void GetB(InterfaceRequest<B> b) override {
675 MakeStrongBinding(std::make_unique<BImpl>(&d_called_, closure_),
676 std::move(b));
677 }
678
679 bool d_called_;
680 Binding<A> binding_;
681 base::Closure closure_;
682 };
683
TEST_P(InterfacePtrTest,Scoping)684 TEST_P(InterfacePtrTest, Scoping) {
685 APtr a;
686 base::RunLoop run_loop;
687 AImpl a_impl(MakeRequest(&a), run_loop.QuitClosure());
688
689 EXPECT_FALSE(a_impl.d_called());
690
691 {
692 BPtr b;
693 a->GetB(MakeRequest(&b));
694 CPtr c;
695 b->GetC(MakeRequest(&c));
696 c->D();
697 }
698
699 // While B & C have fallen out of scope, the pipes will remain until they are
700 // flushed.
701 EXPECT_FALSE(a_impl.d_called());
702 run_loop.Run();
703 EXPECT_TRUE(a_impl.d_called());
704 }
705
706 class PingTestImpl : public sample::PingTest {
707 public:
PingTestImpl(InterfaceRequest<sample::PingTest> request)708 explicit PingTestImpl(InterfaceRequest<sample::PingTest> request)
709 : binding_(this, std::move(request)) {}
~PingTestImpl()710 ~PingTestImpl() override {}
711
712 private:
713 // sample::PingTest:
Ping(const PingCallback & callback)714 void Ping(const PingCallback& callback) override { callback.Run(); }
715
716 Binding<sample::PingTest> binding_;
717 };
718
719 // Tests that FuseProxy does what it's supposed to do.
TEST_P(InterfacePtrTest,Fusion)720 TEST_P(InterfacePtrTest, Fusion) {
721 sample::PingTestPtrInfo proxy_info;
722 PingTestImpl impl(MakeRequest(&proxy_info));
723
724 // Create another PingTest pipe and fuse it to the one hanging off |impl|.
725 sample::PingTestPtr ptr;
726 EXPECT_TRUE(FuseInterface(mojo::MakeRequest(&ptr), std::move(proxy_info)));
727
728 // Ping!
729 bool called = false;
730 base::RunLoop loop;
731 ptr->Ping(base::Bind(&SetFlagAndRunClosure, &called, loop.QuitClosure()));
732 loop.Run();
733 EXPECT_TRUE(called);
734 }
735
Fail()736 void Fail() {
737 FAIL() << "Unexpected connection error";
738 }
739
TEST_P(InterfacePtrTest,FlushForTesting)740 TEST_P(InterfacePtrTest, FlushForTesting) {
741 math::CalculatorPtr calc;
742 MathCalculatorImpl calc_impl(MakeRequest(&calc));
743 calc.set_connection_error_handler(base::Bind(&Fail));
744
745 MathCalculatorUI calculator_ui(std::move(calc));
746
747 calculator_ui.Add(2.0, base::DoNothing());
748 calculator_ui.GetInterfacePtr().FlushForTesting();
749 EXPECT_EQ(2.0, calculator_ui.GetOutput());
750
751 calculator_ui.Multiply(5.0, base::DoNothing());
752 calculator_ui.GetInterfacePtr().FlushForTesting();
753
754 EXPECT_EQ(10.0, calculator_ui.GetOutput());
755 }
756
SetBool(bool * value)757 void SetBool(bool* value) {
758 *value = true;
759 }
760
TEST_P(InterfacePtrTest,FlushForTestingWithClosedPeer)761 TEST_P(InterfacePtrTest, FlushForTestingWithClosedPeer) {
762 math::CalculatorPtr calc;
763 MakeRequest(&calc);
764 bool called = false;
765 calc.set_connection_error_handler(base::Bind(&SetBool, &called));
766 calc.FlushForTesting();
767 EXPECT_TRUE(called);
768 calc.FlushForTesting();
769 }
770
TEST_P(InterfacePtrTest,ConnectionErrorWithReason)771 TEST_P(InterfacePtrTest, ConnectionErrorWithReason) {
772 math::CalculatorPtr calc;
773 MathCalculatorImpl calc_impl(MakeRequest(&calc));
774
775 base::RunLoop run_loop;
776 calc.set_connection_error_with_reason_handler(base::Bind(
777 [](const base::Closure& quit_closure, uint32_t custom_reason,
778 const std::string& description) {
779 EXPECT_EQ(42u, custom_reason);
780 EXPECT_EQ("hey", description);
781 quit_closure.Run();
782 },
783 run_loop.QuitClosure()));
784
785 calc_impl.binding()->CloseWithReason(42u, "hey");
786
787 run_loop.Run();
788 }
789
TEST_P(InterfacePtrTest,InterfaceRequestResetWithReason)790 TEST_P(InterfacePtrTest, InterfaceRequestResetWithReason) {
791 math::CalculatorPtr calc;
792 auto request = MakeRequest(&calc);
793
794 base::RunLoop run_loop;
795 calc.set_connection_error_with_reason_handler(base::Bind(
796 [](const base::Closure& quit_closure, uint32_t custom_reason,
797 const std::string& description) {
798 EXPECT_EQ(88u, custom_reason);
799 EXPECT_EQ("greetings", description);
800 quit_closure.Run();
801 },
802 run_loop.QuitClosure()));
803
804 request.ResetWithReason(88u, "greetings");
805
806 run_loop.Run();
807 }
808
TEST_P(InterfacePtrTest,CallbackIsPassedInterfacePtr)809 TEST_P(InterfacePtrTest, CallbackIsPassedInterfacePtr) {
810 sample::PingTestPtr ptr;
811 auto request = mojo::MakeRequest(&ptr);
812
813 base::RunLoop run_loop;
814
815 // Make a call with the proxy's lifetime bound to the response callback.
816 sample::PingTest* raw_proxy = ptr.get();
817 ptr.set_connection_error_handler(run_loop.QuitClosure());
818 raw_proxy->Ping(base::Bind(base::DoNothing::Repeatedly<sample::PingTestPtr>(),
819 base::Passed(&ptr)));
820
821 // Trigger an error on |ptr|. This will ultimately lead to the proxy's
822 // response callbacks being destroyed, which will in turn lead to the proxy
823 // being destroyed. This should not crash.
824 request.PassMessagePipe();
825 run_loop.Run();
826 }
827
TEST_P(InterfacePtrTest,ConnectionErrorHandlerOwnsInterfacePtr)828 TEST_P(InterfacePtrTest, ConnectionErrorHandlerOwnsInterfacePtr) {
829 sample::PingTestPtr* ptr = new sample::PingTestPtr;
830 auto request = mojo::MakeRequest(ptr);
831
832 base::RunLoop run_loop;
833
834 // Make a call with |ptr|'s lifetime bound to the connection error handler
835 // callback.
836 ptr->set_connection_error_handler(base::Bind(
837 [](const base::Closure& quit, sample::PingTestPtr* ptr) {
838 ptr->reset();
839 quit.Run();
840 },
841 run_loop.QuitClosure(), base::Owned(ptr)));
842
843 // Trigger an error on |ptr|. In the error handler |ptr| is reset. This
844 // shouldn't immediately destroy the callback (and |ptr| that it owns), before
845 // the callback is completed.
846 request.PassMessagePipe();
847 run_loop.Run();
848 }
849
TEST_P(InterfacePtrTest,ThreadSafeInterfacePointer)850 TEST_P(InterfacePtrTest, ThreadSafeInterfacePointer) {
851 math::CalculatorPtr ptr;
852 MathCalculatorImpl calc_impl(MakeRequest(&ptr));
853 scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr =
854 math::ThreadSafeCalculatorPtr::Create(std::move(ptr));
855
856 base::RunLoop run_loop;
857
858 auto run_method = base::Bind(
859 [](const scoped_refptr<base::TaskRunner>& main_task_runner,
860 const base::Closure& quit_closure,
861 const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr) {
862 auto calc_callback = base::Bind(
863 [](const scoped_refptr<base::TaskRunner>& main_task_runner,
864 const base::Closure& quit_closure,
865 scoped_refptr<base::SequencedTaskRunner> sender_sequence_runner,
866 double result) {
867 EXPECT_EQ(123, result);
868 // Validate the callback is invoked on the calling sequence.
869 EXPECT_TRUE(sender_sequence_runner->RunsTasksInCurrentSequence());
870 // Notify the run_loop to quit.
871 main_task_runner->PostTask(FROM_HERE, quit_closure);
872 });
873 scoped_refptr<base::SequencedTaskRunner> current_sequence_runner =
874 base::SequencedTaskRunnerHandle::Get();
875 (*thread_safe_ptr)
876 ->Add(123, base::Bind(calc_callback, main_task_runner, quit_closure,
877 current_sequence_runner));
878 },
879 base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(),
880 thread_safe_ptr);
881 base::CreateSequencedTaskRunnerWithTraits({})->PostTask(FROM_HERE,
882 run_method);
883
884 // Block until the method callback is called on the background thread.
885 run_loop.Run();
886 }
887
TEST_P(InterfacePtrTest,ThreadSafeInterfacePointerWithTaskRunner)888 TEST_P(InterfacePtrTest, ThreadSafeInterfacePointerWithTaskRunner) {
889 const scoped_refptr<base::SequencedTaskRunner> other_thread_task_runner =
890 base::CreateSequencedTaskRunnerWithTraits({});
891
892 math::CalculatorPtr ptr;
893 auto request = mojo::MakeRequest(&ptr);
894
895 // Create a ThreadSafeInterfacePtr that we'll bind from a different thread.
896 scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr =
897 math::ThreadSafeCalculatorPtr::Create(ptr.PassInterface(),
898 other_thread_task_runner);
899 ASSERT_TRUE(thread_safe_ptr);
900
901 MathCalculatorImpl* math_calc_impl = nullptr;
902 {
903 base::RunLoop run_loop;
904 auto run_method = base::Bind(
905 [](const scoped_refptr<base::TaskRunner>& main_task_runner,
906 const base::Closure& quit_closure,
907 const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr,
908 math::CalculatorRequest request,
909 MathCalculatorImpl** math_calc_impl) {
910 math::CalculatorPtr ptr;
911 // In real life, the implementation would have a legitimate owner.
912 *math_calc_impl = new MathCalculatorImpl(std::move(request));
913 main_task_runner->PostTask(FROM_HERE, quit_closure);
914 },
915 base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(),
916 thread_safe_ptr, base::Passed(&request), &math_calc_impl);
917 other_thread_task_runner->PostTask(FROM_HERE, run_method);
918 run_loop.Run();
919 }
920
921 {
922 // The interface ptr is bound, we can call methods on it.
923 auto calc_callback =
924 base::Bind([](const base::Closure& quit_closure, double result) {
925 EXPECT_EQ(123, result);
926 quit_closure.Run();
927 });
928 base::RunLoop run_loop;
929 (*thread_safe_ptr)
930 ->Add(123, base::Bind(calc_callback, run_loop.QuitClosure()));
931 // Block until the method callback is called.
932 run_loop.Run();
933 }
934
935 other_thread_task_runner->DeleteSoon(FROM_HERE, math_calc_impl);
936
937 // Reset the pointer now so the InterfacePtr associated resources can be
938 // deleted before the background thread's message loop is invalidated.
939 thread_safe_ptr = nullptr;
940 }
941
942 INSTANTIATE_MOJO_BINDINGS_TEST_CASE_P(InterfacePtrTest);
943
944 } // namespace
945 } // namespace test
946 } // namespace mojo
947