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