• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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