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.
5 #include "mojo/public/cpp/utility/run_loop.h"
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"
17 class TestRunLoopHandler : public RunLoopHandler {
22 last_error_result_(MOJO_RESULT_OK) {
24 ~TestRunLoopHandler() override {}
26 void clear_ready_count() { ready_count_ = 0; }
27 int ready_count() const { return ready_count_; }
29 void clear_error_count() { error_count_ = 0; }
30 int error_count() const { return error_count_; }
32 MojoResult last_error_result() const { return last_error_result_; }
35 void OnHandleReady(const Handle& handle) override { ready_count_++; }
36 void OnHandleError(const Handle& handle, MojoResult result) override {
38 last_error_result_ = result;
44 MojoResult last_error_result_;
46 MOJO_DISALLOW_COPY_AND_ASSIGN(TestRunLoopHandler);
49 class RunLoopTest : public testing::Test {
53 void SetUp() override {
57 void TearDown() override {
63 MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
66 // Trivial test to verify Run() with no added handles returns.
67 TEST_F(RunLoopTest, ExitsWithNoHandles) {
72 class RemoveOnReadyRunLoopHandler : public TestRunLoopHandler {
74 RemoveOnReadyRunLoopHandler() : run_loop_(NULL) {
76 ~RemoveOnReadyRunLoopHandler() override {}
78 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
81 void OnHandleReady(const Handle& handle) override {
82 run_loop_->RemoveHandler(handle);
83 TestRunLoopHandler::OnHandleReady(handle);
89 MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveOnReadyRunLoopHandler);
92 // Verifies RunLoop quits when no more handles (handle is removed when ready).
93 TEST_F(RunLoopTest, HandleReady) {
94 RemoveOnReadyRunLoopHandler handler;
95 MessagePipe test_pipe;
96 EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
99 handler.set_run_loop(&run_loop);
100 run_loop.AddHandler(&handler, test_pipe.handle0.get(),
101 MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
103 EXPECT_EQ(1, handler.ready_count());
104 EXPECT_EQ(0, handler.error_count());
105 EXPECT_FALSE(run_loop.HasHandler(test_pipe.handle0.get()));
108 class QuitOnReadyRunLoopHandler : public TestRunLoopHandler {
110 QuitOnReadyRunLoopHandler() : run_loop_(NULL) {
112 ~QuitOnReadyRunLoopHandler() override {}
114 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
117 void OnHandleReady(const Handle& handle) override {
119 TestRunLoopHandler::OnHandleReady(handle);
125 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnReadyRunLoopHandler);
128 // Verifies Quit() from OnHandleReady() quits the loop.
129 TEST_F(RunLoopTest, QuitFromReady) {
130 QuitOnReadyRunLoopHandler handler;
131 MessagePipe test_pipe;
132 EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
135 handler.set_run_loop(&run_loop);
136 run_loop.AddHandler(&handler, test_pipe.handle0.get(),
137 MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
139 EXPECT_EQ(1, handler.ready_count());
140 EXPECT_EQ(0, handler.error_count());
141 EXPECT_TRUE(run_loop.HasHandler(test_pipe.handle0.get()));
144 class QuitOnErrorRunLoopHandler : public TestRunLoopHandler {
146 QuitOnErrorRunLoopHandler() : run_loop_(NULL) {
148 ~QuitOnErrorRunLoopHandler() override {}
150 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
153 void OnHandleError(const Handle& handle, MojoResult result) override {
155 TestRunLoopHandler::OnHandleError(handle, result);
161 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnErrorRunLoopHandler);
164 // Verifies Quit() when the deadline is reached works.
165 TEST_F(RunLoopTest, QuitWhenDeadlineExpired) {
166 QuitOnErrorRunLoopHandler handler;
167 MessagePipe test_pipe;
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));
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()));
180 // Test that handlers are notified of loop destruction.
181 TEST_F(RunLoopTest, Destruction) {
182 TestRunLoopHandler handler;
183 MessagePipe test_pipe;
186 run_loop.AddHandler(&handler,
187 test_pipe.handle0.get(),
188 MOJO_HANDLE_SIGNAL_READABLE,
189 MOJO_DEADLINE_INDEFINITE);
191 EXPECT_EQ(1, handler.error_count());
192 EXPECT_EQ(MOJO_RESULT_ABORTED, handler.last_error_result());
195 class RemoveManyRunLoopHandler : public TestRunLoopHandler {
197 RemoveManyRunLoopHandler() : run_loop_(NULL) {
199 ~RemoveManyRunLoopHandler() override {}
201 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
202 void add_handle(const Handle& handle) { handles_.push_back(handle); }
205 void OnHandleError(const Handle& handle, MojoResult result) override {
206 for (size_t i = 0; i < handles_.size(); i++)
207 run_loop_->RemoveHandler(handles_[i]);
208 TestRunLoopHandler::OnHandleError(handle, result);
212 std::vector<Handle> handles_;
215 MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveManyRunLoopHandler);
218 // Test that handlers are notified of loop destruction.
219 TEST_F(RunLoopTest, MultipleHandleDestruction) {
220 RemoveManyRunLoopHandler odd_handler;
221 TestRunLoopHandler even_handler;
222 MessagePipe test_pipe1, test_pipe2, test_pipe3;
225 odd_handler.set_run_loop(&run_loop);
226 odd_handler.add_handle(test_pipe1.handle0.get());
227 odd_handler.add_handle(test_pipe3.handle0.get());
228 run_loop.AddHandler(&odd_handler,
229 test_pipe1.handle0.get(),
230 MOJO_HANDLE_SIGNAL_READABLE,
231 MOJO_DEADLINE_INDEFINITE);
232 run_loop.AddHandler(&even_handler,
233 test_pipe2.handle0.get(),
234 MOJO_HANDLE_SIGNAL_READABLE,
235 MOJO_DEADLINE_INDEFINITE);
236 run_loop.AddHandler(&odd_handler,
237 test_pipe3.handle0.get(),
238 MOJO_HANDLE_SIGNAL_READABLE,
239 MOJO_DEADLINE_INDEFINITE);
241 EXPECT_EQ(1, odd_handler.error_count());
242 EXPECT_EQ(1, even_handler.error_count());
243 EXPECT_EQ(MOJO_RESULT_ABORTED, odd_handler.last_error_result());
244 EXPECT_EQ(MOJO_RESULT_ABORTED, even_handler.last_error_result());
247 class AddHandlerOnErrorHandler : public TestRunLoopHandler {
249 AddHandlerOnErrorHandler() : run_loop_(NULL) {
251 ~AddHandlerOnErrorHandler() override {}
253 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
256 void OnHandleError(const Handle& handle, MojoResult result) override {
257 run_loop_->AddHandler(this, handle,
258 MOJO_HANDLE_SIGNAL_READABLE,
259 MOJO_DEADLINE_INDEFINITE);
260 TestRunLoopHandler::OnHandleError(handle, result);
266 MOJO_DISALLOW_COPY_AND_ASSIGN(AddHandlerOnErrorHandler);
269 TEST_F(RunLoopTest, AddHandlerOnError) {
270 AddHandlerOnErrorHandler handler;
271 MessagePipe test_pipe;
274 handler.set_run_loop(&run_loop);
275 run_loop.AddHandler(&handler,
276 test_pipe.handle0.get(),
277 MOJO_HANDLE_SIGNAL_READABLE,
278 MOJO_DEADLINE_INDEFINITE);
280 EXPECT_EQ(1, handler.error_count());
281 EXPECT_EQ(MOJO_RESULT_ABORTED, handler.last_error_result());
284 TEST_F(RunLoopTest, Current) {
285 EXPECT_TRUE(RunLoop::current() == NULL);
288 EXPECT_EQ(&run_loop, RunLoop::current());
290 EXPECT_TRUE(RunLoop::current() == NULL);
293 class NestingRunLoopHandler : public TestRunLoopHandler {
295 static const size_t kDepthLimit;
296 static const char kSignalMagic;
298 NestingRunLoopHandler()
302 reached_depth_limit_(false) {}
304 ~NestingRunLoopHandler() override {}
306 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
307 void set_pipe(MessagePipe* pipe) { pipe_ = pipe; }
308 bool reached_depth_limit() const { return reached_depth_limit_; }
311 void OnHandleReady(const Handle& handle) override {
312 TestRunLoopHandler::OnHandleReady(handle);
313 EXPECT_EQ(handle.value(), pipe_->handle0.get().value());
316 size_t current_depth = ++depth_;
317 if (current_depth < kDepthLimit) {
320 if (current_depth == kDepthLimit - 1) {
321 // The topmost loop Quit()-ed, so its parent takes back the
322 // control without exeeding deadline.
323 EXPECT_EQ(error_count(), 0);
325 EXPECT_EQ(error_count(), 1);
329 EXPECT_EQ(current_depth, kDepthLimit);
330 reached_depth_limit_ = true;
337 char write_byte = kSignalMagic;
338 MojoResult write_result = WriteMessageRaw(
339 pipe_->handle1.get(),
340 &write_byte, 1, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
341 EXPECT_EQ(write_result, MOJO_RESULT_OK);
346 uint32_t bytes_read = 1;
347 uint32_t handles_read = 0;
348 MojoResult read_result = ReadMessageRaw(
349 pipe_->handle0.get(),
350 &read_byte, &bytes_read, NULL, &handles_read,
351 MOJO_READ_MESSAGE_FLAG_NONE);
352 EXPECT_EQ(read_result, MOJO_RESULT_OK);
353 EXPECT_EQ(read_byte, kSignalMagic);
360 bool reached_depth_limit_;
362 MOJO_DISALLOW_COPY_AND_ASSIGN(NestingRunLoopHandler);
365 const size_t NestingRunLoopHandler::kDepthLimit = 10;
366 const char NestingRunLoopHandler::kSignalMagic = 'X';
368 TEST_F(RunLoopTest, NestedRun) {
369 NestingRunLoopHandler handler;
370 MessagePipe test_pipe;
372 handler.set_run_loop(&run_loop);
373 handler.set_pipe(&test_pipe);
374 run_loop.AddHandler(&handler, test_pipe.handle0.get(),
375 MOJO_HANDLE_SIGNAL_READABLE,
376 static_cast<MojoDeadline>(10000));
377 handler.WriteSignal();
380 EXPECT_TRUE(handler.reached_depth_limit());
381 // Got MOJO_RESULT_DEADLINE_EXCEEDED once then removed from the
382 // RunLoop's handler list.
383 EXPECT_EQ(handler.error_count(), 1);
384 EXPECT_EQ(handler.last_error_result(), MOJO_RESULT_DEADLINE_EXCEEDED);
388 Task(int num, std::vector<int>* sequence) : num(num), sequence(sequence) {}
390 void Run() const { sequence->push_back(num); }
393 std::vector<int>* sequence;
396 TEST_F(RunLoopTest, DelayedTaskOrder) {
397 std::vector<int> sequence;
399 run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0);
400 run_loop.PostDelayedTask(Closure(Task(2, &sequence)), 0);
401 run_loop.PostDelayedTask(Closure(Task(3, &sequence)), 0);
402 run_loop.RunUntilIdle();
404 ASSERT_EQ(3u, sequence.size());
405 EXPECT_EQ(1, sequence[0]);
406 EXPECT_EQ(2, sequence[1]);
407 EXPECT_EQ(3, sequence[2]);
410 struct QuittingTask {
411 explicit QuittingTask(RunLoop* run_loop) : run_loop(run_loop) {}
413 void Run() const { run_loop->Quit(); }
418 TEST_F(RunLoopTest, QuitFromDelayedTask) {
419 TestRunLoopHandler handler;
420 MessagePipe test_pipe;
422 run_loop.AddHandler(&handler,
423 test_pipe.handle0.get(),
424 MOJO_HANDLE_SIGNAL_READABLE,
425 MOJO_DEADLINE_INDEFINITE);
426 run_loop.PostDelayedTask(Closure(QuittingTask(&run_loop)), 0);