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