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
21namespace mojo {
22namespace {
23
24class 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
37class 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
61template <typename... Args>
62void DoSetFlagAndRunClosure(bool* flag,
63                            const base::Closure& closure,
64                            Args... args) {
65  *flag = true;
66  closure.Run();
67}
68
69template <typename... Args>
70base::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
78using BindingTest = BindingTestBase;
79
80TEST_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.
97TEST_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.
132TEST_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.
153TEST_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
170class 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.
197TEST_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.
211TEST_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
246class 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
261TEST_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
268TEST_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.
291TEST_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
315using StrongBindingTest = BindingTestBase;
316
317// Tests that destroying a mojo::StrongBinding closes the bound message pipe
318// handle but does *not* destroy the implementation object.
319TEST_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
347class 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).
363TEST_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.
384TEST_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