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