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 virtual ~TestRunLoopHandler() {}
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 virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
38 virtual void OnHandleError(const Handle& handle, MojoResult result)
41 last_error_result_ = result;
47 MojoResult last_error_result_;
49 MOJO_DISALLOW_COPY_AND_ASSIGN(TestRunLoopHandler);
52 class RunLoopTest : public testing::Test {
56 virtual void SetUp() MOJO_OVERRIDE {
60 virtual void TearDown() MOJO_OVERRIDE {
66 MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
69 // Trivial test to verify Run() with no added handles returns.
70 TEST_F(RunLoopTest, ExitsWithNoHandles) {
75 class RemoveOnReadyRunLoopHandler : public TestRunLoopHandler {
77 RemoveOnReadyRunLoopHandler() : run_loop_(NULL) {
79 virtual ~RemoveOnReadyRunLoopHandler() {}
81 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
84 virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
85 run_loop_->RemoveHandler(handle);
86 TestRunLoopHandler::OnHandleReady(handle);
92 MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveOnReadyRunLoopHandler);
95 // Verifies RunLoop quits when no more handles (handle is removed when ready).
96 TEST_F(RunLoopTest, HandleReady) {
97 RemoveOnReadyRunLoopHandler handler;
98 MessagePipe test_pipe;
99 EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
102 handler.set_run_loop(&run_loop);
103 run_loop.AddHandler(&handler, test_pipe.handle0.get(),
104 MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
106 EXPECT_EQ(1, handler.ready_count());
107 EXPECT_EQ(0, handler.error_count());
108 EXPECT_FALSE(run_loop.HasHandler(test_pipe.handle0.get()));
111 class QuitOnReadyRunLoopHandler : public TestRunLoopHandler {
113 QuitOnReadyRunLoopHandler() : run_loop_(NULL) {
115 virtual ~QuitOnReadyRunLoopHandler() {}
117 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
120 virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
122 TestRunLoopHandler::OnHandleReady(handle);
128 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnReadyRunLoopHandler);
131 // Verifies Quit() from OnHandleReady() quits the loop.
132 TEST_F(RunLoopTest, QuitFromReady) {
133 QuitOnReadyRunLoopHandler handler;
134 MessagePipe test_pipe;
135 EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
138 handler.set_run_loop(&run_loop);
139 run_loop.AddHandler(&handler, test_pipe.handle0.get(),
140 MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
142 EXPECT_EQ(1, handler.ready_count());
143 EXPECT_EQ(0, handler.error_count());
144 EXPECT_TRUE(run_loop.HasHandler(test_pipe.handle0.get()));
147 class QuitOnErrorRunLoopHandler : public TestRunLoopHandler {
149 QuitOnErrorRunLoopHandler() : run_loop_(NULL) {
151 virtual ~QuitOnErrorRunLoopHandler() {}
153 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
156 virtual void OnHandleError(const Handle& handle, MojoResult result)
159 TestRunLoopHandler::OnHandleError(handle, result);
165 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnErrorRunLoopHandler);
168 // Verifies Quit() when the deadline is reached works.
169 TEST_F(RunLoopTest, QuitWhenDeadlineExpired) {
170 QuitOnErrorRunLoopHandler handler;
171 MessagePipe test_pipe;
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));
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()));
184 TEST_F(RunLoopTest, Current) {
185 EXPECT_TRUE(RunLoop::current() == NULL);
188 EXPECT_EQ(&run_loop, RunLoop::current());
190 EXPECT_TRUE(RunLoop::current() == NULL);
193 class NestingRunLoopHandler : public TestRunLoopHandler {
195 static const size_t kDepthLimit;
196 static const char kSignalMagic;
198 NestingRunLoopHandler()
202 reached_depth_limit_(false) {}
204 virtual ~NestingRunLoopHandler() {}
206 void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
207 void set_pipe(MessagePipe* pipe) { pipe_ = pipe; }
208 bool reached_depth_limit() const { return reached_depth_limit_; }
211 virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
212 TestRunLoopHandler::OnHandleReady(handle);
213 EXPECT_EQ(handle.value(), pipe_->handle0.get().value());
216 size_t current_depth = ++depth_;
217 if (current_depth < kDepthLimit) {
220 if (current_depth == kDepthLimit - 1) {
221 // The topmost loop Quit()-ed, so its parent takes back the
222 // control without exeeding deadline.
223 EXPECT_EQ(error_count(), 0);
225 EXPECT_EQ(error_count(), 1);
229 EXPECT_EQ(current_depth, kDepthLimit);
230 reached_depth_limit_ = true;
237 char write_byte = kSignalMagic;
238 MojoResult write_result = WriteMessageRaw(
239 pipe_->handle1.get(),
240 &write_byte, 1, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
241 EXPECT_EQ(write_result, MOJO_RESULT_OK);
246 uint32_t bytes_read = 1;
247 uint32_t handles_read = 0;
248 MojoResult read_result = ReadMessageRaw(
249 pipe_->handle0.get(),
250 &read_byte, &bytes_read, NULL, &handles_read,
251 MOJO_READ_MESSAGE_FLAG_NONE);
252 EXPECT_EQ(read_result, MOJO_RESULT_OK);
253 EXPECT_EQ(read_byte, kSignalMagic);
260 bool reached_depth_limit_;
262 MOJO_DISALLOW_COPY_AND_ASSIGN(NestingRunLoopHandler);
265 const size_t NestingRunLoopHandler::kDepthLimit = 10;
266 const char NestingRunLoopHandler::kSignalMagic = 'X';
268 TEST_F(RunLoopTest, NestedRun) {
269 NestingRunLoopHandler handler;
270 MessagePipe test_pipe;
272 handler.set_run_loop(&run_loop);
273 handler.set_pipe(&test_pipe);
274 run_loop.AddHandler(&handler, test_pipe.handle0.get(),
275 MOJO_HANDLE_SIGNAL_READABLE,
276 static_cast<MojoDeadline>(10000));
277 handler.WriteSignal();
280 EXPECT_TRUE(handler.reached_depth_limit());
281 // Got MOJO_RESULT_DEADLINE_EXCEEDED once then removed from the
282 // RunLoop's handler list.
283 EXPECT_EQ(handler.error_count(), 1);
284 EXPECT_EQ(handler.last_error_result(), MOJO_RESULT_DEADLINE_EXCEEDED);
288 Task(int num, std::vector<int>* sequence) : num(num), sequence(sequence) {}
290 void Run() const { sequence->push_back(num); }
293 std::vector<int>* sequence;
296 TEST_F(RunLoopTest, DelayedTaskOrder) {
297 std::vector<int> sequence;
299 run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0);
300 run_loop.PostDelayedTask(Closure(Task(2, &sequence)), 0);
301 run_loop.PostDelayedTask(Closure(Task(3, &sequence)), 0);
302 run_loop.RunUntilIdle();
304 ASSERT_EQ(3u, sequence.size());
305 EXPECT_EQ(1, sequence[0]);
306 EXPECT_EQ(2, sequence[1]);
307 EXPECT_EQ(3, sequence[2]);