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