Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: mojo/edk/system/watch_unittest.cc

Issue 2725133002: Mojo: Armed Watchers (Closed)
Patch Set: . Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/edk/system/watch.cc ('k') | mojo/edk/system/watcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « mojo/edk/system/watch.cc ('k') | mojo/edk/system/watcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698