| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 #include "mojo/public/cpp/utility/run_loop.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "gtest/gtest.h" | |
| 10 #include "mojo/public/cpp/system/macros.h" | |
| 11 #include "mojo/public/cpp/system/message_pipe.h" | |
| 12 #include "mojo/public/cpp/test_support/test_utils.h" | |
| 13 #include "mojo/public/cpp/utility/run_loop_handler.h" | |
| 14 | |
| 15 namespace mojo { | |
| 16 namespace { | |
| 17 | |
| 18 class TestRunLoopHandler : public RunLoopHandler { | |
| 19 public: | |
| 20 TestRunLoopHandler() {} | |
| 21 ~TestRunLoopHandler() override {} | |
| 22 | |
| 23 void clear_ready_count() { ready_count_ = 0; } | |
| 24 int ready_count() const { return ready_count_; } | |
| 25 | |
| 26 void clear_error_count() { error_count_ = 0; } | |
| 27 int error_count() const { return error_count_; } | |
| 28 | |
| 29 void clear_expected_handler_id() { have_expected_handler_id_ = false; } | |
| 30 void set_expected_handler_id(Id id) { | |
| 31 have_expected_handler_id_ = true; | |
| 32 expected_handler_id_ = id; | |
| 33 } | |
| 34 | |
| 35 MojoResult last_error_result() const { return last_error_result_; } | |
| 36 | |
| 37 // RunLoopHandler: | |
| 38 void OnHandleReady(Id id) override { | |
| 39 ready_count_++; | |
| 40 if (have_expected_handler_id_) { | |
| 41 EXPECT_EQ(expected_handler_id_, id); | |
| 42 clear_expected_handler_id(); | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 void OnHandleError(Id id, MojoResult result) override { | |
| 47 error_count_++; | |
| 48 last_error_result_ = result; | |
| 49 if (have_expected_handler_id_) { | |
| 50 EXPECT_EQ(expected_handler_id_, id); | |
| 51 clear_expected_handler_id(); | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 int ready_count_ = 0; | |
| 57 int error_count_ = 0; | |
| 58 bool have_expected_handler_id_ = false; | |
| 59 Id expected_handler_id_ = 0u; | |
| 60 MojoResult last_error_result_ = MOJO_RESULT_OK; | |
| 61 | |
| 62 MOJO_DISALLOW_COPY_AND_ASSIGN(TestRunLoopHandler); | |
| 63 }; | |
| 64 | |
| 65 // Trivial test to verify Run() with no added handles returns. | |
| 66 TEST(RunLoopTest, ExitsWithNoHandles) { | |
| 67 RunLoop run_loop; | |
| 68 run_loop.Run(); | |
| 69 } | |
| 70 | |
| 71 class RemoveOnReadyRunLoopHandler : public TestRunLoopHandler { | |
| 72 public: | |
| 73 RemoveOnReadyRunLoopHandler() : run_loop_(nullptr) {} | |
| 74 ~RemoveOnReadyRunLoopHandler() override {} | |
| 75 | |
| 76 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 77 | |
| 78 // RunLoopHandler: | |
| 79 void OnHandleReady(Id id) override { | |
| 80 run_loop_->RemoveHandler(id); | |
| 81 TestRunLoopHandler::OnHandleReady(id); | |
| 82 } | |
| 83 | |
| 84 private: | |
| 85 RunLoop* run_loop_; | |
| 86 | |
| 87 MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveOnReadyRunLoopHandler); | |
| 88 }; | |
| 89 | |
| 90 // Verifies RunLoop quits when no more handles (handle is removed when ready). | |
| 91 TEST(RunLoopTest, HandleReady) { | |
| 92 RemoveOnReadyRunLoopHandler handler; | |
| 93 MessagePipe test_pipe; | |
| 94 EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string())); | |
| 95 | |
| 96 RunLoop run_loop; | |
| 97 handler.set_run_loop(&run_loop); | |
| 98 auto id = run_loop.AddHandler(&handler, test_pipe.handle0.get(), | |
| 99 MOJO_HANDLE_SIGNAL_READABLE, | |
| 100 MOJO_DEADLINE_INDEFINITE); | |
| 101 handler.set_expected_handler_id(id); | |
| 102 run_loop.Run(); | |
| 103 EXPECT_EQ(1, handler.ready_count()); | |
| 104 EXPECT_EQ(0, handler.error_count()); | |
| 105 EXPECT_EQ(0u, run_loop.num_handlers()); | |
| 106 } | |
| 107 | |
| 108 class QuitOnReadyRunLoopHandler : public TestRunLoopHandler { | |
| 109 public: | |
| 110 QuitOnReadyRunLoopHandler() {} | |
| 111 ~QuitOnReadyRunLoopHandler() override {} | |
| 112 | |
| 113 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 114 | |
| 115 // RunLoopHandler: | |
| 116 void OnHandleReady(Id id) override { | |
| 117 run_loop_->Quit(); | |
| 118 TestRunLoopHandler::OnHandleReady(id); | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 RunLoop* run_loop_ = nullptr; | |
| 123 | |
| 124 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnReadyRunLoopHandler); | |
| 125 }; | |
| 126 | |
| 127 // Verifies Quit() from OnHandleReady() quits the loop. | |
| 128 TEST(RunLoopTest, QuitFromReady) { | |
| 129 QuitOnReadyRunLoopHandler handler; | |
| 130 MessagePipe test_pipe; | |
| 131 EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string())); | |
| 132 | |
| 133 RunLoopHandler::Id id2; | |
| 134 { | |
| 135 RunLoop run_loop; | |
| 136 handler.set_run_loop(&run_loop); | |
| 137 auto id1 = run_loop.AddHandler(&handler, test_pipe.handle0.get(), | |
| 138 MOJO_HANDLE_SIGNAL_READABLE, | |
| 139 MOJO_DEADLINE_INDEFINITE); | |
| 140 handler.set_expected_handler_id(id1); | |
| 141 // Quitting should keep this handler. | |
| 142 id2 = run_loop.AddHandler(&handler, test_pipe.handle1.get(), | |
| 143 MOJO_HANDLE_SIGNAL_READABLE, | |
| 144 MOJO_DEADLINE_INDEFINITE); | |
| 145 EXPECT_NE(id2, id1); | |
| 146 run_loop.Run(); | |
| 147 EXPECT_EQ(1, handler.ready_count()); | |
| 148 EXPECT_EQ(0, handler.error_count()); | |
| 149 EXPECT_EQ(1u, run_loop.num_handlers()); | |
| 150 | |
| 151 // Destroying the RunLoop should call the second handler's OnHandleError(). | |
| 152 handler.set_expected_handler_id(id2); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 class QuitOnErrorRunLoopHandler : public TestRunLoopHandler { | |
| 157 public: | |
| 158 QuitOnErrorRunLoopHandler() {} | |
| 159 ~QuitOnErrorRunLoopHandler() override {} | |
| 160 | |
| 161 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 162 | |
| 163 // RunLoopHandler: | |
| 164 void OnHandleError(Id id, MojoResult result) override { | |
| 165 run_loop_->Quit(); | |
| 166 TestRunLoopHandler::OnHandleError(id, result); | |
| 167 } | |
| 168 | |
| 169 private: | |
| 170 RunLoop* run_loop_ = nullptr; | |
| 171 | |
| 172 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnErrorRunLoopHandler); | |
| 173 }; | |
| 174 | |
| 175 // Verifies Quit() when the deadline is reached works. | |
| 176 TEST(RunLoopTest, QuitWhenDeadlineExpired) { | |
| 177 QuitOnErrorRunLoopHandler handler; | |
| 178 MessagePipe test_pipe; | |
| 179 RunLoop run_loop; | |
| 180 handler.set_run_loop(&run_loop); | |
| 181 auto id = run_loop.AddHandler(&handler, test_pipe.handle0.get(), | |
| 182 MOJO_HANDLE_SIGNAL_READABLE, | |
| 183 static_cast<MojoDeadline>(10000)); | |
| 184 handler.set_expected_handler_id(id); | |
| 185 run_loop.Run(); | |
| 186 EXPECT_EQ(0, handler.ready_count()); | |
| 187 EXPECT_EQ(1, handler.error_count()); | |
| 188 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, handler.last_error_result()); | |
| 189 EXPECT_EQ(0u, run_loop.num_handlers()); | |
| 190 } | |
| 191 | |
| 192 // Test that handlers are notified of loop destruction. | |
| 193 TEST(RunLoopTest, Destruction) { | |
| 194 TestRunLoopHandler handler; | |
| 195 MessagePipe test_pipe; | |
| 196 { | |
| 197 RunLoop run_loop; | |
| 198 auto id = run_loop.AddHandler(&handler, test_pipe.handle0.get(), | |
| 199 MOJO_HANDLE_SIGNAL_READABLE, | |
| 200 MOJO_DEADLINE_INDEFINITE); | |
| 201 handler.set_expected_handler_id(id); | |
| 202 } | |
| 203 EXPECT_EQ(1, handler.error_count()); | |
| 204 EXPECT_EQ(MOJO_RESULT_ABORTED, handler.last_error_result()); | |
| 205 } | |
| 206 | |
| 207 class RemoveManyRunLoopHandler : public TestRunLoopHandler { | |
| 208 public: | |
| 209 RemoveManyRunLoopHandler() {} | |
| 210 ~RemoveManyRunLoopHandler() override {} | |
| 211 | |
| 212 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 213 void add_id(Id id) { ids_.push_back(id); } | |
| 214 | |
| 215 // RunLoopHandler: | |
| 216 void OnHandleError(Id id, MojoResult result) override { | |
| 217 for (size_t i = 0; i < ids_.size(); i++) | |
| 218 run_loop_->RemoveHandler(ids_[i]); | |
| 219 TestRunLoopHandler::OnHandleError(id, result); | |
| 220 } | |
| 221 | |
| 222 private: | |
| 223 std::vector<Id> ids_; | |
| 224 RunLoop* run_loop_ = nullptr; | |
| 225 | |
| 226 MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveManyRunLoopHandler); | |
| 227 }; | |
| 228 | |
| 229 // Test that handlers are notified of loop destruction. | |
| 230 TEST(RunLoopTest, MultipleHandleDestruction) { | |
| 231 RemoveManyRunLoopHandler odd_handler; | |
| 232 TestRunLoopHandler even_handler; | |
| 233 MessagePipe test_pipe1, test_pipe2, test_pipe3; | |
| 234 { | |
| 235 RunLoop run_loop; | |
| 236 odd_handler.set_run_loop(&run_loop); | |
| 237 odd_handler.add_id(run_loop.AddHandler( | |
| 238 &odd_handler, test_pipe1.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, | |
| 239 MOJO_DEADLINE_INDEFINITE)); | |
| 240 auto even_id = run_loop.AddHandler(&even_handler, test_pipe2.handle0.get(), | |
| 241 MOJO_HANDLE_SIGNAL_READABLE, | |
| 242 MOJO_DEADLINE_INDEFINITE); | |
| 243 even_handler.set_expected_handler_id(even_id); | |
| 244 odd_handler.add_id(run_loop.AddHandler( | |
| 245 &odd_handler, test_pipe3.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, | |
| 246 MOJO_DEADLINE_INDEFINITE)); | |
| 247 } | |
| 248 EXPECT_EQ(1, odd_handler.error_count()); | |
| 249 EXPECT_EQ(1, even_handler.error_count()); | |
| 250 EXPECT_EQ(MOJO_RESULT_ABORTED, odd_handler.last_error_result()); | |
| 251 EXPECT_EQ(MOJO_RESULT_ABORTED, even_handler.last_error_result()); | |
| 252 } | |
| 253 | |
| 254 class AddHandlerOnErrorHandler : public TestRunLoopHandler { | |
| 255 public: | |
| 256 AddHandlerOnErrorHandler() {} | |
| 257 ~AddHandlerOnErrorHandler() override {} | |
| 258 | |
| 259 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 260 void set_handle(Handle handle) { handle_ = handle; } | |
| 261 | |
| 262 // RunLoopHandler: | |
| 263 void OnHandleError(Id id, MojoResult result) override { | |
| 264 EXPECT_EQ(MOJO_RESULT_ABORTED, result); | |
| 265 | |
| 266 TestRunLoopHandler::OnHandleError(id, result); | |
| 267 | |
| 268 if (!on_handle_error_was_called_) { | |
| 269 on_handle_error_was_called_ = true; | |
| 270 auto id = run_loop_->AddHandler( | |
| 271 this, handle_, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); | |
| 272 set_expected_handler_id(id); | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 private: | |
| 277 RunLoop* run_loop_ = nullptr; | |
| 278 bool on_handle_error_was_called_ = false; | |
| 279 Handle handle_; | |
| 280 | |
| 281 MOJO_DISALLOW_COPY_AND_ASSIGN(AddHandlerOnErrorHandler); | |
| 282 }; | |
| 283 | |
| 284 TEST(RunLoopTest, AddHandlerOnError) { | |
| 285 AddHandlerOnErrorHandler handler; | |
| 286 MessagePipe test_pipe; | |
| 287 { | |
| 288 RunLoop run_loop; | |
| 289 handler.set_run_loop(&run_loop); | |
| 290 handler.set_handle(test_pipe.handle0.get()); | |
| 291 auto id = run_loop.AddHandler(&handler, test_pipe.handle0.get(), | |
| 292 MOJO_HANDLE_SIGNAL_READABLE, | |
| 293 MOJO_DEADLINE_INDEFINITE); | |
| 294 handler.set_expected_handler_id(id); | |
| 295 } | |
| 296 EXPECT_EQ(2, handler.error_count()); | |
| 297 } | |
| 298 | |
| 299 TEST(RunLoopTest, Current) { | |
| 300 EXPECT_TRUE(RunLoop::current() == nullptr); | |
| 301 { | |
| 302 RunLoop run_loop; | |
| 303 EXPECT_EQ(&run_loop, RunLoop::current()); | |
| 304 } | |
| 305 EXPECT_TRUE(RunLoop::current() == nullptr); | |
| 306 } | |
| 307 | |
| 308 class NestingRunLoopHandler : public TestRunLoopHandler { | |
| 309 public: | |
| 310 static constexpr size_t kDepthLimit = 10; | |
| 311 static constexpr char kSignalMagic = 'X'; | |
| 312 | |
| 313 NestingRunLoopHandler() {} | |
| 314 ~NestingRunLoopHandler() override {} | |
| 315 | |
| 316 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 317 void set_pipe(MessagePipe* pipe) { pipe_ = pipe; } | |
| 318 bool reached_depth_limit() const { return reached_depth_limit_; } | |
| 319 | |
| 320 // RunLoopHandler: | |
| 321 void OnHandleReady(Id id) override { | |
| 322 TestRunLoopHandler::OnHandleReady(id); | |
| 323 | |
| 324 ReadSignal(); | |
| 325 size_t current_depth = ++depth_; | |
| 326 if (current_depth < kDepthLimit) { | |
| 327 AddHandlerAndWriteSignal(); | |
| 328 run_loop_->Run(); | |
| 329 // The innermost loop stops running due to Quit() being called; the outer | |
| 330 // loops stop running due to having no more handlers. No errors/timeouts | |
| 331 // should ever occur. | |
| 332 EXPECT_EQ(error_count(), 0); | |
| 333 } else { | |
| 334 EXPECT_EQ(current_depth, kDepthLimit); | |
| 335 reached_depth_limit_ = true; | |
| 336 run_loop_->Quit(); | |
| 337 } | |
| 338 --depth_; | |
| 339 } | |
| 340 | |
| 341 void AddHandlerAndWriteSignal() { | |
| 342 run_loop_->AddHandler(this, pipe_->handle0.get(), | |
| 343 MOJO_HANDLE_SIGNAL_READABLE, | |
| 344 static_cast<MojoDeadline>(10000)); | |
| 345 MojoResult write_result = | |
| 346 WriteMessageRaw(pipe_->handle1.get(), &kSignalMagic, 1, nullptr, 0, | |
| 347 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
| 348 EXPECT_EQ(write_result, MOJO_RESULT_OK); | |
| 349 } | |
| 350 | |
| 351 void ReadSignal() { | |
| 352 char read_byte = 0; | |
| 353 uint32_t bytes_read = 1; | |
| 354 uint32_t handles_read = 0; | |
| 355 MojoResult read_result = | |
| 356 ReadMessageRaw(pipe_->handle0.get(), &read_byte, &bytes_read, nullptr, | |
| 357 &handles_read, MOJO_READ_MESSAGE_FLAG_NONE); | |
| 358 EXPECT_EQ(read_result, MOJO_RESULT_OK); | |
| 359 EXPECT_EQ(read_byte, kSignalMagic); | |
| 360 } | |
| 361 | |
| 362 private: | |
| 363 RunLoop* run_loop_ = nullptr; | |
| 364 MessagePipe* pipe_ = nullptr; | |
| 365 size_t depth_ = 0u; | |
| 366 bool reached_depth_limit_ = false; | |
| 367 | |
| 368 MOJO_DISALLOW_COPY_AND_ASSIGN(NestingRunLoopHandler); | |
| 369 }; | |
| 370 | |
| 371 // static | |
| 372 const size_t NestingRunLoopHandler::kDepthLimit; | |
| 373 | |
| 374 // static | |
| 375 const char NestingRunLoopHandler::kSignalMagic; | |
| 376 | |
| 377 TEST(RunLoopTest, NestedRun) { | |
| 378 NestingRunLoopHandler handler; | |
| 379 MessagePipe test_pipe; | |
| 380 RunLoop run_loop; | |
| 381 handler.set_run_loop(&run_loop); | |
| 382 handler.set_pipe(&test_pipe); | |
| 383 handler.AddHandlerAndWriteSignal(); | |
| 384 run_loop.Run(); | |
| 385 | |
| 386 EXPECT_TRUE(handler.reached_depth_limit()); | |
| 387 // See the comment in NestingRunLoopHandler::OnHandleReady() above. | |
| 388 EXPECT_EQ(handler.error_count(), 0); | |
| 389 } | |
| 390 | |
| 391 struct Task { | |
| 392 Task(int num, std::vector<int>* sequence) : num(num), sequence(sequence) {} | |
| 393 | |
| 394 void Run() const { sequence->push_back(num); } | |
| 395 | |
| 396 int num; | |
| 397 std::vector<int>* sequence; | |
| 398 }; | |
| 399 | |
| 400 TEST(RunLoopTest, DelayedTaskOrder) { | |
| 401 std::vector<int> sequence; | |
| 402 RunLoop run_loop; | |
| 403 run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0); | |
| 404 run_loop.PostDelayedTask(Closure(Task(2, &sequence)), 0); | |
| 405 run_loop.PostDelayedTask(Closure(Task(3, &sequence)), 0); | |
| 406 run_loop.RunUntilIdle(); | |
| 407 | |
| 408 ASSERT_EQ(3u, sequence.size()); | |
| 409 EXPECT_EQ(1, sequence[0]); | |
| 410 EXPECT_EQ(2, sequence[1]); | |
| 411 EXPECT_EQ(3, sequence[2]); | |
| 412 } | |
| 413 | |
| 414 struct QuittingTask { | |
| 415 explicit QuittingTask(RunLoop* run_loop) : run_loop(run_loop) {} | |
| 416 | |
| 417 void Run() const { run_loop->Quit(); } | |
| 418 | |
| 419 RunLoop* run_loop; | |
| 420 }; | |
| 421 | |
| 422 TEST(RunLoopTest, QuitFromDelayedTask) { | |
| 423 TestRunLoopHandler handler; | |
| 424 MessagePipe test_pipe; | |
| 425 RunLoop run_loop; | |
| 426 run_loop.AddHandler(&handler, | |
| 427 test_pipe.handle0.get(), | |
| 428 MOJO_HANDLE_SIGNAL_READABLE, | |
| 429 MOJO_DEADLINE_INDEFINITE); | |
| 430 run_loop.PostDelayedTask(Closure(QuittingTask(&run_loop)), 0); | |
| 431 run_loop.Run(); | |
| 432 } | |
| 433 | |
| 434 } // namespace | |
| 435 } // namespace mojo | |
| OLD | NEW |