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