Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Side by Side Diff: base/files/file_descriptor_watcher_posix_unittest.cc

Issue 2332923004: Add a new file descriptor watch API. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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:
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
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_ = MakeUnique<FileDescriptorWatcher>(
73 reinterpret_cast<MessageLoopForIO*>(message_loop_for_io));
dcheng 2016/09/14 06:48:19 static_cast should work and look slightly less sca
fdoray 2016/09/14 17:06:14 Done.
74 }
75
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 EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[0])));
85 EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[1])));
86 }
87
88 protected:
89 int read_file_descriptor() const { return pipe_fds_[0]; }
90 int write_file_descriptor() const { return pipe_fds_[1]; }
91
92 // Waits for a short delay and run pending tasks.
93 void WaitAndRunPendingTasks() {
94 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
95 RunLoop().RunUntilIdle();
96 }
97
98 // Registers ReadableCallback() to be called on |mock_| when
99 // read_file_descriptor() is readable without blocking.
100 std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable() {
101 std::unique_ptr<FileDescriptorWatcher::Controller> controller =
102 FileDescriptorWatcher::WatchReadable(
103 read_file_descriptor(),
104 Bind(&Mock::ReadableCallback, Unretained(&mock_)));
105 EXPECT_TRUE(controller);
106
107 // Unless read_file_descriptor() was readable before the callback was
108 // registered, this shouldn't do anything.
109 WaitAndRunPendingTasks();
110
111 return controller;
112 }
113
114 // Registers WritableCallback() to be called on |mock_| when
115 // write_file_descriptor() is writable without blocking.
116 std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable() {
117 std::unique_ptr<FileDescriptorWatcher::Controller> controller =
118 FileDescriptorWatcher::WatchWritable(
119 read_file_descriptor(),
120 Bind(&Mock::WritableCallback, Unretained(&mock_)));
121 EXPECT_TRUE(controller);
122 return controller;
123 }
124
125 void WriteByte() {
126 constexpr char kByte = '!';
127 ASSERT_TRUE(
128 WriteFileDescriptor(write_file_descriptor(), &kByte, sizeof(kByte)));
129 }
130
131 void ReadByte() {
132 // This is always called as part of the WatchReadable() callback, which
133 // should run on the main thread.
134 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
135
136 char buffer;
137 ASSERT_TRUE(ReadFromFD(read_file_descriptor(), &buffer, sizeof(buffer)));
138 }
139
140 // Mock on wich callbacks are invoked.
141 testing::StrictMock<Mock> mock_;
142
143 // MessageLoop bound to the main thread.
144 std::unique_ptr<MessageLoop> message_loop_;
145
146 // Thread running a MessageLoopForIO. Used when the test type is
147 // MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD.
148 Thread other_thread_;
149
150 private:
151 // Determines which MessageLoopForIO is used to watch file descriptors for
152 // which callbacks are registered on the main thread.
153 std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
154
155 // Watched file descriptors.
156 int pipe_fds_[2];
157
158 // Used to verify that callbacks run on the thread on which they are
159 // registered.
160 ThreadCheckerImpl thread_checker_;
161
162 DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcherTest);
163 };
164
165 } // namespace
166
167 TEST_P(FileDescriptorWatcherTest, WatchWritable) {
168 auto controller = WatchWritable();
169
170 // On Mac and iOS, the write end of a newly created pipe is writable without
171 // blocking.
172 #if defined(OS_MACOSX)
173 RunLoop run_loop;
174 EXPECT_CALL(mock_, WritableCallback())
175 .WillOnce(testing::Invoke(&run_loop, &RunLoop::Quit));
176 run_loop.Run();
177 #endif // defined(OS_MACOSX)
178 }
179
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
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
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
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
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
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
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
OLDNEW
« base/files/file_descriptor_watcher_posix.cc ('K') | « base/files/file_descriptor_watcher_posix.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698