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 |