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