OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 <functional> | |
6 | |
7 #include "base/macros.h" | |
8 #include "base/memory/ref_counted.h" | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/run_loop.h" | |
11 #include "base/single_thread_task_runner.h" | |
12 #include "base/threading/thread_task_runner_handle.h" | |
13 #include "mojo/edk/system/request_context.h" | |
14 #include "mojo/edk/test/mojo_test_base.h" | |
15 #include "mojo/public/c/system/functions.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 namespace mojo { | |
19 namespace edk { | |
20 namespace { | |
21 | |
22 void IgnoreResult(uintptr_t context, | |
23 MojoResult result, | |
24 MojoHandleSignalsState signals, | |
25 MojoWatchNotificationFlags flags) { | |
26 } | |
27 | |
28 // A test helper class for watching a handle. The WatchHelper instance is used | |
29 // as a watch context for a single watch callback. | |
30 class WatchHelper { | |
31 public: | |
32 using Callback = | |
33 std::function<void(MojoResult result, MojoHandleSignalsState state)>; | |
34 | |
35 WatchHelper() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} | |
36 ~WatchHelper() { | |
37 CHECK(!watching_); | |
38 } | |
39 | |
40 void Watch(MojoHandle handle, | |
41 MojoHandleSignals signals, | |
42 const Callback& callback) { | |
43 CHECK(!watching_); | |
44 | |
45 handle_ = handle; | |
46 callback_ = callback; | |
47 watching_ = true; | |
48 CHECK_EQ(MOJO_RESULT_OK, MojoWatch(handle_, signals, &WatchHelper::OnNotify, | |
49 reinterpret_cast<uintptr_t>(this))); | |
50 } | |
51 | |
52 bool is_watching() const { return watching_; } | |
53 | |
54 void Cancel() { | |
55 CHECK_EQ(MOJO_RESULT_OK, | |
56 MojoCancelWatch(handle_, reinterpret_cast<uintptr_t>(this))); | |
57 CHECK(watching_); | |
58 watching_ = false; | |
59 } | |
60 | |
61 private: | |
62 static void OnNotify(uintptr_t context, | |
63 MojoResult result, | |
64 MojoHandleSignalsState state, | |
65 MojoWatchNotificationFlags flags) { | |
66 WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); | |
67 watcher->task_runner_->PostTask( | |
68 FROM_HERE, | |
69 base::Bind(&NotifyOnMainThread, context, result, state, flags)); | |
70 } | |
71 | |
72 static void NotifyOnMainThread(uintptr_t context, | |
73 MojoResult result, | |
74 MojoHandleSignalsState state, | |
75 MojoWatchNotificationFlags flags) { | |
76 WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); | |
77 CHECK(watcher->watching_); | |
78 if (result == MOJO_RESULT_CANCELLED) | |
79 watcher->watching_ = false; | |
80 watcher->callback_(result, state); | |
81 } | |
82 | |
83 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
84 bool watching_ = false; | |
85 MojoHandle handle_; | |
86 Callback callback_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(WatchHelper); | |
89 }; | |
90 | |
91 class WatchTest : public test::MojoTestBase { | |
92 public: | |
93 WatchTest() {} | |
94 ~WatchTest() override {} | |
95 | |
96 protected: | |
97 | |
98 private: | |
99 base::MessageLoop message_loop_; | |
100 | |
101 DISALLOW_COPY_AND_ASSIGN(WatchTest); | |
102 }; | |
103 | |
104 TEST_F(WatchTest, NotifyBasic) { | |
105 MojoHandle a, b; | |
106 CreateMessagePipe(&a, &b); | |
107 | |
108 base::RunLoop loop; | |
109 WatchHelper b_watcher; | |
110 b_watcher.Watch( | |
111 b, MOJO_HANDLE_SIGNAL_READABLE, | |
112 [&] (MojoResult result, MojoHandleSignalsState state) { | |
113 EXPECT_EQ(MOJO_RESULT_OK, result); | |
114 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
115 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
116 EXPECT_TRUE(b_watcher.is_watching()); | |
117 loop.Quit(); | |
118 }); | |
119 | |
120 WriteMessage(a, "Hello!"); | |
121 loop.Run(); | |
122 | |
123 EXPECT_TRUE(b_watcher.is_watching()); | |
124 b_watcher.Cancel(); | |
125 | |
126 CloseHandle(a); | |
127 CloseHandle(b); | |
128 } | |
129 | |
130 TEST_F(WatchTest, NotifyUnsatisfiable) { | |
131 MojoHandle a, b; | |
132 CreateMessagePipe(&a, &b); | |
133 | |
134 base::RunLoop loop; | |
135 WatchHelper b_watcher; | |
136 b_watcher.Watch( | |
137 b, MOJO_HANDLE_SIGNAL_READABLE, | |
138 [&] (MojoResult result, MojoHandleSignalsState state) { | |
139 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); | |
140 EXPECT_EQ(0u, | |
141 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
142 EXPECT_EQ(0u, | |
143 state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
144 EXPECT_TRUE(b_watcher.is_watching()); | |
145 loop.Quit(); | |
146 }); | |
147 | |
148 CloseHandle(a); | |
149 loop.Run(); | |
150 | |
151 b_watcher.Cancel(); | |
152 | |
153 CloseHandle(b); | |
154 } | |
155 | |
156 TEST_F(WatchTest, NotifyCancellation) { | |
157 MojoHandle a, b; | |
158 CreateMessagePipe(&a, &b); | |
159 | |
160 base::RunLoop loop; | |
161 WatchHelper b_watcher; | |
162 b_watcher.Watch( | |
163 b, MOJO_HANDLE_SIGNAL_READABLE, | |
164 [&] (MojoResult result, MojoHandleSignalsState state) { | |
165 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); | |
166 EXPECT_EQ(0u, state.satisfied_signals); | |
167 EXPECT_EQ(0u, state.satisfiable_signals); | |
168 EXPECT_FALSE(b_watcher.is_watching()); | |
169 loop.Quit(); | |
170 }); | |
171 | |
172 CloseHandle(b); | |
173 loop.Run(); | |
174 | |
175 CloseHandle(a); | |
176 } | |
177 | |
178 TEST_F(WatchTest, InvalidArguemnts) { | |
179 MojoHandle a, b; | |
180 CreateMessagePipe(&a, &b); | |
181 | |
182 uintptr_t context = reinterpret_cast<uintptr_t>(this); | |
183 EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, | |
184 &IgnoreResult, context)); | |
185 | |
186 // Can't cancel a watch that doesn't exist. | |
187 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(a, ~context)); | |
188 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(b, context)); | |
189 | |
190 CloseHandle(a); | |
191 CloseHandle(b); | |
192 | |
193 // Can't watch a handle that doesn't exist. | |
194 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
195 MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); | |
196 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
197 MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); | |
198 } | |
199 | |
200 TEST_F(WatchTest, NoDuplicateContext) { | |
201 MojoHandle a, b; | |
202 CreateMessagePipe(&a, &b); | |
203 | |
204 // Try to add the same watch twice; should fail. | |
205 uintptr_t context = reinterpret_cast<uintptr_t>(this); | |
206 EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, | |
207 &IgnoreResult, context)); | |
208 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
209 MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); | |
210 | |
211 // Cancel and add it again; should be OK. | |
212 EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(a, context)); | |
213 EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, | |
214 &IgnoreResult, context)); | |
215 | |
216 CloseHandle(a); | |
217 CloseHandle(b); | |
218 } | |
219 | |
220 TEST_F(WatchTest, MultipleWatches) { | |
221 MojoHandle a, b; | |
222 CreateMessagePipe(&a, &b); | |
223 | |
224 // Add multiple watchers to |b| and see that they are both notified by a | |
225 // single write to |a|. | |
226 base::RunLoop loop; | |
227 int expected_notifications = 2; | |
228 auto on_readable = [&] (MojoResult result, MojoHandleSignalsState state) { | |
229 EXPECT_EQ(MOJO_RESULT_OK, result); | |
230 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
231 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
232 EXPECT_GT(expected_notifications, 0); | |
233 if (--expected_notifications == 0) | |
234 loop.Quit(); | |
235 }; | |
236 WatchHelper watcher1; | |
237 WatchHelper watcher2; | |
238 watcher1.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); | |
239 watcher2.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); | |
240 | |
241 WriteMessage(a, "Ping!"); | |
242 loop.Run(); | |
243 | |
244 watcher1.Cancel(); | |
245 watcher2.Cancel(); | |
246 | |
247 CloseHandle(a); | |
248 CloseHandle(b); | |
249 } | |
250 | |
251 TEST_F(WatchTest, WatchWhileSatisfied) { | |
252 MojoHandle a, b; | |
253 CreateMessagePipe(&a, &b); | |
254 | |
255 // Write to |a| and then start watching |b|. The callback should be invoked | |
256 // synchronously. | |
257 WriteMessage(a, "hey"); | |
258 bool signaled = false; | |
259 WatchHelper b_watcher; | |
260 base::RunLoop loop; | |
261 b_watcher.Watch( | |
262 b, MOJO_HANDLE_SIGNAL_READABLE, | |
263 [&] (MojoResult result, MojoHandleSignalsState state) { | |
264 EXPECT_EQ(MOJO_RESULT_OK, result); | |
265 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
266 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
267 signaled = true; | |
268 loop.Quit(); | |
269 }); | |
270 loop.Run(); | |
271 EXPECT_TRUE(signaled); | |
272 b_watcher.Cancel(); | |
273 | |
274 CloseHandle(a); | |
275 CloseHandle(b); | |
276 } | |
277 | |
278 TEST_F(WatchTest, WatchWhileUnsatisfiable) { | |
279 MojoHandle a, b; | |
280 CreateMessagePipe(&a, &b); | |
281 | |
282 // Close |a| and then try to watch |b|. MojoWatch() should fail. | |
283 CloseHandle(a); | |
284 uintptr_t context = reinterpret_cast<uintptr_t>(this); | |
285 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | |
286 MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); | |
287 | |
288 CloseHandle(b); | |
289 } | |
290 | |
291 TEST_F(WatchTest, RespondFromCallback) { | |
292 MojoHandle a, b; | |
293 CreateMessagePipe(&a, &b); | |
294 | |
295 // Watch |a| and |b|. Write to |a|, then write to |b| from within the callback | |
296 // which notifies it of the available message. | |
297 const std::string kTestMessage = "hello worlds."; | |
298 base::RunLoop loop; | |
299 WatchHelper b_watcher; | |
300 b_watcher.Watch( | |
301 b, MOJO_HANDLE_SIGNAL_READABLE, | |
302 [&] (MojoResult result, MojoHandleSignalsState state) { | |
303 EXPECT_EQ(MOJO_RESULT_OK, result); | |
304 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
305 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
306 EXPECT_TRUE(b_watcher.is_watching()); | |
307 | |
308 // Echo a's message back to it. | |
309 WriteMessage(b, ReadMessage(b)); | |
310 }); | |
311 | |
312 WatchHelper a_watcher; | |
313 a_watcher.Watch( | |
314 a, MOJO_HANDLE_SIGNAL_READABLE, | |
315 [&] (MojoResult result, MojoHandleSignalsState state) { | |
316 EXPECT_EQ(MOJO_RESULT_OK, result); | |
317 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
318 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
319 EXPECT_TRUE(a_watcher.is_watching()); | |
320 | |
321 // Expect to receive back the message that was originally sent to |b|. | |
322 EXPECT_EQ(kTestMessage, ReadMessage(a)); | |
323 | |
324 loop.Quit(); | |
325 }); | |
326 | |
327 WriteMessage(a, kTestMessage); | |
328 loop.Run(); | |
329 | |
330 a_watcher.Cancel(); | |
331 b_watcher.Cancel(); | |
332 | |
333 CloseHandle(a); | |
334 CloseHandle(b); | |
335 } | |
336 | |
337 TEST_F(WatchTest, WatchDataPipeConsumer) { | |
338 MojoHandle a, b; | |
339 CreateDataPipe(&a, &b, 64); | |
340 | |
341 base::RunLoop loop; | |
342 WatchHelper b_watcher; | |
343 b_watcher.Watch( | |
344 b, MOJO_HANDLE_SIGNAL_READABLE, | |
345 [&] (MojoResult result, MojoHandleSignalsState state) { | |
346 EXPECT_EQ(MOJO_RESULT_OK, result); | |
347 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
348 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
349 EXPECT_TRUE(b_watcher.is_watching()); | |
350 loop.Quit(); | |
351 }); | |
352 | |
353 WriteData(a, "Hello!"); | |
354 loop.Run(); | |
355 | |
356 EXPECT_TRUE(b_watcher.is_watching()); | |
357 b_watcher.Cancel(); | |
358 | |
359 CloseHandle(a); | |
360 CloseHandle(b); | |
361 } | |
362 | |
363 TEST_F(WatchTest, WatchDataPipeProducer) { | |
364 MojoHandle a, b; | |
365 CreateDataPipe(&a, &b, 8); | |
366 | |
367 // Fill the pipe to capacity so writes will block. | |
368 WriteData(a, "xxxxxxxx"); | |
369 | |
370 base::RunLoop loop; | |
371 WatchHelper a_watcher; | |
372 a_watcher.Watch( | |
373 a, MOJO_HANDLE_SIGNAL_WRITABLE, | |
374 [&] (MojoResult result, MojoHandleSignalsState state) { | |
375 EXPECT_EQ(MOJO_RESULT_OK, result); | |
376 EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, | |
377 state.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); | |
378 EXPECT_TRUE(a_watcher.is_watching()); | |
379 loop.Quit(); | |
380 }); | |
381 | |
382 EXPECT_EQ("xxxxxxxx", ReadData(b, 8)); | |
383 loop.Run(); | |
384 | |
385 EXPECT_TRUE(a_watcher.is_watching()); | |
386 a_watcher.Cancel(); | |
387 | |
388 CloseHandle(a); | |
389 CloseHandle(b); | |
390 } | |
391 | |
392 TEST_F(WatchTest, WakeUpSelfWithinWatchCallback) { | |
393 MojoHandle a, b; | |
394 CreateMessagePipe(&a, &b); | |
395 | |
396 int expected_notifications = 2; | |
397 base::RunLoop loop; | |
398 WatchHelper b_watcher; | |
399 b_watcher.Watch( | |
400 b, MOJO_HANDLE_SIGNAL_READABLE, | |
401 [&] (MojoResult result, MojoHandleSignalsState state) { | |
402 EXPECT_EQ(MOJO_RESULT_OK, result); | |
403 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
404 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
405 EXPECT_TRUE(b_watcher.is_watching()); | |
406 if (--expected_notifications == 0) { | |
407 loop.Quit(); | |
408 } else { | |
409 // Trigger b's watch again from within this callback. This should be | |
410 // safe to do. | |
411 WriteMessage(a, "hey"); | |
412 } | |
413 }); | |
414 | |
415 WriteMessage(a, "hey hey hey"); | |
416 loop.Run(); | |
417 | |
418 b_watcher.Cancel(); | |
419 | |
420 CloseHandle(a); | |
421 CloseHandle(b); | |
422 } | |
423 | |
424 TEST_F(WatchTest, NestedCancellation) { | |
425 // Verifies that cancellations in nested system request contexts preempt | |
426 // other notifications for the same watcher. This tests against the condition | |
427 // hit by http://crbug.com/622298. | |
428 | |
429 MojoHandle a, b, c, d; | |
430 CreateMessagePipe(&a, &b); | |
431 CreateMessagePipe(&c, &d); | |
432 | |
433 base::RunLoop loop; | |
434 bool a_watcher_run = false; | |
435 WatchHelper a_watcher; | |
436 a_watcher.Watch( | |
437 a, MOJO_HANDLE_SIGNAL_READABLE, | |
438 [&](MojoResult result, MojoHandleSignalsState state) { | |
439 a_watcher_run = true; | |
440 }); | |
441 | |
442 WatchHelper c_watcher; | |
443 c_watcher.Watch( | |
444 c, MOJO_HANDLE_SIGNAL_READABLE, | |
445 [&](MojoResult result, MojoHandleSignalsState state) { | |
446 // This will trigger a notification on |a_watcher| above to be executed | |
447 // once this handler finishes running... | |
448 CloseHandle(b); | |
449 | |
450 // ...but this should prevent that notification from dispatching because | |
451 // |a_watcher| is now cancelled. | |
452 a_watcher.Cancel(); | |
453 | |
454 loop.Quit(); | |
455 }); | |
456 | |
457 { | |
458 // Force "system" notifications for the synchronous behavior required to | |
459 // test this case. | |
460 mojo::edk::RequestContext request_context( | |
461 mojo::edk::RequestContext::Source::SYSTEM); | |
462 | |
463 // Trigger the |c_watcher| callback above. | |
464 CloseHandle(d); | |
465 } | |
466 | |
467 loop.Run(); | |
468 | |
469 EXPECT_FALSE(a_watcher.is_watching()); | |
470 EXPECT_FALSE(a_watcher_run); | |
471 | |
472 c_watcher.Cancel(); | |
473 | |
474 CloseHandle(a); | |
475 CloseHandle(c); | |
476 } | |
477 | |
478 } // namespace | |
479 } // namespace edk | |
480 } // namespace mojo | |
OLD | NEW |