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