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" | |
6 #include "mojo/public/cpp/bindings/error_handler.h" | 5 #include "mojo/public/cpp/bindings/error_handler.h" |
7 #include "mojo/public/cpp/bindings/strong_binding.h" | |
8 #include "mojo/public/cpp/environment/environment.h" | 6 #include "mojo/public/cpp/environment/environment.h" |
9 #include "mojo/public/cpp/utility/run_loop.h" | 7 #include "mojo/public/cpp/utility/run_loop.h" |
10 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" | 8 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" |
11 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" | 9 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
13 | 11 |
14 namespace mojo { | 12 namespace mojo { |
15 namespace test { | 13 namespace test { |
16 namespace { | 14 namespace { |
17 | 15 |
18 class ErrorObserver : public ErrorHandler { | 16 class ErrorObserver : public ErrorHandler { |
19 public: | 17 public: |
20 ErrorObserver() : encountered_error_(false) {} | 18 ErrorObserver() : encountered_error_(false) {} |
21 | 19 |
22 bool encountered_error() const { return encountered_error_; } | 20 bool encountered_error() const { return encountered_error_; } |
23 | 21 |
24 void OnConnectionError() override { encountered_error_ = true; } | 22 void OnConnectionError() override { encountered_error_ = true; } |
25 | 23 |
26 private: | 24 private: |
27 bool encountered_error_; | 25 bool encountered_error_; |
28 }; | 26 }; |
29 | 27 |
30 class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { | 28 class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { |
31 public: | 29 public: |
32 ~MathCalculatorImpl() override {} | 30 ~MathCalculatorImpl() override {} |
33 | 31 |
34 MathCalculatorImpl() : total_(0.0) {} | 32 MathCalculatorImpl() : total_(0.0), got_connection_(false) {} |
| 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 |
48 private: | 50 private: |
49 double total_; | 51 double total_; |
| 52 bool got_connection_; |
50 }; | 53 }; |
51 | 54 |
52 class MathCalculatorUIImpl : public math::CalculatorUI { | 55 class MathCalculatorUIImpl : public math::CalculatorUI { |
53 public: | 56 public: |
54 explicit MathCalculatorUIImpl(math::CalculatorPtr calculator) | 57 explicit MathCalculatorUIImpl(math::CalculatorPtr calculator) |
55 : calculator_(calculator.Pass()), output_(0.0) { | 58 : calculator_(calculator.Pass()), output_(0.0) { |
56 calculator_.set_client(this); | 59 calculator_.set_client(this); |
57 } | 60 } |
58 | 61 |
59 bool WaitForIncomingMethodCall() { | 62 bool WaitForIncomingMethodCall() { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 static int num_instances_; | 116 static int num_instances_; |
114 }; | 117 }; |
115 | 118 |
116 // static | 119 // static |
117 int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0; | 120 int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0; |
118 | 121 |
119 class ReentrantServiceImpl : public InterfaceImpl<sample::Service> { | 122 class ReentrantServiceImpl : public InterfaceImpl<sample::Service> { |
120 public: | 123 public: |
121 ~ReentrantServiceImpl() override {} | 124 ~ReentrantServiceImpl() override {} |
122 | 125 |
123 ReentrantServiceImpl() : call_depth_(0), max_call_depth_(0) {} | 126 ReentrantServiceImpl() |
| 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_; } |
124 | 132 |
125 int max_call_depth() { return max_call_depth_; } | 133 int max_call_depth() { return max_call_depth_; } |
126 | 134 |
127 void Frobinate(sample::FooPtr foo, | 135 void Frobinate(sample::FooPtr foo, |
128 sample::Service::BazOptions baz, | 136 sample::Service::BazOptions baz, |
129 sample::PortPtr port) override { | 137 sample::PortPtr port) override { |
130 max_call_depth_ = std::max(++call_depth_, max_call_depth_); | 138 max_call_depth_ = std::max(++call_depth_, max_call_depth_); |
131 if (call_depth_ == 1) { | 139 if (call_depth_ == 1) { |
132 EXPECT_TRUE(WaitForIncomingMethodCall()); | 140 EXPECT_TRUE(WaitForIncomingMethodCall()); |
133 } | 141 } |
134 call_depth_--; | 142 call_depth_--; |
135 } | 143 } |
136 | 144 |
137 void GetPort(mojo::InterfaceRequest<sample::Port> port) override {} | 145 void GetPort(mojo::InterfaceRequest<sample::Port> port) override {} |
138 | 146 |
139 private: | 147 private: |
| 148 bool got_connection_; |
140 int call_depth_; | 149 int call_depth_; |
141 int max_call_depth_; | 150 int max_call_depth_; |
142 }; | 151 }; |
143 | 152 |
144 class InterfacePtrTest : public testing::Test { | 153 class InterfacePtrTest : public testing::Test { |
145 public: | 154 public: |
146 ~InterfacePtrTest() override { loop_.RunUntilIdle(); } | 155 ~InterfacePtrTest() override { loop_.RunUntilIdle(); } |
147 | 156 |
148 void PumpMessages() { loop_.RunUntilIdle(); } | 157 void PumpMessages() { loop_.RunUntilIdle(); } |
149 | 158 |
150 private: | 159 private: |
151 Environment env_; | 160 Environment env_; |
152 RunLoop loop_; | 161 RunLoop loop_; |
153 }; | 162 }; |
154 | 163 |
155 TEST_F(InterfacePtrTest, EndToEnd) { | 164 TEST_F(InterfacePtrTest, EndToEnd) { |
156 math::CalculatorPtr calc; | 165 math::CalculatorPtr calc; |
157 BindToProxy(new MathCalculatorImpl(), &calc); | 166 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); |
| 167 EXPECT_TRUE(impl->got_connection()); |
158 | 168 |
159 // Suppose this is instantiated in a process that has pipe1_. | 169 // Suppose this is instantiated in a process that has pipe1_. |
160 MathCalculatorUIImpl calculator_ui(calc.Pass()); | 170 MathCalculatorUIImpl calculator_ui(calc.Pass()); |
161 | 171 |
162 calculator_ui.Add(2.0); | 172 calculator_ui.Add(2.0); |
163 calculator_ui.Multiply(5.0); | 173 calculator_ui.Multiply(5.0); |
164 | 174 |
165 PumpMessages(); | 175 PumpMessages(); |
166 | 176 |
167 EXPECT_EQ(10.0, calculator_ui.GetOutput()); | 177 EXPECT_EQ(10.0, calculator_ui.GetOutput()); |
168 } | 178 } |
169 | 179 |
170 TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { | 180 TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { |
171 math::CalculatorPtr calc; | 181 math::CalculatorPtr calc; |
172 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); | 182 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc); |
| 183 EXPECT_TRUE(impl->got_connection()); |
173 | 184 |
174 // Suppose this is instantiated in a process that has pipe1_. | 185 // Suppose this is instantiated in a process that has pipe1_. |
175 MathCalculatorUIImpl calculator_ui(calc.Pass()); | 186 MathCalculatorUIImpl calculator_ui(calc.Pass()); |
176 | 187 |
177 EXPECT_EQ(0.0, calculator_ui.GetOutput()); | 188 EXPECT_EQ(0.0, calculator_ui.GetOutput()); |
178 | 189 |
179 calculator_ui.Add(2.0); | 190 calculator_ui.Add(2.0); |
180 EXPECT_EQ(0.0, calculator_ui.GetOutput()); | 191 EXPECT_EQ(0.0, calculator_ui.GetOutput()); |
181 impl->WaitForIncomingMethodCall(); | 192 impl->WaitForIncomingMethodCall(); |
182 calculator_ui.WaitForIncomingMethodCall(); | 193 calculator_ui.WaitForIncomingMethodCall(); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 | 245 |
235 calculator_ui.Add(2.0); | 246 calculator_ui.Add(2.0); |
236 PumpMessages(); | 247 PumpMessages(); |
237 EXPECT_EQ(2.0, calculator_ui.GetOutput()); | 248 EXPECT_EQ(2.0, calculator_ui.GetOutput()); |
238 EXPECT_FALSE(calculator_ui.encountered_error()); | 249 EXPECT_FALSE(calculator_ui.encountered_error()); |
239 | 250 |
240 calculator_ui.Multiply(5.0); | 251 calculator_ui.Multiply(5.0); |
241 EXPECT_FALSE(calculator_ui.encountered_error()); | 252 EXPECT_FALSE(calculator_ui.encountered_error()); |
242 | 253 |
243 // Close the server. | 254 // Close the server. |
244 server->internal_router()->CloseMessagePipe(); | 255 server->internal_state()->router()->CloseMessagePipe(); |
245 | 256 |
246 // The state change isn't picked up locally yet. | 257 // The state change isn't picked up locally yet. |
247 EXPECT_FALSE(calculator_ui.encountered_error()); | 258 EXPECT_FALSE(calculator_ui.encountered_error()); |
248 | 259 |
249 PumpMessages(); | 260 PumpMessages(); |
250 | 261 |
251 // OK, now we see the error. | 262 // OK, now we see the error. |
252 EXPECT_TRUE(calculator_ui.encountered_error()); | 263 EXPECT_TRUE(calculator_ui.encountered_error()); |
253 } | 264 } |
254 | 265 |
255 TEST_F(InterfacePtrTest, EncounteredErrorCallback) { | 266 TEST_F(InterfacePtrTest, EncounteredErrorCallback) { |
256 math::CalculatorPtr proxy; | 267 math::CalculatorPtr proxy; |
257 MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); | 268 MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); |
258 | 269 |
259 ErrorObserver error_observer; | 270 ErrorObserver error_observer; |
260 proxy.set_error_handler(&error_observer); | 271 proxy.set_error_handler(&error_observer); |
261 | 272 |
262 MathCalculatorUIImpl calculator_ui(proxy.Pass()); | 273 MathCalculatorUIImpl calculator_ui(proxy.Pass()); |
263 | 274 |
264 calculator_ui.Add(2.0); | 275 calculator_ui.Add(2.0); |
265 PumpMessages(); | 276 PumpMessages(); |
266 EXPECT_EQ(2.0, calculator_ui.GetOutput()); | 277 EXPECT_EQ(2.0, calculator_ui.GetOutput()); |
267 EXPECT_FALSE(calculator_ui.encountered_error()); | 278 EXPECT_FALSE(calculator_ui.encountered_error()); |
268 | 279 |
269 calculator_ui.Multiply(5.0); | 280 calculator_ui.Multiply(5.0); |
270 EXPECT_FALSE(calculator_ui.encountered_error()); | 281 EXPECT_FALSE(calculator_ui.encountered_error()); |
271 | 282 |
272 // Close the server. | 283 // Close the server. |
273 server->internal_router()->CloseMessagePipe(); | 284 server->internal_state()->router()->CloseMessagePipe(); |
274 | 285 |
275 // The state change isn't picked up locally yet. | 286 // The state change isn't picked up locally yet. |
276 EXPECT_FALSE(calculator_ui.encountered_error()); | 287 EXPECT_FALSE(calculator_ui.encountered_error()); |
277 | 288 |
278 PumpMessages(); | 289 PumpMessages(); |
279 | 290 |
280 // OK, now we see the error. | 291 // OK, now we see the error. |
281 EXPECT_TRUE(calculator_ui.encountered_error()); | 292 EXPECT_TRUE(calculator_ui.encountered_error()); |
282 | 293 |
283 // We should have also been able to observe the error through the | 294 // 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... |
319 impl->BeginTest(true); | 330 impl->BeginTest(true); |
320 | 331 |
321 PumpMessages(); | 332 PumpMessages(); |
322 | 333 |
323 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances()); | 334 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances()); |
324 } | 335 } |
325 | 336 |
326 TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { | 337 TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { |
327 sample::ServicePtr proxy; | 338 sample::ServicePtr proxy; |
328 ReentrantServiceImpl* impl = BindToProxy(new ReentrantServiceImpl(), &proxy); | 339 ReentrantServiceImpl* impl = BindToProxy(new ReentrantServiceImpl(), &proxy); |
| 340 EXPECT_TRUE(impl->got_connection()); |
329 | 341 |
330 proxy->Frobinate(sample::FooPtr(), | 342 proxy->Frobinate(sample::FooPtr(), |
331 sample::Service::BAZ_OPTIONS_REGULAR, | 343 sample::Service::BAZ_OPTIONS_REGULAR, |
332 sample::PortPtr()); | 344 sample::PortPtr()); |
333 proxy->Frobinate(sample::FooPtr(), | 345 proxy->Frobinate(sample::FooPtr(), |
334 sample::Service::BAZ_OPTIONS_REGULAR, | 346 sample::Service::BAZ_OPTIONS_REGULAR, |
335 sample::PortPtr()); | 347 sample::PortPtr()); |
336 | 348 |
337 PumpMessages(); | 349 PumpMessages(); |
338 | 350 |
339 EXPECT_EQ(2, impl->max_call_depth()); | 351 EXPECT_EQ(2, impl->max_call_depth()); |
340 } | 352 } |
341 | 353 |
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 | |
484 } // namespace | 354 } // namespace |
485 } // namespace test | 355 } // namespace test |
486 } // namespace mojo | 356 } // namespace mojo |
OLD | NEW |