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/watcher.h"
6 
7 #include <memory>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "mojo/public/c/system/types.h"
15 #include "mojo/public/cpp/system/message_pipe.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace mojo {
19 namespace {
20 
21 template <typename Handler>
RunResultHandler(Handler f,MojoResult result)22 void RunResultHandler(Handler f, MojoResult result) { f(result); }
23 
24 template <typename Handler>
OnReady(Handler f)25 Watcher::ReadyCallback OnReady(Handler f) {
26   return base::Bind(&RunResultHandler<Handler>, f);
27 }
28 
NotReached()29 Watcher::ReadyCallback NotReached() {
30   return OnReady([] (MojoResult) { NOTREACHED(); });
31 }
32 
33 class WatcherTest : public testing::Test {
34  public:
WatcherTest()35   WatcherTest() {}
~WatcherTest()36   ~WatcherTest() override {}
37 
SetUp()38   void SetUp() override {
39     message_loop_.reset(new base::MessageLoop);
40   }
41 
TearDown()42   void TearDown() override {
43     message_loop_.reset();
44   }
45 
46  protected:
47   std::unique_ptr<base::MessageLoop> message_loop_;
48 };
49 
TEST_F(WatcherTest,WatchBasic)50 TEST_F(WatcherTest, WatchBasic) {
51   ScopedMessagePipeHandle a, b;
52   CreateMessagePipe(nullptr, &a, &b);
53 
54   bool notified = false;
55   base::RunLoop run_loop;
56   Watcher b_watcher;
57   EXPECT_EQ(MOJO_RESULT_OK,
58             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
59                             OnReady([&] (MojoResult result) {
60                               EXPECT_EQ(MOJO_RESULT_OK, result);
61                               notified = true;
62                               run_loop.Quit();
63                             })));
64   EXPECT_TRUE(b_watcher.IsWatching());
65 
66   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
67                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
68   run_loop.Run();
69   EXPECT_TRUE(notified);
70 
71   b_watcher.Cancel();
72 }
73 
TEST_F(WatcherTest,WatchUnsatisfiable)74 TEST_F(WatcherTest, WatchUnsatisfiable) {
75   ScopedMessagePipeHandle a, b;
76   CreateMessagePipe(nullptr, &a, &b);
77   a.reset();
78 
79   Watcher b_watcher;
80   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
81             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
82                             NotReached()));
83   EXPECT_FALSE(b_watcher.IsWatching());
84 }
85 
TEST_F(WatcherTest,WatchInvalidHandle)86 TEST_F(WatcherTest, WatchInvalidHandle) {
87   ScopedMessagePipeHandle a, b;
88   CreateMessagePipe(nullptr, &a, &b);
89   a.reset();
90   b.reset();
91 
92   Watcher b_watcher;
93   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
94             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
95                             NotReached()));
96   EXPECT_FALSE(b_watcher.IsWatching());
97 }
98 
TEST_F(WatcherTest,Cancel)99 TEST_F(WatcherTest, Cancel) {
100   ScopedMessagePipeHandle a, b;
101   CreateMessagePipe(nullptr, &a, &b);
102 
103   base::RunLoop run_loop;
104   Watcher b_watcher;
105   EXPECT_EQ(MOJO_RESULT_OK,
106             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
107                             NotReached()));
108   EXPECT_TRUE(b_watcher.IsWatching());
109   b_watcher.Cancel();
110   EXPECT_FALSE(b_watcher.IsWatching());
111 
112   // This should never trigger the watcher.
113   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
114                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
115 
116   base::ThreadTaskRunnerHandle::Get()->PostTask(
117       FROM_HERE, run_loop.QuitClosure());
118   run_loop.Run();
119 }
120 
TEST_F(WatcherTest,CancelOnClose)121 TEST_F(WatcherTest, CancelOnClose) {
122   ScopedMessagePipeHandle a, b;
123   CreateMessagePipe(nullptr, &a, &b);
124 
125   base::RunLoop run_loop;
126   Watcher b_watcher;
127   EXPECT_EQ(MOJO_RESULT_OK,
128             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
129                             OnReady([&] (MojoResult result) {
130                               EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
131                               run_loop.Quit();
132                             })));
133   EXPECT_TRUE(b_watcher.IsWatching());
134 
135   // This should trigger the watcher above.
136   b.reset();
137 
138   run_loop.Run();
139 
140   EXPECT_FALSE(b_watcher.IsWatching());
141 }
142 
TEST_F(WatcherTest,CancelOnDestruction)143 TEST_F(WatcherTest, CancelOnDestruction) {
144   ScopedMessagePipeHandle a, b;
145   CreateMessagePipe(nullptr, &a, &b);
146   base::RunLoop run_loop;
147   {
148     Watcher b_watcher;
149     EXPECT_EQ(MOJO_RESULT_OK,
150               b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
151                               NotReached()));
152     EXPECT_TRUE(b_watcher.IsWatching());
153 
154     // |b_watcher| should be cancelled when it goes out of scope.
155   }
156 
157   // This should never trigger the watcher above.
158   EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0,
159                                             MOJO_WRITE_MESSAGE_FLAG_NONE));
160   base::ThreadTaskRunnerHandle::Get()->PostTask(
161       FROM_HERE, run_loop.QuitClosure());
162   run_loop.Run();
163 }
164 
TEST_F(WatcherTest,NotifyOnMessageLoopDestruction)165 TEST_F(WatcherTest, NotifyOnMessageLoopDestruction) {
166   ScopedMessagePipeHandle a, b;
167   CreateMessagePipe(nullptr, &a, &b);
168 
169   bool notified = false;
170   Watcher b_watcher;
171   EXPECT_EQ(MOJO_RESULT_OK,
172             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
173                             OnReady([&] (MojoResult result) {
174                               EXPECT_EQ(MOJO_RESULT_ABORTED, result);
175                               notified = true;
176                             })));
177   EXPECT_TRUE(b_watcher.IsWatching());
178 
179   message_loop_.reset();
180 
181   EXPECT_TRUE(notified);
182 
183   EXPECT_TRUE(b_watcher.IsWatching());
184   b_watcher.Cancel();
185 }
186 
TEST_F(WatcherTest,CloseAndCancel)187 TEST_F(WatcherTest, CloseAndCancel) {
188   ScopedMessagePipeHandle a, b;
189   CreateMessagePipe(nullptr, &a, &b);
190 
191   Watcher b_watcher;
192   EXPECT_EQ(MOJO_RESULT_OK,
193             b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE,
194                             OnReady([](MojoResult result) { FAIL(); })));
195   EXPECT_TRUE(b_watcher.IsWatching());
196 
197   // This should trigger the watcher above...
198   b.reset();
199   // ...but the watcher is cancelled first.
200   b_watcher.Cancel();
201 
202   EXPECT_FALSE(b_watcher.IsWatching());
203 
204   base::RunLoop().RunUntilIdle();
205 }
206 
207 }  // namespace
208 }  // namespace mojo
209