• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
BindingTestBase()26   BindingTestBase() {}
~BindingTestBase()27   ~BindingTestBase() override {}
28 
loop()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:
ServiceImpl(bool * was_deleted=nullptr)39   explicit ServiceImpl(bool* was_deleted = nullptr)
40       : was_deleted_(was_deleted) {}
~ServiceImpl()41   ~ServiceImpl() override {
42     if (was_deleted_)
43       *was_deleted_ = true;
44   }
45 
46  private:
47   // sample::Service implementation
Frobinate(sample::FooPtr foo,BazOptions options,sample::PortPtr port,const FrobinateCallback & callback)48   void Frobinate(sample::FooPtr foo,
49                  BazOptions options,
50                  sample::PortPtr port,
51                  const FrobinateCallback& callback) override {
52     callback.Run(1);
53   }
GetPort(InterfaceRequest<sample::Port> port)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>
DoSetFlagAndRunClosure(bool * flag,const base::Closure & closure,Args...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>
SetFlagAndRunClosure(bool * flag,const base::Closure & callback=base::Closure ())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 
TEST_F(BindingTest,Close)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.
TEST_F(BindingTest,DestroyClosesMessagePipe)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.
TEST_F(BindingTest,ConnectionError)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.
TEST_F(BindingTest,CloseDoesntCallConnectionErrorHandler)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:
ServiceImplWithBinding(bool * was_deleted,const base::Closure & closure,InterfaceRequest<sample::Service> request)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:
~ServiceImplWithBinding()184   ~ServiceImplWithBinding() override{
185     closure_.Run();
186   }
187 
OnConnectionError()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.
TEST_F(BindingTest,SelfDeleteOnConnectionError)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.
TEST_F(BindingTest,Unbind)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:
IntegerAccessorImpl()248   IntegerAccessorImpl() {}
~IntegerAccessorImpl()249   ~IntegerAccessorImpl() override {}
250 
251  private:
252   // sample::IntegerAccessor implementation.
GetInteger(const GetIntegerCallback & callback)253   void GetInteger(const GetIntegerCallback& callback) override {
254     callback.Run(1, sample::Enum::VALUE);
255   }
SetInteger(int64_t data,sample::Enum type)256   void SetInteger(int64_t data, sample::Enum type) override {}
257 
258   DISALLOW_COPY_AND_ASSIGN(IntegerAccessorImpl);
259 };
260 
TEST_F(BindingTest,SetInterfacePtrVersion)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 
TEST_F(BindingTest,PauseResume)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.
TEST_F(BindingTest,ErrorHandleNotRunWhilePaused)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.
TEST_F(StrongBindingTest,DestroyClosesMessagePipe)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:
ServiceImplWithStrongBinding(bool * was_deleted,InterfaceRequest<sample::Service> request)349   ServiceImplWithStrongBinding(bool* was_deleted,
350                                InterfaceRequest<sample::Service> request)
351       : ServiceImpl(was_deleted), binding_(this, std::move(request)) {}
352 
binding()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).
TEST_F(StrongBindingTest,ConnectionErrorDestroysImpl)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.
TEST_F(StrongBindingTest,ExplicitDeleteImpl)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