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