| OLD | NEW |
| (Empty) |
| 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 "gtest/gtest.h" | |
| 9 #include "mojo/public/cpp/bindings/binding.h" | |
| 10 #include "mojo/public/cpp/bindings/strong_binding.h" | |
| 11 #include "mojo/public/cpp/system/macros.h" | |
| 12 #include "mojo/public/cpp/utility/run_loop.h" | |
| 13 #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h" | |
| 14 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" | |
| 15 | |
| 16 namespace mojo { | |
| 17 namespace { | |
| 18 | |
| 19 class BindingTestBase : public testing::Test { | |
| 20 public: | |
| 21 BindingTestBase() {} | |
| 22 ~BindingTestBase() override {} | |
| 23 | |
| 24 RunLoop& loop() { return loop_; } | |
| 25 | |
| 26 private: | |
| 27 RunLoop loop_; | |
| 28 | |
| 29 MOJO_DISALLOW_COPY_AND_ASSIGN(BindingTestBase); | |
| 30 }; | |
| 31 | |
| 32 class ServiceImpl : public sample::Service { | |
| 33 public: | |
| 34 explicit ServiceImpl(bool* was_deleted = nullptr) | |
| 35 : was_deleted_(was_deleted) {} | |
| 36 ~ServiceImpl() override { | |
| 37 if (was_deleted_) | |
| 38 *was_deleted_ = true; | |
| 39 } | |
| 40 | |
| 41 private: | |
| 42 // sample::Service implementation | |
| 43 void Frobinate(sample::FooPtr foo, | |
| 44 BazOptions options, | |
| 45 mojo::InterfaceHandle<sample::Port> port, | |
| 46 const FrobinateCallback& callback) override { | |
| 47 callback.Run(1); | |
| 48 } | |
| 49 void GetPort(InterfaceRequest<sample::Port> port) override {} | |
| 50 | |
| 51 bool* const was_deleted_; | |
| 52 | |
| 53 MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceImpl); | |
| 54 }; | |
| 55 | |
| 56 // BindingTest ----------------------------------------------------------------- | |
| 57 | |
| 58 using BindingTest = BindingTestBase; | |
| 59 | |
| 60 TEST_F(BindingTest, Close) { | |
| 61 bool called = false; | |
| 62 sample::ServicePtr ptr; | |
| 63 auto request = GetProxy(&ptr); | |
| 64 ptr.set_connection_error_handler([&called]() { called = true; }); | |
| 65 ServiceImpl impl; | |
| 66 Binding<sample::Service> binding(&impl, request.Pass()); | |
| 67 | |
| 68 binding.Close(); | |
| 69 EXPECT_FALSE(called); | |
| 70 loop().RunUntilIdle(); | |
| 71 EXPECT_TRUE(called); | |
| 72 } | |
| 73 | |
| 74 // Tests that destroying a mojo::Binding closes the bound message pipe handle. | |
| 75 TEST_F(BindingTest, DestroyClosesMessagePipe) { | |
| 76 bool encountered_error = false; | |
| 77 ServiceImpl impl; | |
| 78 sample::ServicePtr ptr; | |
| 79 auto request = GetProxy(&ptr); | |
| 80 ptr.set_connection_error_handler( | |
| 81 [&encountered_error]() { encountered_error = true; }); | |
| 82 bool called = false; | |
| 83 auto called_cb = [&called](int32_t result) { called = true; }; | |
| 84 { | |
| 85 Binding<sample::Service> binding(&impl, request.Pass()); | |
| 86 ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, | |
| 87 called_cb); | |
| 88 loop().RunUntilIdle(); | |
| 89 EXPECT_TRUE(called); | |
| 90 EXPECT_FALSE(encountered_error); | |
| 91 } | |
| 92 // Now that the Binding is out of scope we should detect an error on the other | |
| 93 // end of the pipe. | |
| 94 loop().RunUntilIdle(); | |
| 95 EXPECT_TRUE(encountered_error); | |
| 96 | |
| 97 // And calls should fail. | |
| 98 called = false; | |
| 99 ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, | |
| 100 called_cb); | |
| 101 loop().RunUntilIdle(); | |
| 102 EXPECT_FALSE(called); | |
| 103 } | |
| 104 | |
| 105 // Tests that the binding's connection error handler gets called when the other | |
| 106 // end is closed. | |
| 107 TEST_F(BindingTest, ConnectionError) { | |
| 108 bool called = false; | |
| 109 { | |
| 110 ServiceImpl impl; | |
| 111 sample::ServicePtr ptr; | |
| 112 Binding<sample::Service> binding(&impl, GetProxy(&ptr)); | |
| 113 binding.set_connection_error_handler([&called]() { called = true; }); | |
| 114 ptr.reset(); | |
| 115 EXPECT_FALSE(called); | |
| 116 loop().RunUntilIdle(); | |
| 117 EXPECT_TRUE(called); | |
| 118 // We want to make sure that it isn't called again during destruction. | |
| 119 called = false; | |
| 120 } | |
| 121 EXPECT_FALSE(called); | |
| 122 } | |
| 123 | |
| 124 // Tests that calling Close doesn't result in the connection error handler being | |
| 125 // called. | |
| 126 TEST_F(BindingTest, CloseDoesntCallConnectionErrorHandler) { | |
| 127 ServiceImpl impl; | |
| 128 sample::ServicePtr ptr; | |
| 129 Binding<sample::Service> binding(&impl, GetProxy(&ptr)); | |
| 130 bool called = false; | |
| 131 binding.set_connection_error_handler([&called]() { called = true; }); | |
| 132 binding.Close(); | |
| 133 loop().RunUntilIdle(); | |
| 134 EXPECT_FALSE(called); | |
| 135 | |
| 136 // We can also close the other end, and the error handler still won't be | |
| 137 // called. | |
| 138 ptr.reset(); | |
| 139 loop().RunUntilIdle(); | |
| 140 EXPECT_FALSE(called); | |
| 141 } | |
| 142 | |
| 143 class ServiceImplWithBinding : public ServiceImpl { | |
| 144 public: | |
| 145 ServiceImplWithBinding(bool* was_deleted, | |
| 146 InterfaceRequest<sample::Service> request) | |
| 147 : ServiceImpl(was_deleted), binding_(this, request.Pass()) { | |
| 148 binding_.set_connection_error_handler([this]() { delete this; }); | |
| 149 } | |
| 150 | |
| 151 private: | |
| 152 Binding<sample::Service> binding_; | |
| 153 | |
| 154 MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceImplWithBinding); | |
| 155 }; | |
| 156 | |
| 157 // Tests that the binding may be deleted in the connection error handler. | |
| 158 TEST_F(BindingTest, SelfDeleteOnConnectionError) { | |
| 159 bool was_deleted = false; | |
| 160 sample::ServicePtr ptr; | |
| 161 // This should delete itself on connection error. | |
| 162 new ServiceImplWithBinding(&was_deleted, GetProxy(&ptr)); | |
| 163 ptr.reset(); | |
| 164 EXPECT_FALSE(was_deleted); | |
| 165 loop().RunUntilIdle(); | |
| 166 EXPECT_TRUE(was_deleted); | |
| 167 } | |
| 168 | |
| 169 // Tests that explicitly calling Unbind followed by rebinding works. | |
| 170 TEST_F(BindingTest, Unbind) { | |
| 171 ServiceImpl impl; | |
| 172 sample::ServicePtr ptr; | |
| 173 Binding<sample::Service> binding(&impl, GetProxy(&ptr)); | |
| 174 | |
| 175 bool called = false; | |
| 176 auto called_cb = [&called](int32_t result) { called = true; }; | |
| 177 ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, | |
| 178 called_cb); | |
| 179 loop().RunUntilIdle(); | |
| 180 EXPECT_TRUE(called); | |
| 181 | |
| 182 called = false; | |
| 183 auto request = binding.Unbind(); | |
| 184 EXPECT_FALSE(binding.is_bound()); | |
| 185 // All calls should fail when not bound... | |
| 186 ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, | |
| 187 called_cb); | |
| 188 loop().RunUntilIdle(); | |
| 189 EXPECT_FALSE(called); | |
| 190 | |
| 191 called = false; | |
| 192 binding.Bind(request.Pass()); | |
| 193 EXPECT_TRUE(binding.is_bound()); | |
| 194 // ...and should succeed again when the rebound. | |
| 195 ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, | |
| 196 called_cb); | |
| 197 loop().RunUntilIdle(); | |
| 198 EXPECT_TRUE(called); | |
| 199 } | |
| 200 | |
| 201 class IntegerAccessorImpl : public sample::IntegerAccessor { | |
| 202 public: | |
| 203 IntegerAccessorImpl() {} | |
| 204 ~IntegerAccessorImpl() override {} | |
| 205 | |
| 206 private: | |
| 207 // sample::IntegerAccessor implementation. | |
| 208 void GetInteger(const GetIntegerCallback& callback) override { | |
| 209 callback.Run(1, sample::Enum::VALUE); | |
| 210 } | |
| 211 void SetInteger(int64_t data, sample::Enum type) override {} | |
| 212 | |
| 213 MOJO_DISALLOW_COPY_AND_ASSIGN(IntegerAccessorImpl); | |
| 214 }; | |
| 215 | |
| 216 TEST_F(BindingTest, SetInterfaceHandleVersion) { | |
| 217 IntegerAccessorImpl impl; | |
| 218 mojo::InterfaceHandle<sample::IntegerAccessor> handle; | |
| 219 Binding<sample::IntegerAccessor> binding(&impl, &handle); | |
| 220 EXPECT_EQ(3u, handle.version()); | |
| 221 } | |
| 222 | |
| 223 // StrongBindingTest ----------------------------------------------------------- | |
| 224 | |
| 225 using StrongBindingTest = BindingTestBase; | |
| 226 | |
| 227 // Tests that destroying a mojo::StrongBinding closes the bound message pipe | |
| 228 // handle but does *not* destroy the implementation object. | |
| 229 TEST_F(StrongBindingTest, DestroyClosesMessagePipe) { | |
| 230 bool encountered_error = false; | |
| 231 bool was_deleted = false; | |
| 232 ServiceImpl impl(&was_deleted); | |
| 233 sample::ServicePtr ptr; | |
| 234 auto request = GetProxy(&ptr); | |
| 235 ptr.set_connection_error_handler( | |
| 236 [&encountered_error]() { encountered_error = true; }); | |
| 237 bool called = false; | |
| 238 auto called_cb = [&called](int32_t result) { called = true; }; | |
| 239 { | |
| 240 StrongBinding<sample::Service> binding(&impl, request.Pass()); | |
| 241 ptr->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, | |
| 242 called_cb); | |
| 243 loop().RunUntilIdle(); | |
| 244 EXPECT_TRUE(called); | |
| 245 EXPECT_FALSE(encountered_error); | |
| 246 } | |
| 247 // Now that the StrongBinding is out of scope we should detect an error on the | |
| 248 // other end of the pipe. | |
| 249 loop().RunUntilIdle(); | |
| 250 EXPECT_TRUE(encountered_error); | |
| 251 // But destroying the StrongBinding doesn't destroy the object. | |
| 252 ASSERT_FALSE(was_deleted); | |
| 253 } | |
| 254 | |
| 255 class ServiceImplWithStrongBinding : public ServiceImpl { | |
| 256 public: | |
| 257 ServiceImplWithStrongBinding(bool* was_deleted, | |
| 258 InterfaceRequest<sample::Service> request) | |
| 259 : ServiceImpl(was_deleted), binding_(this, request.Pass()) {} | |
| 260 | |
| 261 StrongBinding<sample::Service>& binding() { return binding_; } | |
| 262 | |
| 263 private: | |
| 264 StrongBinding<sample::Service> binding_; | |
| 265 | |
| 266 MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceImplWithStrongBinding); | |
| 267 }; | |
| 268 | |
| 269 // Tests the typical case, where the implementation object owns the | |
| 270 // StrongBinding (and should be destroyed on connection error). | |
| 271 TEST_F(StrongBindingTest, ConnectionErrorDestroysImpl) { | |
| 272 sample::ServicePtr ptr; | |
| 273 bool was_deleted = false; | |
| 274 // Will delete itself. | |
| 275 new ServiceImplWithBinding(&was_deleted, GetProxy(&ptr)); | |
| 276 | |
| 277 loop().RunUntilIdle(); | |
| 278 EXPECT_FALSE(was_deleted); | |
| 279 | |
| 280 ptr.reset(); | |
| 281 EXPECT_FALSE(was_deleted); | |
| 282 loop().RunUntilIdle(); | |
| 283 EXPECT_TRUE(was_deleted); | |
| 284 } | |
| 285 | |
| 286 // Tests that even when the implementation object owns the StrongBinding, that | |
| 287 // the implementation can still be deleted (which should result in the message | |
| 288 // pipe being closed). Also checks that the connection error handler doesn't get | |
| 289 // called. | |
| 290 TEST_F(StrongBindingTest, ExplicitDeleteImpl) { | |
| 291 bool ptr_error_handler_called = false; | |
| 292 sample::ServicePtr ptr; | |
| 293 auto request = GetProxy(&ptr); | |
| 294 ptr.set_connection_error_handler( | |
| 295 [&ptr_error_handler_called]() { ptr_error_handler_called = true; }); | |
| 296 bool was_deleted = false; | |
| 297 ServiceImplWithStrongBinding* impl = | |
| 298 new ServiceImplWithStrongBinding(&was_deleted, request.Pass()); | |
| 299 bool binding_error_handler_called = false; | |
| 300 impl->binding().set_connection_error_handler( | |
| 301 [&binding_error_handler_called]() { | |
| 302 binding_error_handler_called = true; | |
| 303 }); | |
| 304 | |
| 305 loop().RunUntilIdle(); | |
| 306 EXPECT_FALSE(ptr_error_handler_called); | |
| 307 EXPECT_FALSE(was_deleted); | |
| 308 | |
| 309 delete impl; | |
| 310 EXPECT_FALSE(ptr_error_handler_called); | |
| 311 EXPECT_TRUE(was_deleted); | |
| 312 was_deleted = false; // It shouldn't be double-deleted! | |
| 313 loop().RunUntilIdle(); | |
| 314 EXPECT_TRUE(ptr_error_handler_called); | |
| 315 EXPECT_FALSE(was_deleted); | |
| 316 | |
| 317 EXPECT_FALSE(binding_error_handler_called); | |
| 318 } | |
| 319 | |
| 320 // Tests that StrongBinding::Close() compiles. | |
| 321 TEST_F(BindingTest, StrongBindingCloseCompile) { | |
| 322 ServiceImpl impl; | |
| 323 sample::ServicePtr ptr; | |
| 324 StrongBinding<sample::Service> binding(&impl, GetProxy(&ptr)); | |
| 325 binding.Close(); | |
| 326 } | |
| 327 | |
| 328 // Tests that StrongBinding::Unbind() compiles. | |
| 329 TEST_F(BindingTest, StrongBindingUnbindCompile) { | |
| 330 ServiceImpl impl; | |
| 331 sample::ServicePtr ptr; | |
| 332 StrongBinding<sample::Service> binding(&impl, GetProxy(&ptr)); | |
| 333 binding.Unbind(); | |
| 334 } | |
| 335 | |
| 336 } // namespace | |
| 337 } // namespace mojo | |
| OLD | NEW |