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