Home | History | Annotate | Download | only in tests
      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 // Note: This file tests both binding.h (mojo::Binding) and strong_binding.h
      6 // (mojo::StrongBinding).
      7 
      8 #include "mojo/public/cpp/bindings/binding.h"
      9 
     10 #include <stdint.h>
     11 #include <utility>
     12 
     13 #include "base/macros.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/run_loop.h"
     16 #include "mojo/public/cpp/bindings/strong_binding.h"
     17 #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h"
     18 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace mojo {
     22 namespace {
     23 
     24 class BindingTestBase : public testing::Test {
     25  public:
     26   BindingTestBase() {}
     27   ~BindingTestBase() override {}
     28 
     29   base::MessageLoop& loop() { return loop_; }
     30 
     31  private:
     32   base::MessageLoop loop_;
     33 
     34   DISALLOW_COPY_AND_ASSIGN(BindingTestBase);
     35 };
     36 
     37 class ServiceImpl : public sample::Service {
     38  public:
     39   explicit ServiceImpl(bool* was_deleted = nullptr)
     40       : was_deleted_(was_deleted) {}
     41   ~ServiceImpl() override {
     42     if (was_deleted_)
     43       *was_deleted_ = true;
     44   }
     45 
     46  private:
     47   // sample::Service implementation
     48   void Frobinate(sample::FooPtr foo,
     49                  BazOptions options,
     50                  sample::PortPtr port,
     51                  const FrobinateCallback& callback) override {
     52     callback.Run(1);
     53   }
     54   void GetPort(InterfaceRequest<sample::Port> port) override {}
     55 
     56   bool* const was_deleted_;
     57 
     58   DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
     59 };
     60 
     61 template <typename... Args>
     62 void DoSetFlagAndRunClosure(bool* flag,
     63                             const base::Closure& closure,
     64                             Args... args) {
     65   *flag = true;
     66   closure.Run();
     67 }
     68 
     69 template <typename... Args>
     70 base::Callback<void(Args...)> SetFlagAndRunClosure(
     71     bool* flag,
     72     const base::Closure& callback = base::Closure()) {
     73   return base::Bind(&DoSetFlagAndRunClosure<Args...>, flag, callback);
     74 }
     75 
     76 // BindingTest -----------------------------------------------------------------
     77 
     78 using BindingTest = BindingTestBase;
     79 
     80 TEST_F(BindingTest, Close) {
     81   bool called = false;
     82   sample::ServicePtr ptr;
     83   auto request = GetProxy(&ptr);
     84   base::RunLoop run_loop;
     85   ptr.set_connection_error_handler(
     86       SetFlagAndRunClosure(&called, run_loop.QuitClosure()));
     87   ServiceImpl impl;
     88   Binding<sample::Service> binding(&impl, std::move(request));
     89 
     90   binding.Close();
     91   EXPECT_FALSE(called);
     92   run_loop.Run();
     93   EXPECT_TRUE(called);
     94 }
     95 
     96 // Tests that destroying a mojo::Binding closes the bound message pipe handle.
     97 TEST_F(BindingTest, DestroyClosesMessagePipe) {
     98   bool encountered_error = false;
     99   ServiceImpl impl;
    100   sample::ServicePtr ptr;
    101   auto request = GetProxy(&ptr);
    102   base::RunLoop run_loop;
    103   ptr.set_connection_error_handler(
    104       SetFlagAndRunClosure(&encountered_error, run_loop.QuitClosure()));
    105   bool called = false;
    106   base::RunLoop run_loop2;
    107   {
    108     Binding<sample::Service> binding(&impl, std::move(request));
    109     ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    110                    SetFlagAndRunClosure<int32_t>(&called,
    111                                                  run_loop2.QuitClosure()));
    112     run_loop2.Run();
    113     EXPECT_TRUE(called);
    114     EXPECT_FALSE(encountered_error);
    115   }
    116   // Now that the Binding is out of scope we should detect an error on the other
    117   // end of the pipe.
    118   run_loop.Run();
    119   EXPECT_TRUE(encountered_error);
    120 
    121   // And calls should fail.
    122   called = false;
    123   ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    124                  SetFlagAndRunClosure<int32_t>(&called,
    125                                                run_loop2.QuitClosure()));
    126   base::RunLoop().RunUntilIdle();
    127   EXPECT_FALSE(called);
    128 }
    129 
    130 // Tests that the binding's connection error handler gets called when the other
    131 // end is closed.
    132 TEST_F(BindingTest, ConnectionError) {
    133   bool called = false;
    134   {
    135     ServiceImpl impl;
    136     sample::ServicePtr ptr;
    137     Binding<sample::Service> binding(&impl, GetProxy(&ptr));
    138     base::RunLoop run_loop;
    139     binding.set_connection_error_handler(
    140         SetFlagAndRunClosure(&called, run_loop.QuitClosure()));
    141     ptr.reset();
    142     EXPECT_FALSE(called);
    143     run_loop.Run();
    144     EXPECT_TRUE(called);
    145     // We want to make sure that it isn't called again during destruction.
    146     called = false;
    147   }
    148   EXPECT_FALSE(called);
    149 }
    150 
    151 // Tests that calling Close doesn't result in the connection error handler being
    152 // called.
    153 TEST_F(BindingTest, CloseDoesntCallConnectionErrorHandler) {
    154   ServiceImpl impl;
    155   sample::ServicePtr ptr;
    156   Binding<sample::Service> binding(&impl, GetProxy(&ptr));
    157   bool called = false;
    158   binding.set_connection_error_handler(SetFlagAndRunClosure(&called));
    159   binding.Close();
    160   base::RunLoop().RunUntilIdle();
    161   EXPECT_FALSE(called);
    162 
    163   // We can also close the other end, and the error handler still won't be
    164   // called.
    165   ptr.reset();
    166   base::RunLoop().RunUntilIdle();
    167   EXPECT_FALSE(called);
    168 }
    169 
    170 class ServiceImplWithBinding : public ServiceImpl {
    171  public:
    172   ServiceImplWithBinding(bool* was_deleted,
    173                          const base::Closure& closure,
    174                          InterfaceRequest<sample::Service> request)
    175       : ServiceImpl(was_deleted),
    176         binding_(this, std::move(request)),
    177         closure_(closure) {
    178     binding_.set_connection_error_handler(
    179         base::Bind(&ServiceImplWithBinding::OnConnectionError,
    180                    base::Unretained(this)));
    181   }
    182 
    183  private:
    184   ~ServiceImplWithBinding() override{
    185     closure_.Run();
    186   }
    187 
    188   void OnConnectionError() { delete this; }
    189 
    190   Binding<sample::Service> binding_;
    191   base::Closure closure_;
    192 
    193   DISALLOW_COPY_AND_ASSIGN(ServiceImplWithBinding);
    194 };
    195 
    196 // Tests that the binding may be deleted in the connection error handler.
    197 TEST_F(BindingTest, SelfDeleteOnConnectionError) {
    198   bool was_deleted = false;
    199   sample::ServicePtr ptr;
    200   // This should delete itself on connection error.
    201   base::RunLoop run_loop;
    202   new ServiceImplWithBinding(&was_deleted, run_loop.QuitClosure(),
    203                              GetProxy(&ptr));
    204   ptr.reset();
    205   EXPECT_FALSE(was_deleted);
    206   run_loop.Run();
    207   EXPECT_TRUE(was_deleted);
    208 }
    209 
    210 // Tests that explicitly calling Unbind followed by rebinding works.
    211 TEST_F(BindingTest, Unbind) {
    212   ServiceImpl impl;
    213   sample::ServicePtr ptr;
    214   Binding<sample::Service> binding(&impl, GetProxy(&ptr));
    215 
    216   bool called = false;
    217   base::RunLoop run_loop;
    218   ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    219                  SetFlagAndRunClosure<int32_t>(&called,
    220                                                run_loop.QuitClosure()));
    221   run_loop.Run();
    222   EXPECT_TRUE(called);
    223 
    224   called = false;
    225   auto request = binding.Unbind();
    226   EXPECT_FALSE(binding.is_bound());
    227   // All calls should fail when not bound...
    228   ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    229                  SetFlagAndRunClosure<int32_t>(&called,
    230                                                run_loop.QuitClosure()));
    231   base::RunLoop().RunUntilIdle();
    232   EXPECT_FALSE(called);
    233 
    234   called = false;
    235   binding.Bind(std::move(request));
    236   EXPECT_TRUE(binding.is_bound());
    237   // ...and should succeed again when the rebound.
    238   base::RunLoop run_loop2;
    239   ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    240                  SetFlagAndRunClosure<int32_t>(&called,
    241                                                run_loop2.QuitClosure()));
    242   run_loop2.Run();
    243   EXPECT_TRUE(called);
    244 }
    245 
    246 class IntegerAccessorImpl : public sample::IntegerAccessor {
    247  public:
    248   IntegerAccessorImpl() {}
    249   ~IntegerAccessorImpl() override {}
    250 
    251  private:
    252   // sample::IntegerAccessor implementation.
    253   void GetInteger(const GetIntegerCallback& callback) override {
    254     callback.Run(1, sample::Enum::VALUE);
    255   }
    256   void SetInteger(int64_t data, sample::Enum type) override {}
    257 
    258   DISALLOW_COPY_AND_ASSIGN(IntegerAccessorImpl);
    259 };
    260 
    261 TEST_F(BindingTest, SetInterfacePtrVersion) {
    262   IntegerAccessorImpl impl;
    263   sample::IntegerAccessorPtr ptr;
    264   Binding<sample::IntegerAccessor> binding(&impl, &ptr);
    265   EXPECT_EQ(3u, ptr.version());
    266 }
    267 
    268 TEST_F(BindingTest, PauseResume) {
    269   bool called = false;
    270   base::RunLoop run_loop;
    271   sample::ServicePtr ptr;
    272   auto request = GetProxy(&ptr);
    273   ServiceImpl impl;
    274   Binding<sample::Service> binding(&impl, std::move(request));
    275   binding.PauseIncomingMethodCallProcessing();
    276   ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    277                  SetFlagAndRunClosure<int32_t>(&called,
    278                                                run_loop.QuitClosure()));
    279   EXPECT_FALSE(called);
    280   base::RunLoop().RunUntilIdle();
    281   // Frobinate() should not be called as the binding is paused.
    282   EXPECT_FALSE(called);
    283 
    284   // Resume the binding, which should trigger processing.
    285   binding.ResumeIncomingMethodCallProcessing();
    286   run_loop.Run();
    287   EXPECT_TRUE(called);
    288 }
    289 
    290 // Verifies the connection error handler is not run while a binding is paused.
    291 TEST_F(BindingTest, ErrorHandleNotRunWhilePaused) {
    292   bool called = false;
    293   base::RunLoop run_loop;
    294   sample::ServicePtr ptr;
    295   auto request = GetProxy(&ptr);
    296   ServiceImpl impl;
    297   Binding<sample::Service> binding(&impl, std::move(request));
    298   binding.set_connection_error_handler(
    299       SetFlagAndRunClosure(&called, run_loop.QuitClosure()));
    300   binding.PauseIncomingMethodCallProcessing();
    301 
    302   ptr.reset();
    303   base::RunLoop().RunUntilIdle();
    304   // The connection error handle should not be called as the binding is paused.
    305   EXPECT_FALSE(called);
    306 
    307   // Resume the binding, which should trigger the error handler.
    308   binding.ResumeIncomingMethodCallProcessing();
    309   run_loop.Run();
    310   EXPECT_TRUE(called);
    311 }
    312 
    313 // StrongBindingTest -----------------------------------------------------------
    314 
    315 using StrongBindingTest = BindingTestBase;
    316 
    317 // Tests that destroying a mojo::StrongBinding closes the bound message pipe
    318 // handle but does *not* destroy the implementation object.
    319 TEST_F(StrongBindingTest, DestroyClosesMessagePipe) {
    320   base::RunLoop run_loop;
    321   bool encountered_error = false;
    322   bool was_deleted = false;
    323   ServiceImpl impl(&was_deleted);
    324   sample::ServicePtr ptr;
    325   auto request = GetProxy(&ptr);
    326   ptr.set_connection_error_handler(
    327       SetFlagAndRunClosure(&encountered_error, run_loop.QuitClosure()));
    328   bool called = false;
    329   base::RunLoop run_loop2;
    330   {
    331     StrongBinding<sample::Service> binding(&impl, std::move(request));
    332     ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
    333                    SetFlagAndRunClosure<int32_t>(&called,
    334                                                  run_loop2.QuitClosure()));
    335     run_loop2.Run();
    336     EXPECT_TRUE(called);
    337     EXPECT_FALSE(encountered_error);
    338   }
    339   // Now that the StrongBinding is out of scope we should detect an error on the
    340   // other end of the pipe.
    341   run_loop.Run();
    342   EXPECT_TRUE(encountered_error);
    343   // But destroying the StrongBinding doesn't destroy the object.
    344   ASSERT_FALSE(was_deleted);
    345 }
    346 
    347 class ServiceImplWithStrongBinding : public ServiceImpl {
    348  public:
    349   ServiceImplWithStrongBinding(bool* was_deleted,
    350                                InterfaceRequest<sample::Service> request)
    351       : ServiceImpl(was_deleted), binding_(this, std::move(request)) {}
    352 
    353   StrongBinding<sample::Service>& binding() { return binding_; }
    354 
    355  private:
    356   StrongBinding<sample::Service> binding_;
    357 
    358   DISALLOW_COPY_AND_ASSIGN(ServiceImplWithStrongBinding);
    359 };
    360 
    361 // Tests the typical case, where the implementation object owns the
    362 // StrongBinding (and should be destroyed on connection error).
    363 TEST_F(StrongBindingTest, ConnectionErrorDestroysImpl) {
    364   sample::ServicePtr ptr;
    365   bool was_deleted = false;
    366   // Will delete itself.
    367   base::RunLoop run_loop;
    368   new ServiceImplWithBinding(&was_deleted, run_loop.QuitClosure(),
    369                              GetProxy(&ptr));
    370 
    371   base::RunLoop().RunUntilIdle();
    372   EXPECT_FALSE(was_deleted);
    373 
    374   ptr.reset();
    375   EXPECT_FALSE(was_deleted);
    376   run_loop.Run();
    377   EXPECT_TRUE(was_deleted);
    378 }
    379 
    380 // Tests that even when the implementation object owns the StrongBinding, that
    381 // the implementation can still be deleted (which should result in the message
    382 // pipe being closed). Also checks that the connection error handler doesn't get
    383 // called.
    384 TEST_F(StrongBindingTest, ExplicitDeleteImpl) {
    385   bool ptr_error_handler_called = false;
    386   sample::ServicePtr ptr;
    387   auto request = GetProxy(&ptr);
    388   base::RunLoop run_loop;
    389   ptr.set_connection_error_handler(
    390       SetFlagAndRunClosure(&ptr_error_handler_called, run_loop.QuitClosure()));
    391   bool was_deleted = false;
    392   ServiceImplWithStrongBinding* impl =
    393       new ServiceImplWithStrongBinding(&was_deleted, std::move(request));
    394   bool binding_error_handler_called = false;
    395   impl->binding().set_connection_error_handler(
    396       SetFlagAndRunClosure(&binding_error_handler_called));
    397 
    398   base::RunLoop().RunUntilIdle();
    399   EXPECT_FALSE(ptr_error_handler_called);
    400   EXPECT_FALSE(was_deleted);
    401 
    402   delete impl;
    403   EXPECT_FALSE(ptr_error_handler_called);
    404   EXPECT_TRUE(was_deleted);
    405   was_deleted = false;  // It shouldn't be double-deleted!
    406   run_loop.Run();
    407   EXPECT_TRUE(ptr_error_handler_called);
    408   EXPECT_FALSE(was_deleted);
    409 
    410   EXPECT_FALSE(binding_error_handler_called);
    411 }
    412 
    413 }  // namespace
    414 }  // mojo
    415