• 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/files/file_descriptor_watcher_posix.h"
11 
12 #include <unistd.h>
13 
14 #include <memory>
15 
16 #include "base/containers/span.h"
17 #include "base/files/file_util.h"
18 #include "base/functional/bind.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/message_loop/message_pump_type.h"
21 #include "base/posix/eintr_wrapper.h"
22 #include "base/run_loop.h"
23 #include "base/test/task_environment.h"
24 #include "base/test/test_timeouts.h"
25 #include "base/threading/platform_thread.h"
26 #include "base/threading/thread.h"
27 #include "base/threading/thread_checker_impl.h"
28 #include "build/build_config.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 
32 namespace base {
33 
34 namespace {
35 
36 class Mock {
37  public:
38   Mock() = default;
39   Mock(const Mock&) = delete;
40   Mock& operator=(const Mock&) = delete;
41 
42   MOCK_METHOD0(ReadableCallback, void());
43   MOCK_METHOD0(WritableCallback, void());
44   MOCK_METHOD0(ReadableCallback2, void());
45   MOCK_METHOD0(WritableCallback2, void());
46 };
47 
48 enum class FileDescriptorWatcherTestType {
49   MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD,
50   MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD,
51 };
52 
53 class FileDescriptorWatcherTest
54     : public testing::TestWithParam<FileDescriptorWatcherTestType> {
55  public:
FileDescriptorWatcherTest()56   FileDescriptorWatcherTest()
57       : task_environment_(std::make_unique<test::TaskEnvironment>(
58             GetParam() == FileDescriptorWatcherTestType::
59                               MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD
60                 ? test::TaskEnvironment::MainThreadType::IO
61                 : test::TaskEnvironment::MainThreadType::DEFAULT)),
62         other_thread_("FileDescriptorWatcherTest_OtherThread") {}
63   FileDescriptorWatcherTest(const FileDescriptorWatcherTest&) = delete;
64   FileDescriptorWatcherTest& operator=(const FileDescriptorWatcherTest&) =
65       delete;
66   ~FileDescriptorWatcherTest() override = default;
67 
SetUp()68   void SetUp() override {
69     ASSERT_EQ(0, pipe(pipe_fds_));
70     ASSERT_EQ(0, pipe(pipe_fds2_));
71 
72     scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner;
73     if (GetParam() ==
74         FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD) {
75       Thread::Options options;
76       options.message_pump_type = MessagePumpType::IO;
77       ASSERT_TRUE(other_thread_.StartWithOptions(std::move(options)));
78       file_descriptor_watcher_ =
79           std::make_unique<FileDescriptorWatcher>(other_thread_.task_runner());
80     }
81   }
82 
TearDown()83   void TearDown() override {
84     if (GetParam() ==
85             FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD &&
86         task_environment_) {
87       // Allow the delete task posted by the Controller's destructor to run.
88       base::RunLoop().RunUntilIdle();
89     }
90 
91     // Ensure that OtherThread is done processing before closing fds.
92     other_thread_.Stop();
93 
94     EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[0])));
95     EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[1])));
96 
97     // These fds may be destroyed during tests.
98     if (pipe_fds2_[0] != -1) {
99       EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds2_[0])));
100     }
101     if (pipe_fds2_[1] != -1) {
102       EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds2_[1])));
103     }
104   }
105 
106  protected:
read_file_descriptor() const107   int read_file_descriptor() const { return pipe_fds_[0]; }
write_file_descriptor() const108   int write_file_descriptor() const { return pipe_fds_[1]; }
109 
read_file_descriptor2() const110   int read_file_descriptor2() const { return pipe_fds2_[0]; }
write_file_descriptor2() const111   int write_file_descriptor2() const { return pipe_fds2_[1]; }
read_file_descriptor2_ref()112   int& read_file_descriptor2_ref() { return pipe_fds2_[0]; }
write_file_descriptor2_ref()113   int& write_file_descriptor2_ref() { return pipe_fds2_[1]; }
114 
115   // Waits for a short delay and run pending tasks.
WaitAndRunPendingTasks()116   void WaitAndRunPendingTasks() {
117     PlatformThread::Sleep(TestTimeouts::tiny_timeout());
118     RunLoop().RunUntilIdle();
119   }
120 
121   // Registers ReadableCallback() to be called on |mock_| when
122   // read_file_descriptor() is readable without blocking.
WatchReadable()123   std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable() {
124     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
125         FileDescriptorWatcher::WatchReadable(
126             read_file_descriptor(),
127             BindRepeating(&Mock::ReadableCallback, Unretained(&mock_)));
128     EXPECT_TRUE(controller);
129 
130     // Unless read_file_descriptor() was readable before the callback was
131     // registered, this shouldn't do anything.
132     WaitAndRunPendingTasks();
133 
134     return controller;
135   }
136 
137   // Registers WritableCallback() to be called on |mock_| when
138   // write_file_descriptor() is writable without blocking.
WatchWritable()139   std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable() {
140     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
141         FileDescriptorWatcher::WatchWritable(
142             write_file_descriptor(),
143             BindRepeating(&Mock::WritableCallback, Unretained(&mock_)));
144     EXPECT_TRUE(controller);
145     return controller;
146   }
147 
148   // Registers ReadableCallback2() to be called on |mock_| when
149   // read_file_descriptor2() is readable without blocking.
WatchReadable2()150   std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable2() {
151     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
152         FileDescriptorWatcher::WatchReadable(
153             read_file_descriptor2(),
154             BindRepeating(&Mock::ReadableCallback2, Unretained(&mock_)));
155     EXPECT_TRUE(controller);
156 
157     // Unless read_file_descriptor() was readable before the callback was
158     // registered, this shouldn't do anything.
159     WaitAndRunPendingTasks();
160 
161     return controller;
162   }
163 
164   // Registers WritableCallback2() to be called on |mock_| when
165   // write_file_descriptor2() is writable without blocking.
WatchWritable2()166   std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable2() {
167     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
168         FileDescriptorWatcher::WatchWritable(
169             write_file_descriptor2(),
170             BindRepeating(&Mock::WritableCallback2, Unretained(&mock_)));
171     EXPECT_TRUE(controller);
172     return controller;
173   }
174 
WriteByte()175   void WriteByte() {
176     constexpr char kByte = '!';
177     ASSERT_TRUE(WriteFileDescriptor(write_file_descriptor(),
178                                     byte_span_from_ref(kByte)));
179   }
180 
ReadByte()181   void ReadByte() {
182     // This is always called in ReadableCallback(), which should run on the main
183     // thread.
184     EXPECT_TRUE(thread_checker_.CalledOnValidThread());
185 
186     char buffer;
187     ASSERT_TRUE(ReadFromFD(read_file_descriptor(), span_from_ref(buffer)));
188   }
189 
WriteByte2()190   void WriteByte2() {
191     constexpr char kByte = '!';
192     ASSERT_TRUE(WriteFileDescriptor(write_file_descriptor2(),
193                                     byte_span_from_ref(kByte)));
194   }
195 
ReadByte2()196   void ReadByte2() {
197     // This is always called in ReadableCallback2(), which should run on the
198     // main thread.
199     EXPECT_TRUE(thread_checker_.CalledOnValidThread());
200 
201     char buffer;
202     ASSERT_TRUE(ReadFromFD(read_file_descriptor2(), span_from_ref(buffer)));
203   }
204 
CloseWriteFd2()205   void CloseWriteFd2() {
206     ASSERT_EQ(0, IGNORE_EINTR(close(write_file_descriptor2())));
207     write_file_descriptor2_ref() = -1;
208   }
209 
210   // Mock on wich callbacks are invoked.
211   testing::StrictMock<Mock> mock_;
212 
213   // Task environment bound to the main thread.
214   std::unique_ptr<test::TaskEnvironment> task_environment_;
215 
216   // Thread running an IO message pump. Used when the test type is
217   // MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD.
218   Thread other_thread_;
219 
220  private:
221   // Used to listen for file descriptor events on |other_thread_|. The scoped
222   // task environment implements a watcher for the main thread case.
223   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
224 
225   // Watched file descriptors.
226   int pipe_fds_[2];
227   int pipe_fds2_[2];
228 
229   // Used to verify that callbacks run on the thread on which they are
230   // registered.
231   ThreadCheckerImpl thread_checker_;
232 };
233 
234 }  // namespace
235 
TEST_P(FileDescriptorWatcherTest,WatchWritable)236 TEST_P(FileDescriptorWatcherTest, WatchWritable) {
237   auto controller = WatchWritable();
238 
239   // The write end of a newly created pipe is immediately writable.
240   RunLoop run_loop;
241   EXPECT_CALL(mock_, WritableCallback())
242       .WillOnce(testing::Invoke(&run_loop, &RunLoop::Quit));
243   run_loop.Run();
244 }
245 
TEST_P(FileDescriptorWatcherTest,WatchReadableOneByte)246 TEST_P(FileDescriptorWatcherTest, WatchReadableOneByte) {
247   auto controller = WatchReadable();
248 
249   // Write 1 byte to the pipe, making it readable without blocking. Expect one
250   // call to ReadableCallback() which will read 1 byte from the pipe.
251   WriteByte();
252   RunLoop run_loop;
253   EXPECT_CALL(mock_, ReadableCallback())
254       .WillOnce(testing::Invoke([this, &run_loop] {
255         ReadByte();
256         run_loop.Quit();
257       }));
258   run_loop.Run();
259   testing::Mock::VerifyAndClear(&mock_);
260 
261   // No more call to ReadableCallback() is expected.
262   WaitAndRunPendingTasks();
263 }
264 
TEST_P(FileDescriptorWatcherTest,WatchReadableTwoBytes)265 TEST_P(FileDescriptorWatcherTest, WatchReadableTwoBytes) {
266   auto controller = WatchReadable();
267 
268   // Write 2 bytes to the pipe. Expect two calls to ReadableCallback() which
269   // will each read 1 byte from the pipe.
270   WriteByte();
271   WriteByte();
272   RunLoop run_loop;
273   EXPECT_CALL(mock_, ReadableCallback())
274       .WillOnce(testing::Invoke([this] { ReadByte(); }))
275       .WillOnce(testing::Invoke([this, &run_loop] {
276         ReadByte();
277         run_loop.Quit();
278       }));
279   run_loop.Run();
280   testing::Mock::VerifyAndClear(&mock_);
281 
282   // No more call to ReadableCallback() is expected.
283   WaitAndRunPendingTasks();
284 }
285 
TEST_P(FileDescriptorWatcherTest,WatchReadableByteWrittenFromCallback)286 TEST_P(FileDescriptorWatcherTest, WatchReadableByteWrittenFromCallback) {
287   auto controller = WatchReadable();
288 
289   // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which
290   // 1 byte is read and 1 byte is written to the pipe. Then, expect another call
291   // to ReadableCallback() from which the remaining byte is read from the pipe.
292   WriteByte();
293   RunLoop run_loop;
294   EXPECT_CALL(mock_, ReadableCallback())
295       .WillOnce(testing::Invoke([this] {
296         ReadByte();
297         WriteByte();
298       }))
299       .WillOnce(testing::Invoke([this, &run_loop] {
300         ReadByte();
301         run_loop.Quit();
302       }));
303   run_loop.Run();
304   testing::Mock::VerifyAndClear(&mock_);
305 
306   // No more call to ReadableCallback() is expected.
307   WaitAndRunPendingTasks();
308 }
309 
TEST_P(FileDescriptorWatcherTest,DeleteControllerFromCallback)310 TEST_P(FileDescriptorWatcherTest, DeleteControllerFromCallback) {
311   auto controller = WatchReadable();
312 
313   // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which
314   // |controller| is deleted.
315   WriteByte();
316   RunLoop run_loop;
317   EXPECT_CALL(mock_, ReadableCallback())
318       .WillOnce(testing::Invoke([&run_loop, &controller] {
319         controller = nullptr;
320         run_loop.Quit();
321       }));
322   run_loop.Run();
323   testing::Mock::VerifyAndClear(&mock_);
324 
325   // Since |controller| has been deleted, no call to ReadableCallback() is
326   // expected even though the pipe is still readable without blocking.
327   WaitAndRunPendingTasks();
328 }
329 
TEST_P(FileDescriptorWatcherTest,DeleteControllerBeforeFileDescriptorReadable)330 TEST_P(FileDescriptorWatcherTest,
331        DeleteControllerBeforeFileDescriptorReadable) {
332   auto controller = WatchReadable();
333 
334   // Cancel the watch.
335   controller = nullptr;
336 
337   // Write 1 byte to the pipe to make it readable without blocking.
338   WriteByte();
339 
340   // No call to ReadableCallback() is expected.
341   WaitAndRunPendingTasks();
342 }
343 
TEST_P(FileDescriptorWatcherTest,DeleteControllerAfterFileDescriptorReadable)344 TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterFileDescriptorReadable) {
345   auto controller = WatchReadable();
346 
347   // Write 1 byte to the pipe to make it readable without blocking.
348   WriteByte();
349 
350   // Cancel the watch.
351   controller = nullptr;
352 
353   // No call to ReadableCallback() is expected.
354   WaitAndRunPendingTasks();
355 }
356 
TEST_P(FileDescriptorWatcherTest,DeleteControllerAfterDeleteMessagePumpForIO)357 TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterDeleteMessagePumpForIO) {
358   auto controller = WatchReadable();
359 
360   // Delete the task environment.
361   if (GetParam() ==
362       FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD) {
363     task_environment_.reset();
364   } else {
365     other_thread_.Stop();
366   }
367 
368   // Deleting |controller| shouldn't crash even though that causes a task to be
369   // posted to the message pump thread.
370   controller = nullptr;
371 }
372 
TEST_P(FileDescriptorWatcherTest,WatchReadableOneByteAndWatchReadableTwoBytesOnFd2ClosedInTheMiddle)373 TEST_P(FileDescriptorWatcherTest,
374        WatchReadableOneByteAndWatchReadableTwoBytesOnFd2ClosedInTheMiddle) {
375   auto controller = WatchReadable();
376   auto controller2 = WatchReadable2();
377 
378   // Write 1 byte to the pipe 1 and 2 bytes to the pipe 2. The write fd of the
379   // pipe 2 will be closed before finishing to read 2 bytes. Expect 1 call to
380   // ReadableCallback() and 2 calls to ReadableCallback2() which will each read
381   // 1 byte from the pipes.
382   WriteByte();
383   WriteByte2();
384   WriteByte2();
385 
386   RunLoop run_loop;
387   EXPECT_CALL(mock_, ReadableCallback())
388       .WillOnce(testing::Invoke([this, &controller] {
389         ReadByte();
390         CloseWriteFd2();
391         controller.reset();
392       }));
393   EXPECT_CALL(mock_, ReadableCallback2())
394       .WillOnce(testing::Invoke([this] { ReadByte2(); }))
395       .WillOnce(testing::Invoke([this, &controller2, &run_loop] {
396         ReadByte2();
397         controller2.reset();
398         run_loop.Quit();
399       }));
400   run_loop.Run();
401   testing::Mock::VerifyAndClear(&mock_);
402 
403   // No more call to ReadableCallback() or ReadableCallback2() is expected.
404   WaitAndRunPendingTasks();
405 }
406 
407 INSTANTIATE_TEST_SUITE_P(
408     MessagePumpForIOOnMainThread,
409     FileDescriptorWatcherTest,
410     ::testing::Values(
411         FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD));
412 INSTANTIATE_TEST_SUITE_P(
413     MessagePumpForIOOnOtherThread,
414     FileDescriptorWatcherTest,
415     ::testing::Values(
416         FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD));
417 
418 }  // namespace base
419