OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "mojo/public/cpp/bindings/binding.h" |
5 #include "mojo/public/cpp/bindings/error_handler.h" | 6 #include "mojo/public/cpp/bindings/error_handler.h" |
| 7 #include "mojo/public/cpp/bindings/strong_binding.h" |
6 #include "mojo/public/cpp/environment/environment.h" | 8 #include "mojo/public/cpp/environment/environment.h" |
7 #include "mojo/public/cpp/utility/run_loop.h" | 9 #include "mojo/public/cpp/utility/run_loop.h" |
8 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" | 10 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" |
9 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" | 11 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" |
10 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
11 | 13 |
12 namespace mojo { | 14 namespace mojo { |
13 namespace test { | 15 namespace test { |
14 namespace { | 16 namespace { |
15 | 17 |
16 class ErrorObserver : public ErrorHandler { | 18 class ErrorObserver : public ErrorHandler { |
17 public: | 19 public: |
18 ErrorObserver() : encountered_error_(false) {} | 20 ErrorObserver() : encountered_error_(false) {} |
19 | 21 |
20 bool encountered_error() const { return encountered_error_; } | 22 bool encountered_error() const { return encountered_error_; } |
21 | 23 |
22 void OnConnectionError() override { encountered_error_ = true; } | 24 void OnConnectionError() override { encountered_error_ = true; } |
23 | 25 |
24 private: | 26 private: |
25 bool encountered_error_; | 27 bool encountered_error_; |
26 }; | 28 }; |
27 | 29 |
28 class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { | 30 class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { |
29 public: | 31 public: |
30 ~MathCalculatorImpl() override {} | 32 ~MathCalculatorImpl() override {} |
31 | 33 |
32 MathCalculatorImpl() : total_(0.0), got_connection_(false) {} | 34 MathCalculatorImpl() : total_(0.0) {} |
33 | |
34 void OnConnectionEstablished() override { got_connection_ = true; } | |
35 | 35 |
36 void Clear() override { client()->Output(total_); } | 36 void Clear() override { client()->Output(total_); } |
37 | 37 |
38 void Add(double value) override { | 38 void Add(double value) override { |
39 total_ += value; | 39 total_ += value; |
40 client()->Output(total_); | 40 client()->Output(total_); |
41 } | 41 } |
42 | 42 |
43 void Multiply(double value) override { | 43 void Multiply(double value) override { |
44 total_ *= value; | 44 total_ *= value; |
45 client()->Output(total_); | 45 client()->Output(total_); |
46 } | 46 } |
47 | 47 |
48 bool got_connection() const { return got_connection_; } | |
49 | |
50 private: | 48 private: |
51 double total_; | 49 double total_; |
52 bool got_connection_; | |
53 }; | 50 }; |
54 | 51 |
55 class MathCalculatorUIImpl : public math::CalculatorUI { | 52 class MathCalculatorUIImpl : public math::CalculatorUI { |
56 public: | 53 public: |
57 explicit MathCalculatorUIImpl(math::CalculatorPtr calculator) | 54 explicit MathCalculatorUIImpl(math::CalculatorPtr calculator) |
58 : calculator_(calculator.Pass()), output_(0.0) { | 55 : calculator_(calculator.Pass()), output_(0.0) { |
59 calculator_.set_client(this); | 56 calculator_.set_client(this); |
60 } | 57 } |
61 | 58 |
62 bool WaitForIncomingMethodCall() { | 59 bool WaitForIncomingMethodCall() { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 static int num_instances_; | 113 static int num_instances_; |
117 }; | 114 }; |
118 | 115 |
119 // static | 116 // static |
120 int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0; | 117 int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0; |
121 | 118 |
122 class ReentrantServiceImpl : public InterfaceImpl<sample::Service> { | 119 class ReentrantServiceImpl : public InterfaceImpl<sample::Service> { |
123 public: | 120 public: |
124 ~ReentrantServiceImpl() override {} | 121 ~ReentrantServiceImpl() override {} |
125 | 122 |
126 ReentrantServiceImpl() | 123 ReentrantServiceImpl() : call_depth_(0), max_call_depth_(0) {} |
127 : got_connection_(false), call_depth_(0), max_call_depth_(0) {} | |
128 | |
129 void OnConnectionEstablished() override { got_connection_ = true; } | |
130 | |
131 bool got_connection() const { return got_connection_; } | |
132 | 124 |
133 int max_call_depth() { return max_call_depth_; } | 125 int max_call_depth() { return max_call_depth_; } |
134 | 126 |
135 void Frobinate(sample::FooPtr foo, | 127 void Frobinate(sample::FooPtr foo, |
136 sample::Service::BazOptions baz, | 128 sample::Service::BazOptions baz, |
137 sample::PortPtr port) override { | 129 sample::PortPtr port) override { |
138 max_call_depth_ = std::max(++call_depth_, max_call_depth_); | 130 max_call_depth_ = std::max(++call_depth_, max_call_depth_); |
139 if (call_depth_ == 1) { | 131 if (call_depth_ == 1) { |
140 EXPECT_TRUE(WaitForIncomingMethodCall()); | 132 EXPECT_TRUE(WaitForIncomingMethodCall()); |
141 } | 133 } |
142 call_depth_--; | 134 call_depth_--; |
143 } | 135 } |
144 | 136 |
145 void GetPort(mojo::InterfaceRequest<sample::Port> port) override {} | 137 void GetPort(mojo::InterfaceRequest<sample::Port> port) override {} |
146 | 138 |
147 private: | 139 private: |
148 bool got_connection_; | |
149 int call_depth_; | 140 int call_depth_; |
150 int max_call_depth_; | 141 int max_call_depth_; |
151 }; | 142 }; |
152 | 143 |
153 class InterfacePtrTest : public testing::Test { | 144 class InterfacePtrTest : public testing::Test { |
154 public: | 145 public: |
155 ~InterfacePtrTest() override { loop_.RunUntilIdle(); } | 146 ~InterfacePtrTest() override { loop_.RunUntilIdle(); } |
156 | 147 |
157 void PumpMessages() { loop_.RunUntilIdle(); } | 148 void PumpMessages() { loop_.RunUntilIdle(); } |
158 | 149 |
159 private: | 150 private: |
160 Environment env_; | 151 Environment env_; |
161 RunLoop loop_; | 152 RunLoop loop_; |
162 }; | 153 }; |
163 | 154 |
164 TEST_F(InterfacePtrTest, EndToEnd) { | 155 TEST_F(InterfacePtrTest, EndToEnd) { |
165 math::CalculatorPtr calc; | 156 math::CalculatorPtr calc; |
166 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); | 157 BindToProxy(new MathCalculatorImpl(), &calc); |
167 EXPECT_TRUE(impl->got_connection()); | |
168 | 158 |
169 // Suppose this is instantiated in a process that has pipe1_. | 159 // Suppose this is instantiated in a process that has pipe1_. |
170 MathCalculatorUIImpl calculator_ui(calc.Pass()); | 160 MathCalculatorUIImpl calculator_ui(calc.Pass()); |
171 | 161 |
172 calculator_ui.Add(2.0); | 162 calculator_ui.Add(2.0); |
173 calculator_ui.Multiply(5.0); | 163 calculator_ui.Multiply(5.0); |
174 | 164 |
175 PumpMessages(); | 165 PumpMessages(); |
176 | 166 |
177 EXPECT_EQ(10.0, calculator_ui.GetOutput()); | 167 EXPECT_EQ(10.0, calculator_ui.GetOutput()); |
178 } | 168 } |
179 | 169 |
180 TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { | 170 TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { |
181 math::CalculatorPtr calc; | 171 math::CalculatorPtr calc; |
182 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); | 172 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); |
183 EXPECT_TRUE(impl->got_connection()); | |
184 | 173 |
185 // Suppose this is instantiated in a process that has pipe1_. | 174 // Suppose this is instantiated in a process that has pipe1_. |
186 MathCalculatorUIImpl calculator_ui(calc.Pass()); | 175 MathCalculatorUIImpl calculator_ui(calc.Pass()); |
187 | 176 |
188 EXPECT_EQ(0.0, calculator_ui.GetOutput()); | 177 EXPECT_EQ(0.0, calculator_ui.GetOutput()); |
189 | 178 |
190 calculator_ui.Add(2.0); | 179 calculator_ui.Add(2.0); |
191 EXPECT_EQ(0.0, calculator_ui.GetOutput()); | 180 EXPECT_EQ(0.0, calculator_ui.GetOutput()); |
192 impl->WaitForIncomingMethodCall(); | 181 impl->WaitForIncomingMethodCall(); |
193 calculator_ui.WaitForIncomingMethodCall(); | 182 calculator_ui.WaitForIncomingMethodCall(); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 | 234 |
246 calculator_ui.Add(2.0); | 235 calculator_ui.Add(2.0); |
247 PumpMessages(); | 236 PumpMessages(); |
248 EXPECT_EQ(2.0, calculator_ui.GetOutput()); | 237 EXPECT_EQ(2.0, calculator_ui.GetOutput()); |
249 EXPECT_FALSE(calculator_ui.encountered_error()); | 238 EXPECT_FALSE(calculator_ui.encountered_error()); |
250 | 239 |
251 calculator_ui.Multiply(5.0); | 240 calculator_ui.Multiply(5.0); |
252 EXPECT_FALSE(calculator_ui.encountered_error()); | 241 EXPECT_FALSE(calculator_ui.encountered_error()); |
253 | 242 |
254 // Close the server. | 243 // Close the server. |
255 server->internal_state()->router()->CloseMessagePipe(); | 244 server->internal_router()->CloseMessagePipe(); |
256 | 245 |
257 // The state change isn't picked up locally yet. | 246 // The state change isn't picked up locally yet. |
258 EXPECT_FALSE(calculator_ui.encountered_error()); | 247 EXPECT_FALSE(calculator_ui.encountered_error()); |
259 | 248 |
260 PumpMessages(); | 249 PumpMessages(); |
261 | 250 |
262 // OK, now we see the error. | 251 // OK, now we see the error. |
263 EXPECT_TRUE(calculator_ui.encountered_error()); | 252 EXPECT_TRUE(calculator_ui.encountered_error()); |
264 } | 253 } |
265 | 254 |
266 TEST_F(InterfacePtrTest, EncounteredErrorCallback) { | 255 TEST_F(InterfacePtrTest, EncounteredErrorCallback) { |
267 math::CalculatorPtr proxy; | 256 math::CalculatorPtr proxy; |
268 MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); | 257 MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); |
269 | 258 |
270 ErrorObserver error_observer; | 259 ErrorObserver error_observer; |
271 proxy.set_error_handler(&error_observer); | 260 proxy.set_error_handler(&error_observer); |
272 | 261 |
273 MathCalculatorUIImpl calculator_ui(proxy.Pass()); | 262 MathCalculatorUIImpl calculator_ui(proxy.Pass()); |
274 | 263 |
275 calculator_ui.Add(2.0); | 264 calculator_ui.Add(2.0); |
276 PumpMessages(); | 265 PumpMessages(); |
277 EXPECT_EQ(2.0, calculator_ui.GetOutput()); | 266 EXPECT_EQ(2.0, calculator_ui.GetOutput()); |
278 EXPECT_FALSE(calculator_ui.encountered_error()); | 267 EXPECT_FALSE(calculator_ui.encountered_error()); |
279 | 268 |
280 calculator_ui.Multiply(5.0); | 269 calculator_ui.Multiply(5.0); |
281 EXPECT_FALSE(calculator_ui.encountered_error()); | 270 EXPECT_FALSE(calculator_ui.encountered_error()); |
282 | 271 |
283 // Close the server. | 272 // Close the server. |
284 server->internal_state()->router()->CloseMessagePipe(); | 273 server->internal_router()->CloseMessagePipe(); |
285 | 274 |
286 // The state change isn't picked up locally yet. | 275 // The state change isn't picked up locally yet. |
287 EXPECT_FALSE(calculator_ui.encountered_error()); | 276 EXPECT_FALSE(calculator_ui.encountered_error()); |
288 | 277 |
289 PumpMessages(); | 278 PumpMessages(); |
290 | 279 |
291 // OK, now we see the error. | 280 // OK, now we see the error. |
292 EXPECT_TRUE(calculator_ui.encountered_error()); | 281 EXPECT_TRUE(calculator_ui.encountered_error()); |
293 | 282 |
294 // We should have also been able to observe the error through the | 283 // We should have also been able to observe the error through the |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 impl->BeginTest(true); | 319 impl->BeginTest(true); |
331 | 320 |
332 PumpMessages(); | 321 PumpMessages(); |
333 | 322 |
334 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances()); | 323 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances()); |
335 } | 324 } |
336 | 325 |
337 TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { | 326 TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { |
338 sample::ServicePtr proxy; | 327 sample::ServicePtr proxy; |
339 ReentrantServiceImpl* impl = BindToProxy(new ReentrantServiceImpl(), &proxy); | 328 ReentrantServiceImpl* impl = BindToProxy(new ReentrantServiceImpl(), &proxy); |
340 EXPECT_TRUE(impl->got_connection()); | |
341 | 329 |
342 proxy->Frobinate(sample::FooPtr(), | 330 proxy->Frobinate(sample::FooPtr(), |
343 sample::Service::BAZ_OPTIONS_REGULAR, | 331 sample::Service::BAZ_OPTIONS_REGULAR, |
344 sample::PortPtr()); | 332 sample::PortPtr()); |
345 proxy->Frobinate(sample::FooPtr(), | 333 proxy->Frobinate(sample::FooPtr(), |
346 sample::Service::BAZ_OPTIONS_REGULAR, | 334 sample::Service::BAZ_OPTIONS_REGULAR, |
347 sample::PortPtr()); | 335 sample::PortPtr()); |
348 | 336 |
349 PumpMessages(); | 337 PumpMessages(); |
350 | 338 |
351 EXPECT_EQ(2, impl->max_call_depth()); | 339 EXPECT_EQ(2, impl->max_call_depth()); |
352 } | 340 } |
353 | 341 |
| 342 class StrongMathCalculatorImpl : public math::Calculator, public ErrorHandler { |
| 343 public: |
| 344 StrongMathCalculatorImpl(ScopedMessagePipeHandle handle, |
| 345 bool* error_received, |
| 346 bool* destroyed) |
| 347 : error_received_(error_received), |
| 348 destroyed_(destroyed), |
| 349 binding_(this, handle.Pass()) { |
| 350 binding_.set_error_handler(this); |
| 351 } |
| 352 ~StrongMathCalculatorImpl() override { *destroyed_ = true; } |
| 353 |
| 354 // math::Calculator implementation. |
| 355 void Clear() override { binding_.client()->Output(total_); } |
| 356 |
| 357 void Add(double value) override { |
| 358 total_ += value; |
| 359 binding_.client()->Output(total_); |
| 360 } |
| 361 |
| 362 void Multiply(double value) override { |
| 363 total_ *= value; |
| 364 binding_.client()->Output(total_); |
| 365 } |
| 366 |
| 367 // ErrorHandler implementation. |
| 368 void OnConnectionError() override { *error_received_ = true; } |
| 369 |
| 370 private: |
| 371 double total_ = 0.0; |
| 372 bool* error_received_; |
| 373 bool* destroyed_; |
| 374 |
| 375 StrongBinding<math::Calculator> binding_; |
| 376 }; |
| 377 |
| 378 TEST(StrongConnectorTest, Math) { |
| 379 Environment env; |
| 380 RunLoop loop; |
| 381 |
| 382 bool error_received = false; |
| 383 bool destroyed = false; |
| 384 MessagePipe pipe; |
| 385 new StrongMathCalculatorImpl(pipe.handle0.Pass(), &error_received, |
| 386 &destroyed); |
| 387 |
| 388 math::CalculatorPtr calc; |
| 389 calc.Bind(pipe.handle1.Pass()); |
| 390 |
| 391 { |
| 392 // Suppose this is instantiated in a process that has the other end of the |
| 393 // message pipe. |
| 394 MathCalculatorUIImpl calculator_ui(calc.Pass()); |
| 395 |
| 396 calculator_ui.Add(2.0); |
| 397 calculator_ui.Multiply(5.0); |
| 398 |
| 399 loop.RunUntilIdle(); |
| 400 |
| 401 EXPECT_EQ(10.0, calculator_ui.GetOutput()); |
| 402 EXPECT_FALSE(error_received); |
| 403 EXPECT_FALSE(destroyed); |
| 404 } |
| 405 // Destroying calculator_ui should close the pipe and generate an error on the |
| 406 // other |
| 407 // end which will destroy the instance since it is strongly bound. |
| 408 |
| 409 loop.RunUntilIdle(); |
| 410 EXPECT_TRUE(error_received); |
| 411 EXPECT_TRUE(destroyed); |
| 412 } |
| 413 |
| 414 class WeakMathCalculatorImpl : public math::Calculator, public ErrorHandler { |
| 415 public: |
| 416 WeakMathCalculatorImpl(ScopedMessagePipeHandle handle, |
| 417 bool* error_received, |
| 418 bool* destroyed) |
| 419 : error_received_(error_received), |
| 420 destroyed_(destroyed), |
| 421 binding_(this, handle.Pass()) { |
| 422 binding_.set_error_handler(this); |
| 423 } |
| 424 ~WeakMathCalculatorImpl() override { *destroyed_ = true; } |
| 425 |
| 426 void Clear() override { binding_.client()->Output(total_); } |
| 427 |
| 428 void Add(double value) override { |
| 429 total_ += value; |
| 430 binding_.client()->Output(total_); |
| 431 } |
| 432 |
| 433 void Multiply(double value) override { |
| 434 total_ *= value; |
| 435 binding_.client()->Output(total_); |
| 436 } |
| 437 |
| 438 // ErrorHandler implementation. |
| 439 void OnConnectionError() override { *error_received_ = true; } |
| 440 |
| 441 private: |
| 442 double total_ = 0.0; |
| 443 bool* error_received_; |
| 444 bool* destroyed_; |
| 445 |
| 446 Binding<math::Calculator> binding_; |
| 447 }; |
| 448 |
| 449 TEST(WeakConnectorTest, Math) { |
| 450 Environment env; |
| 451 RunLoop loop; |
| 452 |
| 453 bool error_received = false; |
| 454 bool destroyed = false; |
| 455 MessagePipe pipe; |
| 456 WeakMathCalculatorImpl impl(pipe.handle0.Pass(), &error_received, &destroyed); |
| 457 |
| 458 math::CalculatorPtr calc; |
| 459 calc.Bind(pipe.handle1.Pass()); |
| 460 |
| 461 { |
| 462 // Suppose this is instantiated in a process that has the other end of the |
| 463 // message pipe. |
| 464 MathCalculatorUIImpl calculator_ui(calc.Pass()); |
| 465 |
| 466 calculator_ui.Add(2.0); |
| 467 calculator_ui.Multiply(5.0); |
| 468 |
| 469 loop.RunUntilIdle(); |
| 470 |
| 471 EXPECT_EQ(10.0, calculator_ui.GetOutput()); |
| 472 EXPECT_FALSE(error_received); |
| 473 EXPECT_FALSE(destroyed); |
| 474 // Destroying calculator_ui should close the pipe and generate an error on |
| 475 // the other |
| 476 // end which will destroy the instance since it is strongly bound. |
| 477 } |
| 478 |
| 479 loop.RunUntilIdle(); |
| 480 EXPECT_TRUE(error_received); |
| 481 EXPECT_FALSE(destroyed); |
| 482 } |
| 483 |
354 } // namespace | 484 } // namespace |
355 } // namespace test | 485 } // namespace test |
356 } // namespace mojo | 486 } // namespace mojo |
OLD | NEW |