• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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