• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "mojo/public/cpp/system/simple_watcher.h"
6 
7 #include <memory>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "mojo/public/c/system/types.h"
16 #include "mojo/public/cpp/system/data_pipe.h"
17 #include "mojo/public/cpp/system/message_pipe.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 
20 namespace mojo {
21 namespace {
22 
23 template <typename Handler>
RunResultHandler(Handler f,MojoResult result)24 void RunResultHandler(Handler f, MojoResult result) {
25   f(result);
26 }
27 
28 template <typename Handler>
OnReady(Handler f)29 SimpleWatcher::ReadyCallback OnReady(Handler f) {
30   return base::Bind(&RunResultHandler<Handler>, f);
31 }
32 
NotReached()33 SimpleWatcher::ReadyCallback NotReached() {
34   return OnReady([](MojoResult) { NOTREACHED(); });
35 }
36 
37 class SimpleWatcherTest : public testing::Test {
38  public:
SimpleWatcherTest()39   SimpleWatcherTest() {}
~SimpleWatcherTest()40   ~SimpleWatcherTest() override {}
41 
42  private:
43   base::MessageLoop message_loop_;
44 
45   DISALLOW_COPY_AND_ASSIGN(SimpleWatcherTest);
46 };
47 
TEST_F(SimpleWatcherTest,WatchBasic)48 TEST_F(SimpleWatcherTest, WatchBasic) {
49   ScopedMessagePipeHandle a, b;
50   CreateMessagePipe(nullptr, &a, &b);
51 
52   bool notified = false;
53   base::RunLoop run_loop;
54   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
55                           base::SequencedTaskRunnerHandle::Get());
56   EXPECT_EQ(MOJO_RESULT_OK,
57             b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
58                             OnReady([&](MojoResult result) {
59                               EXPECT_EQ(MOJO_RESULT_OK, result);
60                               notified = true;
61                               run_loop.Quit();
62                             })));
63   EXPECT_TRUE(b_watcher.IsWatching());
64 
65   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
66                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
67   run_loop.Run();
68   EXPECT_TRUE(notified);
69 
70   b_watcher.Cancel();
71 }
72 
TEST_F(SimpleWatcherTest,WatchUnsatisfiable)73 TEST_F(SimpleWatcherTest, WatchUnsatisfiable) {
74   ScopedMessagePipeHandle a, b;
75   CreateMessagePipe(nullptr, &a, &b);
76   a.reset();
77 
78   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL,
79                           base::SequencedTaskRunnerHandle::Get());
80   EXPECT_EQ(
81       MOJO_RESULT_OK,
82       b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached()));
83   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, b_watcher.Arm());
84 }
85 
TEST_F(SimpleWatcherTest,WatchFailedPreconditionNoSpam)86 TEST_F(SimpleWatcherTest, WatchFailedPreconditionNoSpam) {
87   DataPipe pipe;
88   bool had_failed_precondition = false;
89 
90   SimpleWatcher watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC);
91   MojoResult rc =
92       watcher.Watch(pipe.consumer_handle.get(), MOJO_HANDLE_SIGNAL_READABLE,
93                     OnReady([&](MojoResult result) {
94                       EXPECT_FALSE(had_failed_precondition);
95                       switch (result) {
96                         case MOJO_RESULT_OK:
97                           const void* begin;
98                           uint32_t num_bytes;
99                           pipe.consumer_handle->BeginReadData(
100                               &begin, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
101                           pipe.consumer_handle->EndReadData(num_bytes);
102                           break;
103                         case MOJO_RESULT_FAILED_PRECONDITION:
104                           had_failed_precondition = true;
105                           break;
106                       }
107                     }));
108   EXPECT_EQ(MOJO_RESULT_OK, rc);
109 
110   uint32_t size = 5;
111   EXPECT_EQ(MOJO_RESULT_OK, pipe.producer_handle->WriteData(
112                                 "hello", &size, MOJO_WRITE_DATA_FLAG_NONE));
113   base::RunLoop().RunUntilIdle();
114   pipe.producer_handle.reset();
115   base::RunLoop().RunUntilIdle();
116   EXPECT_TRUE(had_failed_precondition);
117 }
118 
TEST_F(SimpleWatcherTest,WatchInvalidHandle)119 TEST_F(SimpleWatcherTest, WatchInvalidHandle) {
120   ScopedMessagePipeHandle a, b;
121   CreateMessagePipe(nullptr, &a, &b);
122   a.reset();
123   b.reset();
124 
125   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
126                           base::SequencedTaskRunnerHandle::Get());
127   EXPECT_EQ(
128       MOJO_RESULT_INVALID_ARGUMENT,
129       b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached()));
130   EXPECT_FALSE(b_watcher.IsWatching());
131 }
132 
TEST_F(SimpleWatcherTest,Cancel)133 TEST_F(SimpleWatcherTest, Cancel) {
134   ScopedMessagePipeHandle a, b;
135   CreateMessagePipe(nullptr, &a, &b);
136 
137   base::RunLoop run_loop;
138   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
139                           base::SequencedTaskRunnerHandle::Get());
140   EXPECT_EQ(
141       MOJO_RESULT_OK,
142       b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached()));
143   EXPECT_TRUE(b_watcher.IsWatching());
144   b_watcher.Cancel();
145   EXPECT_FALSE(b_watcher.IsWatching());
146 
147   // This should never trigger the watcher.
148   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
149                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
150 
151   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
152                                                 run_loop.QuitClosure());
153   run_loop.Run();
154 }
155 
TEST_F(SimpleWatcherTest,CancelOnClose)156 TEST_F(SimpleWatcherTest, CancelOnClose) {
157   ScopedMessagePipeHandle a, b;
158   CreateMessagePipe(nullptr, &a, &b);
159 
160   base::RunLoop run_loop;
161   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
162                           base::SequencedTaskRunnerHandle::Get());
163   EXPECT_EQ(MOJO_RESULT_OK,
164             b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
165                             OnReady([&](MojoResult result) {
166                               EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
167                               run_loop.Quit();
168                             })));
169   EXPECT_TRUE(b_watcher.IsWatching());
170 
171   // This should trigger the watcher above.
172   b.reset();
173 
174   run_loop.Run();
175 
176   EXPECT_FALSE(b_watcher.IsWatching());
177 }
178 
TEST_F(SimpleWatcherTest,CancelOnDestruction)179 TEST_F(SimpleWatcherTest, CancelOnDestruction) {
180   ScopedMessagePipeHandle a, b;
181   CreateMessagePipe(nullptr, &a, &b);
182   base::RunLoop run_loop;
183   {
184     SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
185                             base::SequencedTaskRunnerHandle::Get());
186     EXPECT_EQ(
187         MOJO_RESULT_OK,
188         b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached()));
189     EXPECT_TRUE(b_watcher.IsWatching());
190 
191     // |b_watcher| should be cancelled when it goes out of scope.
192   }
193 
194   // This should never trigger the watcher above.
195   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
196                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
197   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
198                                                 run_loop.QuitClosure());
199   run_loop.Run();
200 }
201 
TEST_F(SimpleWatcherTest,CloseAndCancel)202 TEST_F(SimpleWatcherTest, CloseAndCancel) {
203   ScopedMessagePipeHandle a, b;
204   CreateMessagePipe(nullptr, &a, &b);
205 
206   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
207                           base::SequencedTaskRunnerHandle::Get());
208   EXPECT_EQ(MOJO_RESULT_OK,
209             b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
210                             OnReady([](MojoResult result) { FAIL(); })));
211   EXPECT_TRUE(b_watcher.IsWatching());
212 
213   // This should trigger the watcher above...
214   b.reset();
215   // ...but the watcher is cancelled first.
216   b_watcher.Cancel();
217 
218   EXPECT_FALSE(b_watcher.IsWatching());
219 
220   base::RunLoop().RunUntilIdle();
221 }
222 
TEST_F(SimpleWatcherTest,UnarmedCancel)223 TEST_F(SimpleWatcherTest, UnarmedCancel) {
224   ScopedMessagePipeHandle a, b;
225   CreateMessagePipe(nullptr, &a, &b);
226 
227   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL,
228                           base::SequencedTaskRunnerHandle::Get());
229   base::RunLoop loop;
230   EXPECT_EQ(MOJO_RESULT_OK,
231             b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
232                             base::Bind(
233                                 [](base::RunLoop* loop, MojoResult result) {
234                                   EXPECT_EQ(result, MOJO_RESULT_CANCELLED);
235                                   loop->Quit();
236                                 },
237                                 &loop)));
238 
239   // This message write will not wake up the watcher since the watcher isn't
240   // armed. Instead, the cancellation will dispatch due to the reset below.
241   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
242                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
243   b.reset();
244   loop.Run();
245 }
246 
TEST_F(SimpleWatcherTest,ManualArming)247 TEST_F(SimpleWatcherTest, ManualArming) {
248   ScopedMessagePipeHandle a, b;
249   CreateMessagePipe(nullptr, &a, &b);
250 
251   SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL,
252                           base::SequencedTaskRunnerHandle::Get());
253   base::RunLoop loop;
254   EXPECT_EQ(MOJO_RESULT_OK,
255             b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
256                             base::Bind(
257                                 [](base::RunLoop* loop, MojoResult result) {
258                                   EXPECT_EQ(result, MOJO_RESULT_OK);
259                                   loop->Quit();
260                                 },
261                                 &loop)));
262   EXPECT_EQ(MOJO_RESULT_OK, b_watcher.Arm());
263 
264   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
265                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
266   loop.Run();
267 }
268 
TEST_F(SimpleWatcherTest,ManualArmOrNotifyWhileSignaled)269 TEST_F(SimpleWatcherTest, ManualArmOrNotifyWhileSignaled) {
270   ScopedMessagePipeHandle a, b;
271   CreateMessagePipe(nullptr, &a, &b);
272 
273   base::RunLoop loop1;
274   SimpleWatcher b_watcher1(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL);
275   bool notified1 = false;
276   EXPECT_EQ(MOJO_RESULT_OK,
277             b_watcher1.Watch(
278                 b.get(), MOJO_HANDLE_SIGNAL_READABLE,
279                 base::Bind(
280                     [](base::RunLoop* loop, bool* notified, MojoResult result) {
281                       EXPECT_EQ(result, MOJO_RESULT_OK);
282                       *notified = true;
283                       loop->Quit();
284                     },
285                     &loop1, &notified1)));
286 
287   base::RunLoop loop2;
288   SimpleWatcher b_watcher2(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL);
289   bool notified2 = false;
290   EXPECT_EQ(MOJO_RESULT_OK,
291             b_watcher2.Watch(
292                 b.get(), MOJO_HANDLE_SIGNAL_READABLE,
293                 base::Bind(
294                     [](base::RunLoop* loop, bool* notified, MojoResult result) {
295                       EXPECT_EQ(result, MOJO_RESULT_OK);
296                       *notified = true;
297                       loop->Quit();
298                     },
299                     &loop2, &notified2)));
300 
301   // First ensure that |b| is readable.
302   EXPECT_EQ(MOJO_RESULT_OK, b_watcher1.Arm());
303   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
304                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
305   loop1.Run();
306 
307   EXPECT_TRUE(notified1);
308   EXPECT_FALSE(notified2);
309   notified1 = false;
310 
311   // Now verify that ArmOrNotify results in a notification.
312   b_watcher2.ArmOrNotify();
313   loop2.Run();
314 
315   EXPECT_FALSE(notified1);
316   EXPECT_TRUE(notified2);
317 }
318 
319 }  // namespace
320 }  // namespace mojo
321