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 "base/files/file_descriptor_watcher_posix.h"
6 
7 #include <unistd.h>
8 
9 #include <memory>
10 
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/posix/eintr_wrapper.h"
17 #include "base/run_loop.h"
18 #include "base/test/test_timeouts.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_checker_impl.h"
22 #include "build/build_config.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace base {
27 
28 namespace {
29 
30 class Mock {
31  public:
32   Mock() = default;
33 
34   MOCK_METHOD0(ReadableCallback, void());
35   MOCK_METHOD0(WritableCallback, void());
36 
37  private:
38   DISALLOW_COPY_AND_ASSIGN(Mock);
39 };
40 
41 enum class FileDescriptorWatcherTestType {
42   MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD,
43   MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD,
44 };
45 
46 class FileDescriptorWatcherTest
47     : public testing::TestWithParam<FileDescriptorWatcherTestType> {
48  public:
FileDescriptorWatcherTest()49   FileDescriptorWatcherTest()
50       : message_loop_(GetParam() == FileDescriptorWatcherTestType::
51                                         MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD
52                           ? new MessageLoopForIO
53                           : new MessageLoop),
54         other_thread_("FileDescriptorWatcherTest_OtherThread") {}
55   ~FileDescriptorWatcherTest() override = default;
56 
SetUp()57   void SetUp() override {
58     ASSERT_EQ(0, pipe(pipe_fds_));
59 
60     MessageLoop* message_loop_for_io;
61     if (GetParam() ==
62         FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD) {
63       Thread::Options options;
64       options.message_loop_type = MessageLoop::TYPE_IO;
65       ASSERT_TRUE(other_thread_.StartWithOptions(options));
66       message_loop_for_io = other_thread_.message_loop();
67     } else {
68       message_loop_for_io = message_loop_.get();
69     }
70 
71     ASSERT_TRUE(message_loop_for_io->IsType(MessageLoop::TYPE_IO));
72     file_descriptor_watcher_ = std::make_unique<FileDescriptorWatcher>(
73         static_cast<MessageLoopForIO*>(message_loop_for_io));
74   }
75 
TearDown()76   void TearDown() override {
77     if (GetParam() ==
78             FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD &&
79         message_loop_) {
80       // Allow the delete task posted by the Controller's destructor to run.
81       base::RunLoop().RunUntilIdle();
82     }
83 
84     // Ensure that OtherThread is done processing before closing fds.
85     other_thread_.Stop();
86 
87     EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[0])));
88     EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[1])));
89   }
90 
91  protected:
read_file_descriptor() const92   int read_file_descriptor() const { return pipe_fds_[0]; }
write_file_descriptor() const93   int write_file_descriptor() const { return pipe_fds_[1]; }
94 
95   // Waits for a short delay and run pending tasks.
WaitAndRunPendingTasks()96   void WaitAndRunPendingTasks() {
97     PlatformThread::Sleep(TestTimeouts::tiny_timeout());
98     RunLoop().RunUntilIdle();
99   }
100 
101   // Registers ReadableCallback() to be called on |mock_| when
102   // read_file_descriptor() is readable without blocking.
WatchReadable()103   std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable() {
104     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
105         FileDescriptorWatcher::WatchReadable(
106             read_file_descriptor(),
107             Bind(&Mock::ReadableCallback, Unretained(&mock_)));
108     EXPECT_TRUE(controller);
109 
110     // Unless read_file_descriptor() was readable before the callback was
111     // registered, this shouldn't do anything.
112     WaitAndRunPendingTasks();
113 
114     return controller;
115   }
116 
117   // Registers WritableCallback() to be called on |mock_| when
118   // write_file_descriptor() is writable without blocking.
WatchWritable()119   std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable() {
120     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
121         FileDescriptorWatcher::WatchWritable(
122             write_file_descriptor(),
123             Bind(&Mock::WritableCallback, Unretained(&mock_)));
124     EXPECT_TRUE(controller);
125     return controller;
126   }
127 
WriteByte()128   void WriteByte() {
129     constexpr char kByte = '!';
130     ASSERT_TRUE(
131         WriteFileDescriptor(write_file_descriptor(), &kByte, sizeof(kByte)));
132   }
133 
ReadByte()134   void ReadByte() {
135     // This is always called as part of the WatchReadable() callback, which
136     // should run on the main thread.
137     EXPECT_TRUE(thread_checker_.CalledOnValidThread());
138 
139     char buffer;
140     ASSERT_TRUE(ReadFromFD(read_file_descriptor(), &buffer, sizeof(buffer)));
141   }
142 
143   // Mock on wich callbacks are invoked.
144   testing::StrictMock<Mock> mock_;
145 
146   // MessageLoop bound to the main thread.
147   std::unique_ptr<MessageLoop> message_loop_;
148 
149   // Thread running a MessageLoopForIO. Used when the test type is
150   // MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD.
151   Thread other_thread_;
152 
153  private:
154   // Determines which MessageLoopForIO is used to watch file descriptors for
155   // which callbacks are registered on the main thread.
156   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
157 
158   // Watched file descriptors.
159   int pipe_fds_[2];
160 
161   // Used to verify that callbacks run on the thread on which they are
162   // registered.
163   ThreadCheckerImpl thread_checker_;
164 
165   DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcherTest);
166 };
167 
168 }  // namespace
169 
TEST_P(FileDescriptorWatcherTest,WatchWritable)170 TEST_P(FileDescriptorWatcherTest, WatchWritable) {
171   auto controller = WatchWritable();
172 
173   // The write end of a newly created pipe is immediately writable.
174   RunLoop run_loop;
175   EXPECT_CALL(mock_, WritableCallback())
176       .WillOnce(testing::Invoke(&run_loop, &RunLoop::Quit));
177   run_loop.Run();
178 }
179 
TEST_P(FileDescriptorWatcherTest,WatchReadableOneByte)180 TEST_P(FileDescriptorWatcherTest, WatchReadableOneByte) {
181   auto controller = WatchReadable();
182 
183   // Write 1 byte to the pipe, making it readable without blocking. Expect one
184   // call to ReadableCallback() which will read 1 byte from the pipe.
185   WriteByte();
186   RunLoop run_loop;
187   EXPECT_CALL(mock_, ReadableCallback())
188       .WillOnce(testing::Invoke([this, &run_loop]() {
189         ReadByte();
190         run_loop.Quit();
191       }));
192   run_loop.Run();
193   testing::Mock::VerifyAndClear(&mock_);
194 
195   // No more call to ReadableCallback() is expected.
196   WaitAndRunPendingTasks();
197 }
198 
TEST_P(FileDescriptorWatcherTest,WatchReadableTwoBytes)199 TEST_P(FileDescriptorWatcherTest, WatchReadableTwoBytes) {
200   auto controller = WatchReadable();
201 
202   // Write 2 bytes to the pipe. Expect two calls to ReadableCallback() which
203   // will each read 1 byte from the pipe.
204   WriteByte();
205   WriteByte();
206   RunLoop run_loop;
207   EXPECT_CALL(mock_, ReadableCallback())
208       .WillOnce(testing::Invoke([this]() { ReadByte(); }))
209       .WillOnce(testing::Invoke([this, &run_loop]() {
210         ReadByte();
211         run_loop.Quit();
212       }));
213   run_loop.Run();
214   testing::Mock::VerifyAndClear(&mock_);
215 
216   // No more call to ReadableCallback() is expected.
217   WaitAndRunPendingTasks();
218 }
219 
TEST_P(FileDescriptorWatcherTest,WatchReadableByteWrittenFromCallback)220 TEST_P(FileDescriptorWatcherTest, WatchReadableByteWrittenFromCallback) {
221   auto controller = WatchReadable();
222 
223   // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which
224   // 1 byte is read and 1 byte is written to the pipe. Then, expect another call
225   // to ReadableCallback() from which the remaining byte is read from the pipe.
226   WriteByte();
227   RunLoop run_loop;
228   EXPECT_CALL(mock_, ReadableCallback())
229       .WillOnce(testing::Invoke([this]() {
230         ReadByte();
231         WriteByte();
232       }))
233       .WillOnce(testing::Invoke([this, &run_loop]() {
234         ReadByte();
235         run_loop.Quit();
236       }));
237   run_loop.Run();
238   testing::Mock::VerifyAndClear(&mock_);
239 
240   // No more call to ReadableCallback() is expected.
241   WaitAndRunPendingTasks();
242 }
243 
TEST_P(FileDescriptorWatcherTest,DeleteControllerFromCallback)244 TEST_P(FileDescriptorWatcherTest, DeleteControllerFromCallback) {
245   auto controller = WatchReadable();
246 
247   // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which
248   // |controller| is deleted.
249   WriteByte();
250   RunLoop run_loop;
251   EXPECT_CALL(mock_, ReadableCallback())
252       .WillOnce(testing::Invoke([&run_loop, &controller]() {
253         controller = nullptr;
254         run_loop.Quit();
255       }));
256   run_loop.Run();
257   testing::Mock::VerifyAndClear(&mock_);
258 
259   // Since |controller| has been deleted, no call to ReadableCallback() is
260   // expected even though the pipe is still readable without blocking.
261   WaitAndRunPendingTasks();
262 }
263 
TEST_P(FileDescriptorWatcherTest,DeleteControllerBeforeFileDescriptorReadable)264 TEST_P(FileDescriptorWatcherTest,
265        DeleteControllerBeforeFileDescriptorReadable) {
266   auto controller = WatchReadable();
267 
268   // Cancel the watch.
269   controller = nullptr;
270 
271   // Write 1 byte to the pipe to make it readable without blocking.
272   WriteByte();
273 
274   // No call to ReadableCallback() is expected.
275   WaitAndRunPendingTasks();
276 }
277 
TEST_P(FileDescriptorWatcherTest,DeleteControllerAfterFileDescriptorReadable)278 TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterFileDescriptorReadable) {
279   auto controller = WatchReadable();
280 
281   // Write 1 byte to the pipe to make it readable without blocking.
282   WriteByte();
283 
284   // Cancel the watch.
285   controller = nullptr;
286 
287   // No call to ReadableCallback() is expected.
288   WaitAndRunPendingTasks();
289 }
290 
TEST_P(FileDescriptorWatcherTest,DeleteControllerAfterDeleteMessageLoopForIO)291 TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterDeleteMessageLoopForIO) {
292   auto controller = WatchReadable();
293 
294   // Delete the MessageLoopForIO.
295   if (GetParam() ==
296       FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD) {
297     message_loop_ = nullptr;
298   } else {
299     other_thread_.Stop();
300   }
301 
302   // Deleting |controller| shouldn't crash even though that causes a task to be
303   // posted to the MessageLoopForIO thread.
304   controller = nullptr;
305 }
306 
307 INSTANTIATE_TEST_CASE_P(
308     MessageLoopForIOOnMainThread,
309     FileDescriptorWatcherTest,
310     ::testing::Values(
311         FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD));
312 INSTANTIATE_TEST_CASE_P(
313     MessageLoopForIOOnOtherThread,
314     FileDescriptorWatcherTest,
315     ::testing::Values(
316         FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD));
317 
318 }  // namespace base
319