OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/logging.h" | 6 #include "base/logging.h" |
7 #include "base/macros.h" | 7 #include "base/macros.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "base/threading/thread.h" | 10 #include "base/threading/thread.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 ~SyncMethodTest() override { loop_.RunUntilIdle(); } | 23 ~SyncMethodTest() override { loop_.RunUntilIdle(); } |
24 | 24 |
25 private: | 25 private: |
26 base::MessageLoop loop_; | 26 base::MessageLoop loop_; |
27 }; | 27 }; |
28 | 28 |
29 class TestSyncImpl : public TestSync { | 29 class TestSyncImpl : public TestSync { |
30 public: | 30 public: |
31 TestSyncImpl(TestSyncRequest request) : binding_(this, std::move(request)) {} | 31 TestSyncImpl(TestSyncRequest request) : binding_(this, std::move(request)) {} |
32 | 32 |
33 void set_ping_notification(const Closure& closure) { | 33 using PingHandler = Callback<void(const PingCallback&)>; |
34 ping_notification_ = closure; | 34 void set_ping_handler(const PingHandler& handler) { ping_handler_ = handler; } |
| 35 |
| 36 using EchoHandler = Callback<void(int32_t, const EchoCallback&)>; |
| 37 void set_echo_handler(const EchoHandler& handler) { echo_handler_ = handler; } |
| 38 |
| 39 using AsyncEchoHandler = Callback<void(int32_t, const AsyncEchoCallback&)>; |
| 40 void set_async_echo_handler(const AsyncEchoHandler& handler) { |
| 41 async_echo_handler_ = handler; |
35 } | 42 } |
36 | 43 |
37 // TestSync implementation: | 44 // TestSync implementation: |
38 void Get(const GetCallback& callback) override { callback.Run(42); } | |
39 void Set(int32_t value, const SetCallback& callback) override { | |
40 callback.Run(); | |
41 } | |
42 void Ping(const PingCallback& callback) override { | 45 void Ping(const PingCallback& callback) override { |
43 ping_notification_.Run(); | 46 if (ping_handler_.is_null()) { |
44 callback.Run(); | 47 callback.Run(); |
| 48 return; |
| 49 } |
| 50 ping_handler_.Run(callback); |
45 } | 51 } |
46 void Echo(int32_t value, const EchoCallback& callback) override { | 52 void Echo(int32_t value, const EchoCallback& callback) override { |
47 callback.Run(value); | 53 if (echo_handler_.is_null()) { |
| 54 callback.Run(value); |
| 55 return; |
| 56 } |
| 57 echo_handler_.Run(value, callback); |
48 } | 58 } |
| 59 void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override { |
| 60 if (async_echo_handler_.is_null()) { |
| 61 callback.Run(value); |
| 62 return; |
| 63 } |
| 64 async_echo_handler_.Run(value, callback); |
| 65 } |
| 66 |
| 67 Binding<TestSync>* binding() { return &binding_; } |
49 | 68 |
50 private: | 69 private: |
51 Binding<TestSync> binding_; | 70 Binding<TestSync> binding_; |
52 Closure ping_notification_; | 71 PingHandler ping_handler_; |
| 72 EchoHandler echo_handler_; |
| 73 AsyncEchoHandler async_echo_handler_; |
53 | 74 |
54 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl); | 75 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl); |
55 }; | 76 }; |
56 | 77 |
57 class TestSyncServiceThread { | 78 class TestSyncServiceThread { |
58 public: | 79 public: |
59 TestSyncServiceThread() | 80 TestSyncServiceThread() |
60 : thread_("TestSyncServiceThread"), ping_called_(false) { | 81 : thread_("TestSyncServiceThread"), ping_called_(false) { |
61 base::Thread::Options thread_options; | 82 base::Thread::Options thread_options; |
62 thread_options.message_pump_factory = | 83 thread_options.message_pump_factory = |
63 base::Bind(&common::MessagePumpMojo::Create); | 84 base::Bind(&common::MessagePumpMojo::Create); |
64 thread_.StartWithOptions(thread_options); | 85 thread_.StartWithOptions(thread_options); |
65 } | 86 } |
66 | 87 |
67 void SetUp(TestSyncRequest request) { | 88 void SetUp(TestSyncRequest request) { |
68 CHECK(thread_.task_runner()->BelongsToCurrentThread()); | 89 CHECK(thread_.task_runner()->BelongsToCurrentThread()); |
69 impl_.reset(new TestSyncImpl(std::move(request))); | 90 impl_.reset(new TestSyncImpl(std::move(request))); |
70 impl_->set_ping_notification([this]() { | 91 impl_->set_ping_handler([this](const TestSync::PingCallback& callback) { |
71 base::AutoLock locker(lock_); | 92 { |
72 ping_called_ = true; | 93 base::AutoLock locker(lock_); |
| 94 ping_called_ = true; |
| 95 } |
| 96 callback.Run(); |
73 }); | 97 }); |
74 } | 98 } |
75 | 99 |
76 void TearDown() { | 100 void TearDown() { |
77 CHECK(thread_.task_runner()->BelongsToCurrentThread()); | 101 CHECK(thread_.task_runner()->BelongsToCurrentThread()); |
78 impl_.reset(); | 102 impl_.reset(); |
79 } | 103 } |
80 | 104 |
81 base::Thread* thread() { return &thread_; } | 105 base::Thread* thread() { return &thread_; } |
82 bool ping_called() const { | 106 bool ping_called() const { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 ASSERT_EQ(42, output_value); | 147 ASSERT_EQ(42, output_value); |
124 | 148 |
125 base::RunLoop run_loop; | 149 base::RunLoop run_loop; |
126 service_thread.thread()->task_runner()->PostTaskAndReply( | 150 service_thread.thread()->task_runner()->PostTaskAndReply( |
127 FROM_HERE, base::Bind(&TestSyncServiceThread::TearDown, | 151 FROM_HERE, base::Bind(&TestSyncServiceThread::TearDown, |
128 base::Unretained(&service_thread)), | 152 base::Unretained(&service_thread)), |
129 run_loop.QuitClosure()); | 153 run_loop.QuitClosure()); |
130 run_loop.Run(); | 154 run_loop.Run(); |
131 } | 155 } |
132 | 156 |
| 157 TEST_F(SyncMethodTest, ReenteredBySyncMethodBinding) { |
| 158 // Test that an interface pointer waiting for a sync call response can be |
| 159 // reentered by a binding serving sync methods on the same thread. |
| 160 |
| 161 TestSyncPtr ptr; |
| 162 // The binding lives on the same thread as the interface pointer. |
| 163 TestSyncImpl impl(GetProxy(&ptr)); |
| 164 int32_t output_value = -1; |
| 165 ASSERT_TRUE(ptr->Echo(42, &output_value)); |
| 166 EXPECT_EQ(42, output_value); |
| 167 } |
| 168 |
| 169 TEST_F(SyncMethodTest, InterefacePtrDestroyedDuringSyncCall) { |
| 170 // Test that it won't result in crash or hang if an interface pointer is |
| 171 // destroyed while it is waiting for a sync call response. |
| 172 |
| 173 TestSyncPtr ptr; |
| 174 TestSyncImpl impl(GetProxy(&ptr)); |
| 175 impl.set_ping_handler([&ptr](const TestSync::PingCallback& callback) { |
| 176 ptr.reset(); |
| 177 callback.Run(); |
| 178 }); |
| 179 ASSERT_FALSE(ptr->Ping()); |
| 180 } |
| 181 |
| 182 TEST_F(SyncMethodTest, BindingDestroyedDuringSyncCall) { |
| 183 // Test that it won't result in crash or hang if a binding is |
| 184 // closed (and therefore the message pipe handle is closed) while the |
| 185 // corresponding interface pointer is waiting for a sync call response. |
| 186 |
| 187 TestSyncPtr ptr; |
| 188 TestSyncImpl impl(GetProxy(&ptr)); |
| 189 impl.set_ping_handler([&impl](const TestSync::PingCallback& callback) { |
| 190 impl.binding()->Close(); |
| 191 callback.Run(); |
| 192 }); |
| 193 ASSERT_FALSE(ptr->Ping()); |
| 194 } |
| 195 |
| 196 TEST_F(SyncMethodTest, NestedSyncCallsWithInOrderResponses) { |
| 197 // Test that we can call a sync method on an interface ptr, while there is |
| 198 // already a sync call ongoing. The responses arrive in order. |
| 199 |
| 200 TestSyncPtr ptr; |
| 201 TestSyncImpl impl(GetProxy(&ptr)); |
| 202 |
| 203 // The same variable is used to store the output of the two sync calls, in |
| 204 // order to test that responses are handled in the correct order. |
| 205 int32_t result_value = -1; |
| 206 |
| 207 bool first_call = true; |
| 208 impl.set_echo_handler([&first_call, &ptr, &result_value]( |
| 209 int32_t value, const TestSync::EchoCallback& callback) { |
| 210 if (first_call) { |
| 211 first_call = false; |
| 212 ASSERT_TRUE(ptr->Echo(456, &result_value)); |
| 213 EXPECT_EQ(456, result_value); |
| 214 } |
| 215 callback.Run(value); |
| 216 }); |
| 217 |
| 218 ASSERT_TRUE(ptr->Echo(123, &result_value)); |
| 219 EXPECT_EQ(123, result_value); |
| 220 } |
| 221 |
| 222 TEST_F(SyncMethodTest, NestedSyncCallsWithOutOfOrderResponses) { |
| 223 // Test that we can call a sync method on an interface ptr, while there is |
| 224 // already a sync call ongoing. The responses arrive out of order. |
| 225 |
| 226 TestSyncPtr ptr; |
| 227 TestSyncImpl impl(GetProxy(&ptr)); |
| 228 |
| 229 // The same variable is used to store the output of the two sync calls, in |
| 230 // order to test that responses are handled in the correct order. |
| 231 int32_t result_value = -1; |
| 232 |
| 233 bool first_call = true; |
| 234 impl.set_echo_handler([&first_call, &ptr, &result_value]( |
| 235 int32_t value, const TestSync::EchoCallback& callback) { |
| 236 callback.Run(value); |
| 237 if (first_call) { |
| 238 first_call = false; |
| 239 ASSERT_TRUE(ptr->Echo(456, &result_value)); |
| 240 EXPECT_EQ(456, result_value); |
| 241 } |
| 242 }); |
| 243 |
| 244 ASSERT_TRUE(ptr->Echo(123, &result_value)); |
| 245 EXPECT_EQ(123, result_value); |
| 246 } |
| 247 |
| 248 TEST_F(SyncMethodTest, AsyncResponseQueuedDuringSyncCall) { |
| 249 // Test that while an interface pointer is waiting for the response to a sync |
| 250 // call, async responses are queued until the sync call completes. |
| 251 |
| 252 TestSyncPtr ptr; |
| 253 TestSyncImpl impl(GetProxy(&ptr)); |
| 254 |
| 255 int32_t async_echo_request_value = -1; |
| 256 TestSync::AsyncEchoCallback async_echo_request_callback; |
| 257 base::RunLoop run_loop1; |
| 258 impl.set_async_echo_handler( |
| 259 [&async_echo_request_value, &async_echo_request_callback, &run_loop1]( |
| 260 int32_t value, const TestSync::AsyncEchoCallback& callback) { |
| 261 async_echo_request_value = value; |
| 262 async_echo_request_callback = callback; |
| 263 run_loop1.Quit(); |
| 264 }); |
| 265 |
| 266 bool async_echo_response_dispatched = false; |
| 267 base::RunLoop run_loop2; |
| 268 ptr->AsyncEcho(123, |
| 269 [&async_echo_response_dispatched, &run_loop2](int32_t result) { |
| 270 async_echo_response_dispatched = true; |
| 271 EXPECT_EQ(123, result); |
| 272 run_loop2.Quit(); |
| 273 }); |
| 274 // Run until the AsyncEcho request reaches the service side. |
| 275 run_loop1.Run(); |
| 276 |
| 277 impl.set_echo_handler( |
| 278 [&async_echo_request_value, &async_echo_request_callback]( |
| 279 int32_t value, const TestSync::EchoCallback& callback) { |
| 280 // Send back the async response first. |
| 281 EXPECT_FALSE(async_echo_request_callback.is_null()); |
| 282 async_echo_request_callback.Run(async_echo_request_value); |
| 283 |
| 284 callback.Run(value); |
| 285 }); |
| 286 |
| 287 int32_t result_value = -1; |
| 288 ASSERT_TRUE(ptr->Echo(456, &result_value)); |
| 289 EXPECT_EQ(456, result_value); |
| 290 |
| 291 // Although the AsyncEcho response arrives before the Echo response, it should |
| 292 // be queued and not yet dispatched. |
| 293 EXPECT_FALSE(async_echo_response_dispatched); |
| 294 |
| 295 // Run until the AsyncEcho response is dispatched. |
| 296 run_loop2.Run(); |
| 297 |
| 298 EXPECT_TRUE(async_echo_response_dispatched); |
| 299 } |
| 300 |
| 301 TEST_F(SyncMethodTest, AsyncRequestQueuedDuringSyncCall) { |
| 302 // Test that while an interface pointer is waiting for the response to a sync |
| 303 // call, async requests for a binding running on the same thread are queued |
| 304 // until the sync call completes. |
| 305 |
| 306 TestSyncPtr ptr; |
| 307 TestSyncImpl impl(GetProxy(&ptr)); |
| 308 |
| 309 bool async_echo_request_dispatched = false; |
| 310 impl.set_async_echo_handler([&async_echo_request_dispatched]( |
| 311 int32_t value, const TestSync::AsyncEchoCallback& callback) { |
| 312 async_echo_request_dispatched = true; |
| 313 callback.Run(value); |
| 314 }); |
| 315 |
| 316 bool async_echo_response_dispatched = false; |
| 317 base::RunLoop run_loop; |
| 318 ptr->AsyncEcho(123, |
| 319 [&async_echo_response_dispatched, &run_loop](int32_t result) { |
| 320 async_echo_response_dispatched = true; |
| 321 EXPECT_EQ(123, result); |
| 322 run_loop.Quit(); |
| 323 }); |
| 324 |
| 325 impl.set_echo_handler([&async_echo_request_dispatched]( |
| 326 int32_t value, const TestSync::EchoCallback& callback) { |
| 327 // Although the AsyncEcho request is sent before the Echo request, it |
| 328 // shouldn't be dispatched yet at this point, because there is an ongoing |
| 329 // sync call on the same thread. |
| 330 EXPECT_FALSE(async_echo_request_dispatched); |
| 331 callback.Run(value); |
| 332 }); |
| 333 |
| 334 int32_t result_value = -1; |
| 335 ASSERT_TRUE(ptr->Echo(456, &result_value)); |
| 336 EXPECT_EQ(456, result_value); |
| 337 |
| 338 // Although the AsyncEcho request is sent before the Echo request, it |
| 339 // shouldn't be dispatched yet. |
| 340 EXPECT_FALSE(async_echo_request_dispatched); |
| 341 |
| 342 // Run until the AsyncEcho response is dispatched. |
| 343 run_loop.Run(); |
| 344 |
| 345 EXPECT_TRUE(async_echo_response_dispatched); |
| 346 } |
| 347 |
133 } // namespace | 348 } // namespace |
134 } // namespace test | 349 } // namespace test |
135 } // namespace mojo | 350 } // namespace mojo |
OLD | NEW |