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