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