1 // Copyright 2013 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/common/handle_watcher.h"
6
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/run_loop.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "mojo/public/system/core_cpp.h"
12 #include "mojo/public/tests/test_support.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace mojo {
16 namespace common {
17 namespace test {
18
RunUntilIdle()19 void RunUntilIdle() {
20 base::RunLoop run_loop;
21 run_loop.RunUntilIdle();
22 }
23
DeleteWatcherAndForwardResult(HandleWatcher * watcher,base::Callback<void (MojoResult)> next_callback,MojoResult result)24 void DeleteWatcherAndForwardResult(
25 HandleWatcher* watcher,
26 base::Callback<void(MojoResult)> next_callback,
27 MojoResult result) {
28 delete watcher;
29 next_callback.Run(result);
30 }
31
32 // Helper class to manage the callback and running the message loop waiting for
33 // message to be received. Typical usage is something like:
34 // Schedule callback returned from GetCallback().
35 // RunUntilGotCallback();
36 // EXPECT_TRUE(got_callback());
37 // clear_callback();
38 class CallbackHelper {
39 public:
CallbackHelper()40 CallbackHelper()
41 : got_callback_(false),
42 run_loop_(NULL),
43 weak_factory_(this) {}
~CallbackHelper()44 ~CallbackHelper() {}
45
46 // See description above |got_callback_|.
got_callback() const47 bool got_callback() const { return got_callback_; }
clear_callback()48 void clear_callback() { got_callback_ = false; }
49
50 // Runs the current MessageLoop until the callback returned from GetCallback()
51 // is notified.
RunUntilGotCallback()52 void RunUntilGotCallback() {
53 ASSERT_TRUE(run_loop_ == NULL);
54 base::RunLoop run_loop;
55 base::AutoReset<base::RunLoop*> reseter(&run_loop_, &run_loop);
56 run_loop.Run();
57 }
58
GetCallback()59 base::Callback<void(MojoResult)> GetCallback() {
60 return base::Bind(&CallbackHelper::OnCallback, weak_factory_.GetWeakPtr());
61 }
62
Start(HandleWatcher * watcher,const MessagePipeHandle & handle)63 void Start(HandleWatcher* watcher, const MessagePipeHandle& handle) {
64 StartWithCallback(watcher, handle, GetCallback());
65 }
66
StartWithCallback(HandleWatcher * watcher,const MessagePipeHandle & handle,const base::Callback<void (MojoResult)> & callback)67 void StartWithCallback(HandleWatcher* watcher,
68 const MessagePipeHandle& handle,
69 const base::Callback<void(MojoResult)>& callback) {
70 watcher->Start(handle, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE,
71 callback);
72 }
73
74 private:
OnCallback(MojoResult result)75 void OnCallback(MojoResult result) {
76 got_callback_ = true;
77 if (run_loop_)
78 run_loop_->Quit();
79 }
80
81 // Set to true when the callback is called.
82 bool got_callback_;
83
84 // If non-NULL we're in RunUntilGotCallback().
85 base::RunLoop* run_loop_;
86
87 base::WeakPtrFactory<CallbackHelper> weak_factory_;
88
89 private:
90 DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
91 };
92
93 class HandleWatcherTest : public testing::Test {
94 public:
HandleWatcherTest()95 HandleWatcherTest() {}
~HandleWatcherTest()96 virtual ~HandleWatcherTest() {
97 HandleWatcher::tick_clock_ = NULL;
98 }
99
100 protected:
InstallTickClock()101 void InstallTickClock() {
102 HandleWatcher::tick_clock_ = &tick_clock_;
103 }
104
105 base::SimpleTestTickClock tick_clock_;
106
107 private:
108 base::MessageLoop message_loop_;
109
110 DISALLOW_COPY_AND_ASSIGN(HandleWatcherTest);
111 };
112
113 // Trivial test case with a single handle to watch.
TEST_F(HandleWatcherTest,SingleHandler)114 TEST_F(HandleWatcherTest, SingleHandler) {
115 mojo::test::MessagePipe test_pipe;
116 ASSERT_TRUE(test_pipe.handle_0.is_valid());
117 CallbackHelper callback_helper;
118 HandleWatcher watcher;
119 callback_helper.Start(&watcher, test_pipe.handle_0.get());
120 RunUntilIdle();
121 EXPECT_FALSE(callback_helper.got_callback());
122 EXPECT_EQ(MOJO_RESULT_OK,
123 mojo::test::WriteEmptyMessage(test_pipe.handle_1.get()));
124 callback_helper.RunUntilGotCallback();
125 EXPECT_TRUE(callback_helper.got_callback());
126 }
127
128 // Creates three handles and notfies them in reverse order ensuring each one is
129 // notified appropriately.
TEST_F(HandleWatcherTest,ThreeHandles)130 TEST_F(HandleWatcherTest, ThreeHandles) {
131 mojo::test::MessagePipe test_pipe1;
132 mojo::test::MessagePipe test_pipe2;
133 mojo::test::MessagePipe test_pipe3;
134 CallbackHelper callback_helper1;
135 CallbackHelper callback_helper2;
136 CallbackHelper callback_helper3;
137 ASSERT_TRUE(test_pipe1.handle_0.is_valid());
138 ASSERT_TRUE(test_pipe2.handle_0.is_valid());
139 ASSERT_TRUE(test_pipe3.handle_0.is_valid());
140
141 HandleWatcher watcher1;
142 callback_helper1.Start(&watcher1, test_pipe1.handle_0.get());
143 RunUntilIdle();
144 EXPECT_FALSE(callback_helper1.got_callback());
145 EXPECT_FALSE(callback_helper2.got_callback());
146 EXPECT_FALSE(callback_helper3.got_callback());
147
148 HandleWatcher watcher2;
149 callback_helper2.Start(&watcher2, test_pipe2.handle_0.get());
150 RunUntilIdle();
151 EXPECT_FALSE(callback_helper1.got_callback());
152 EXPECT_FALSE(callback_helper2.got_callback());
153 EXPECT_FALSE(callback_helper3.got_callback());
154
155 HandleWatcher watcher3;
156 callback_helper3.Start(&watcher3, test_pipe3.handle_0.get());
157 RunUntilIdle();
158 EXPECT_FALSE(callback_helper1.got_callback());
159 EXPECT_FALSE(callback_helper2.got_callback());
160 EXPECT_FALSE(callback_helper3.got_callback());
161
162 // Write to 3 and make sure it's notified.
163 EXPECT_EQ(MOJO_RESULT_OK,
164 mojo::test::WriteEmptyMessage(test_pipe3.handle_1.get()));
165 callback_helper3.RunUntilGotCallback();
166 EXPECT_FALSE(callback_helper1.got_callback());
167 EXPECT_FALSE(callback_helper2.got_callback());
168 EXPECT_TRUE(callback_helper3.got_callback());
169 callback_helper3.clear_callback();
170
171 // Write to 1 and 3. Only 1 should be notified since 3 was is no longer
172 // running.
173 EXPECT_EQ(MOJO_RESULT_OK,
174 mojo::test::WriteEmptyMessage(test_pipe1.handle_1.get()));
175 EXPECT_EQ(MOJO_RESULT_OK,
176 mojo::test::WriteEmptyMessage(test_pipe3.handle_1.get()));
177 callback_helper1.RunUntilGotCallback();
178 EXPECT_TRUE(callback_helper1.got_callback());
179 EXPECT_FALSE(callback_helper2.got_callback());
180 EXPECT_FALSE(callback_helper3.got_callback());
181 callback_helper1.clear_callback();
182
183 // Write to 1 and 2. Only 2 should be notified (since 1 was already notified).
184 EXPECT_EQ(MOJO_RESULT_OK,
185 mojo::test::WriteEmptyMessage(test_pipe1.handle_1.get()));
186 EXPECT_EQ(MOJO_RESULT_OK,
187 mojo::test::WriteEmptyMessage(test_pipe2.handle_1.get()));
188 callback_helper2.RunUntilGotCallback();
189 EXPECT_FALSE(callback_helper1.got_callback());
190 EXPECT_TRUE(callback_helper2.got_callback());
191 EXPECT_FALSE(callback_helper3.got_callback());
192 }
193
194 // Verifies Start() invoked a second time works.
TEST_F(HandleWatcherTest,Restart)195 TEST_F(HandleWatcherTest, Restart) {
196 mojo::test::MessagePipe test_pipe1;
197 mojo::test::MessagePipe test_pipe2;
198 CallbackHelper callback_helper1;
199 CallbackHelper callback_helper2;
200 ASSERT_TRUE(test_pipe1.handle_0.is_valid());
201 ASSERT_TRUE(test_pipe2.handle_0.is_valid());
202
203 HandleWatcher watcher1;
204 callback_helper1.Start(&watcher1, test_pipe1.handle_0.get());
205 RunUntilIdle();
206 EXPECT_FALSE(callback_helper1.got_callback());
207 EXPECT_FALSE(callback_helper2.got_callback());
208
209 HandleWatcher watcher2;
210 callback_helper2.Start(&watcher2, test_pipe2.handle_0.get());
211 RunUntilIdle();
212 EXPECT_FALSE(callback_helper1.got_callback());
213 EXPECT_FALSE(callback_helper2.got_callback());
214
215 // Write to 1 and make sure it's notified.
216 EXPECT_EQ(MOJO_RESULT_OK,
217 mojo::test::WriteEmptyMessage(test_pipe1.handle_1.get()));
218 callback_helper1.RunUntilGotCallback();
219 EXPECT_TRUE(callback_helper1.got_callback());
220 EXPECT_FALSE(callback_helper2.got_callback());
221 callback_helper1.clear_callback();
222 EXPECT_EQ(MOJO_RESULT_OK,
223 mojo::test::ReadEmptyMessage(test_pipe1.handle_0.get()));
224
225 // Write to 2 and make sure it's notified.
226 EXPECT_EQ(MOJO_RESULT_OK,
227 mojo::test::WriteEmptyMessage(test_pipe2.handle_1.get()));
228 callback_helper2.RunUntilGotCallback();
229 EXPECT_FALSE(callback_helper1.got_callback());
230 EXPECT_TRUE(callback_helper2.got_callback());
231 callback_helper2.clear_callback();
232
233 // Listen on 1 again.
234 callback_helper1.Start(&watcher1, test_pipe1.handle_0.get());
235 RunUntilIdle();
236 EXPECT_FALSE(callback_helper1.got_callback());
237 EXPECT_FALSE(callback_helper2.got_callback());
238
239 // Write to 1 and make sure it's notified.
240 EXPECT_EQ(MOJO_RESULT_OK,
241 mojo::test::WriteEmptyMessage(test_pipe1.handle_1.get()));
242 callback_helper1.RunUntilGotCallback();
243 EXPECT_TRUE(callback_helper1.got_callback());
244 EXPECT_FALSE(callback_helper2.got_callback());
245 }
246
247 // Verifies deadline is honored.
TEST_F(HandleWatcherTest,Deadline)248 TEST_F(HandleWatcherTest, Deadline) {
249 InstallTickClock();
250
251 mojo::test::MessagePipe test_pipe1;
252 mojo::test::MessagePipe test_pipe2;
253 mojo::test::MessagePipe test_pipe3;
254 CallbackHelper callback_helper1;
255 CallbackHelper callback_helper2;
256 CallbackHelper callback_helper3;
257 ASSERT_TRUE(test_pipe1.handle_0.is_valid());
258 ASSERT_TRUE(test_pipe2.handle_0.is_valid());
259 ASSERT_TRUE(test_pipe3.handle_0.is_valid());
260
261 // Add a watcher with an infinite timeout.
262 HandleWatcher watcher1;
263 callback_helper1.Start(&watcher1, test_pipe1.handle_0.get());
264 RunUntilIdle();
265 EXPECT_FALSE(callback_helper1.got_callback());
266 EXPECT_FALSE(callback_helper2.got_callback());
267 EXPECT_FALSE(callback_helper3.got_callback());
268
269 // Add another watcher wth a timeout of 500 microseconds.
270 HandleWatcher watcher2;
271 watcher2.Start(test_pipe2.handle_0.get(), MOJO_WAIT_FLAG_READABLE, 500,
272 callback_helper2.GetCallback());
273 RunUntilIdle();
274 EXPECT_FALSE(callback_helper1.got_callback());
275 EXPECT_FALSE(callback_helper2.got_callback());
276 EXPECT_FALSE(callback_helper3.got_callback());
277
278 // Advance the clock passed the deadline. We also have to start another
279 // watcher to wake up the background thread.
280 tick_clock_.Advance(base::TimeDelta::FromMicroseconds(501));
281
282 HandleWatcher watcher3;
283 callback_helper3.Start(&watcher3, test_pipe3.handle_0.get());
284
285 callback_helper2.RunUntilGotCallback();
286 EXPECT_FALSE(callback_helper1.got_callback());
287 EXPECT_TRUE(callback_helper2.got_callback());
288 EXPECT_FALSE(callback_helper3.got_callback());
289 }
290
TEST_F(HandleWatcherTest,DeleteInCallback)291 TEST_F(HandleWatcherTest, DeleteInCallback) {
292 mojo::test::MessagePipe test_pipe;
293 CallbackHelper callback_helper;
294
295 HandleWatcher* watcher = new HandleWatcher();
296 callback_helper.StartWithCallback(watcher, test_pipe.handle_1.get(),
297 base::Bind(&DeleteWatcherAndForwardResult,
298 watcher,
299 callback_helper.GetCallback()));
300 mojo::test::WriteEmptyMessage(test_pipe.handle_0.get());
301 callback_helper.RunUntilGotCallback();
302 EXPECT_TRUE(callback_helper.got_callback());
303 }
304
305 } // namespace test
306 } // namespace common
307 } // namespace mojo
308