1 // Copyright 2015 The Chromium OS 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 <brillo/message_loops/message_loop.h>
6
7 // These are the common tests for all the brillo::MessageLoop implementations
8 // that should conform to this interface's contracts. For extra
9 // implementation-specific tests see the particular implementation unittests in
10 // the *_unittest.cc files.
11
12 #include <memory>
13 #include <vector>
14
15 #include <base/bind.h>
16 #include <base/location.h>
17 #include <base/posix/eintr_wrapper.h>
18 #include <gtest/gtest.h>
19
20 #include <brillo/bind_lambda.h>
21 #include <brillo/unittest_utils.h>
22 #include <brillo/message_loops/base_message_loop.h>
23 #include <brillo/message_loops/glib_message_loop.h>
24 #include <brillo/message_loops/message_loop_utils.h>
25
26 using base::Bind;
27 using base::TimeDelta;
28
29 namespace brillo {
30
31 using TaskId = MessageLoop::TaskId;
32
33 template <typename T>
34 class MessageLoopTest : public ::testing::Test {
35 protected:
SetUp()36 void SetUp() override {
37 MessageLoopSetUp();
38 EXPECT_TRUE(this->loop_.get());
39 }
40
41 std::unique_ptr<base::MessageLoopForIO> base_loop_;
42
43 std::unique_ptr<MessageLoop> loop_;
44
45 private:
46 // These MessageLoopSetUp() methods are used to setup each MessageLoop
47 // according to its constructor requirements.
48 void MessageLoopSetUp();
49 };
50
51 template <>
MessageLoopSetUp()52 void MessageLoopTest<GlibMessageLoop>::MessageLoopSetUp() {
53 loop_.reset(new GlibMessageLoop());
54 }
55
56 template <>
MessageLoopSetUp()57 void MessageLoopTest<BaseMessageLoop>::MessageLoopSetUp() {
58 base_loop_.reset(new base::MessageLoopForIO());
59 loop_.reset(new BaseMessageLoop(base::MessageLoopForIO::current()));
60 }
61
62 // This setups gtest to run each one of the following TYPED_TEST test cases on
63 // on each implementation.
64 typedef ::testing::Types<
65 GlibMessageLoop,
66 BaseMessageLoop> MessageLoopTypes;
67 TYPED_TEST_CASE(MessageLoopTest, MessageLoopTypes);
68
69
TYPED_TEST(MessageLoopTest,CancelTaskInvalidValuesTest)70 TYPED_TEST(MessageLoopTest, CancelTaskInvalidValuesTest) {
71 EXPECT_FALSE(this->loop_->CancelTask(MessageLoop::kTaskIdNull));
72 EXPECT_FALSE(this->loop_->CancelTask(1234));
73 }
74
TYPED_TEST(MessageLoopTest,PostTaskTest)75 TYPED_TEST(MessageLoopTest, PostTaskTest) {
76 bool called = false;
77 TaskId task_id = this->loop_->PostTask(FROM_HERE,
78 Bind([&called]() { called = true; }));
79 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
80 MessageLoopRunMaxIterations(this->loop_.get(), 100);
81 EXPECT_TRUE(called);
82 }
83
84 // Tests that we can cancel tasks right after we schedule them.
TYPED_TEST(MessageLoopTest,PostTaskCancelledTest)85 TYPED_TEST(MessageLoopTest, PostTaskCancelledTest) {
86 bool called = false;
87 TaskId task_id = this->loop_->PostTask(FROM_HERE,
88 Bind([&called]() { called = true; }));
89 EXPECT_TRUE(this->loop_->CancelTask(task_id));
90 MessageLoopRunMaxIterations(this->loop_.get(), 100);
91 EXPECT_FALSE(called);
92 // Can't remove a task you already removed.
93 EXPECT_FALSE(this->loop_->CancelTask(task_id));
94 }
95
TYPED_TEST(MessageLoopTest,PostDelayedTaskRunsEventuallyTest)96 TYPED_TEST(MessageLoopTest, PostDelayedTaskRunsEventuallyTest) {
97 bool called = false;
98 TaskId task_id = this->loop_->PostDelayedTask(
99 FROM_HERE,
100 Bind([&called]() { called = true; }),
101 TimeDelta::FromMilliseconds(50));
102 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
103 MessageLoopRunUntil(this->loop_.get(),
104 TimeDelta::FromSeconds(10),
105 Bind([&called]() { return called; }));
106 // Check that the main loop finished before the 10 seconds timeout, so it
107 // finished due to the callback being called and not due to the timeout.
108 EXPECT_TRUE(called);
109 }
110
111 // Test that you can call the overloaded version of PostDelayedTask from
112 // MessageLoop. This is important because only one of the two methods is
113 // virtual, so you need to unhide the other when overriding the virtual one.
TYPED_TEST(MessageLoopTest,PostDelayedTaskWithoutLocation)114 TYPED_TEST(MessageLoopTest, PostDelayedTaskWithoutLocation) {
115 this->loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta());
116 EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
117 }
118
TYPED_TEST(MessageLoopTest,WatchForInvalidFD)119 TYPED_TEST(MessageLoopTest, WatchForInvalidFD) {
120 bool called = false;
121 EXPECT_EQ(MessageLoop::kTaskIdNull, this->loop_->WatchFileDescriptor(
122 FROM_HERE, -1, MessageLoop::kWatchRead, true,
123 Bind([&called] { called = true; })));
124 EXPECT_EQ(MessageLoop::kTaskIdNull, this->loop_->WatchFileDescriptor(
125 FROM_HERE, -1, MessageLoop::kWatchWrite, true,
126 Bind([&called] { called = true; })));
127 EXPECT_EQ(0, MessageLoopRunMaxIterations(this->loop_.get(), 100));
128 EXPECT_FALSE(called);
129 }
130
TYPED_TEST(MessageLoopTest,CancelWatchedFileDescriptor)131 TYPED_TEST(MessageLoopTest, CancelWatchedFileDescriptor) {
132 ScopedPipe pipe;
133 bool called = false;
134 TaskId task_id = this->loop_->WatchFileDescriptor(
135 FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
136 Bind([&called] { called = true; }));
137 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
138 // The reader end is blocked because we didn't write anything to the writer
139 // end.
140 EXPECT_EQ(0, MessageLoopRunMaxIterations(this->loop_.get(), 100));
141 EXPECT_FALSE(called);
142 EXPECT_TRUE(this->loop_->CancelTask(task_id));
143 }
144
145 // When you watch a file descriptor for reading, the guaranties are that a
146 // blocking call to read() on that file descriptor will not block. This should
147 // include the case when the other end of a pipe is closed or the file is empty.
TYPED_TEST(MessageLoopTest,WatchFileDescriptorTriggersWhenPipeClosed)148 TYPED_TEST(MessageLoopTest, WatchFileDescriptorTriggersWhenPipeClosed) {
149 ScopedPipe pipe;
150 bool called = false;
151 EXPECT_EQ(0, HANDLE_EINTR(close(pipe.writer)));
152 pipe.writer = -1;
153 TaskId task_id = this->loop_->WatchFileDescriptor(
154 FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
155 Bind([&called] { called = true; }));
156 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
157 // The reader end is not blocked because we closed the writer end so a read on
158 // the reader end would return 0 bytes read.
159 EXPECT_NE(0, MessageLoopRunMaxIterations(this->loop_.get(), 10));
160 EXPECT_TRUE(called);
161 EXPECT_TRUE(this->loop_->CancelTask(task_id));
162 }
163
164 // When a WatchFileDescriptor task is scheduled with |persistent| = true, we
165 // should keep getting a call whenever the file descriptor is ready.
TYPED_TEST(MessageLoopTest,WatchFileDescriptorPersistently)166 TYPED_TEST(MessageLoopTest, WatchFileDescriptorPersistently) {
167 ScopedPipe pipe;
168 EXPECT_EQ(1, HANDLE_EINTR(write(pipe.writer, "a", 1)));
169
170 int called = 0;
171 TaskId task_id = this->loop_->WatchFileDescriptor(
172 FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
173 Bind([&called] { called++; }));
174 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
175 // We let the main loop run for 20 iterations to give it enough iterations to
176 // verify that our callback was called more than one. We only check that our
177 // callback is called more than once.
178 EXPECT_EQ(20, MessageLoopRunMaxIterations(this->loop_.get(), 20));
179 EXPECT_LT(1, called);
180 EXPECT_TRUE(this->loop_->CancelTask(task_id));
181 }
182
TYPED_TEST(MessageLoopTest,WatchFileDescriptorNonPersistent)183 TYPED_TEST(MessageLoopTest, WatchFileDescriptorNonPersistent) {
184 ScopedPipe pipe;
185 EXPECT_EQ(1, HANDLE_EINTR(write(pipe.writer, "a", 1)));
186
187 int called = 0;
188 TaskId task_id = this->loop_->WatchFileDescriptor(
189 FROM_HERE, pipe.reader, MessageLoop::kWatchRead, false,
190 Bind([&called] { called++; }));
191 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
192 // We let the main loop run for 20 iterations but we just expect it to run
193 // at least once. The callback should be called exactly once since we
194 // scheduled it non-persistently. After it ran, we shouldn't be able to cancel
195 // this task.
196 EXPECT_LT(0, MessageLoopRunMaxIterations(this->loop_.get(), 20));
197 EXPECT_EQ(1, called);
198 EXPECT_FALSE(this->loop_->CancelTask(task_id));
199 }
200
TYPED_TEST(MessageLoopTest,WatchFileDescriptorForReadAndWriteSimultaneously)201 TYPED_TEST(MessageLoopTest, WatchFileDescriptorForReadAndWriteSimultaneously) {
202 ScopedSocketPair socks;
203 EXPECT_EQ(1, HANDLE_EINTR(write(socks.right, "a", 1)));
204 // socks.left should be able to read this "a" and should also be able to write
205 // without blocking since the kernel has some buffering for it.
206
207 TaskId read_task_id = this->loop_->WatchFileDescriptor(
208 FROM_HERE, socks.left, MessageLoop::kWatchRead, true,
209 Bind([this, &read_task_id] {
210 EXPECT_TRUE(this->loop_->CancelTask(read_task_id))
211 << "task_id" << read_task_id;
212 }));
213 EXPECT_NE(MessageLoop::kTaskIdNull, read_task_id);
214
215 TaskId write_task_id = this->loop_->WatchFileDescriptor(
216 FROM_HERE, socks.left, MessageLoop::kWatchWrite, true,
217 Bind([this, &write_task_id] {
218 EXPECT_TRUE(this->loop_->CancelTask(write_task_id));
219 }));
220 EXPECT_NE(MessageLoop::kTaskIdNull, write_task_id);
221
222 EXPECT_LT(0, MessageLoopRunMaxIterations(this->loop_.get(), 20));
223
224 EXPECT_FALSE(this->loop_->CancelTask(read_task_id));
225 EXPECT_FALSE(this->loop_->CancelTask(write_task_id));
226 }
227
228 // Test that we can cancel the task we are running, and should just fail.
TYPED_TEST(MessageLoopTest,DeleteTaskFromSelf)229 TYPED_TEST(MessageLoopTest, DeleteTaskFromSelf) {
230 bool cancel_result = true; // We would expect this to be false.
231 MessageLoop* loop_ptr = this->loop_.get();
232 TaskId task_id;
233 task_id = this->loop_->PostTask(
234 FROM_HERE,
235 Bind([&cancel_result, loop_ptr, &task_id]() {
236 cancel_result = loop_ptr->CancelTask(task_id);
237 }));
238 EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
239 EXPECT_FALSE(cancel_result);
240 }
241
242 // Test that we can cancel a non-persistent file descriptor watching callback,
243 // which should fail.
TYPED_TEST(MessageLoopTest,DeleteNonPersistenIOTaskFromSelf)244 TYPED_TEST(MessageLoopTest, DeleteNonPersistenIOTaskFromSelf) {
245 ScopedPipe pipe;
246 TaskId task_id = this->loop_->WatchFileDescriptor(
247 FROM_HERE, pipe.writer, MessageLoop::kWatchWrite, false /* persistent */,
248 Bind([this, &task_id] {
249 EXPECT_FALSE(this->loop_->CancelTask(task_id));
250 task_id = MessageLoop::kTaskIdNull;
251 }));
252 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
253 EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
254 EXPECT_EQ(MessageLoop::kTaskIdNull, task_id);
255 }
256
257 // Test that we can cancel a persistent file descriptor watching callback from
258 // the same callback.
TYPED_TEST(MessageLoopTest,DeletePersistenIOTaskFromSelf)259 TYPED_TEST(MessageLoopTest, DeletePersistenIOTaskFromSelf) {
260 ScopedPipe pipe;
261 TaskId task_id = this->loop_->WatchFileDescriptor(
262 FROM_HERE, pipe.writer, MessageLoop::kWatchWrite, true /* persistent */,
263 Bind([this, &task_id] {
264 EXPECT_TRUE(this->loop_->CancelTask(task_id));
265 task_id = MessageLoop::kTaskIdNull;
266 }));
267 EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
268 EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
269 EXPECT_EQ(MessageLoop::kTaskIdNull, task_id);
270 }
271
272 // Test that we can cancel several persistent file descriptor watching callbacks
273 // from a scheduled callback. In the BaseMessageLoop implementation, this code
274 // will cause us to cancel an IOTask that has a pending delayed task, but
275 // otherwise is a valid test case on all implementations.
TYPED_TEST(MessageLoopTest,DeleteAllPersistenIOTaskFromSelf)276 TYPED_TEST(MessageLoopTest, DeleteAllPersistenIOTaskFromSelf) {
277 const int kNumTasks = 5;
278 ScopedPipe pipes[kNumTasks];
279 TaskId task_ids[kNumTasks];
280
281 for (int i = 0; i < kNumTasks; ++i) {
282 task_ids[i] = this->loop_->WatchFileDescriptor(
283 FROM_HERE, pipes[i].writer, MessageLoop::kWatchWrite,
284 true /* persistent */,
285 Bind([this, &task_ids] {
286 for (int j = 0; j < kNumTasks; ++j) {
287 // Once we cancel all the tasks, none should run, so this code runs
288 // only once from one callback.
289 EXPECT_TRUE(this->loop_->CancelTask(task_ids[j]));
290 task_ids[j] = MessageLoop::kTaskIdNull;
291 }
292 }));
293 }
294 MessageLoopRunMaxIterations(this->loop_.get(), 100);
295 for (int i = 0; i < kNumTasks; ++i) {
296 EXPECT_EQ(MessageLoop::kTaskIdNull, task_ids[i]);
297 }
298 }
299
300 // Test that if there are several tasks watching for file descriptors to be
301 // available or simply waiting in the message loop are fairly scheduled to run.
302 // In other words, this test ensures that having a file descriptor always
303 // available doesn't prevent other file descriptors watching tasks or delayed
304 // tasks to be dispatched, causing starvation.
TYPED_TEST(MessageLoopTest,AllTasksAreEqual)305 TYPED_TEST(MessageLoopTest, AllTasksAreEqual) {
306 int total_calls = 0;
307
308 // First, schedule a repeating timeout callback to run from the main loop.
309 int timeout_called = 0;
310 base::Closure timeout_callback;
311 MessageLoop::TaskId timeout_task;
312 timeout_callback = base::Bind(
313 [this, &timeout_called, &total_calls, &timeout_callback, &timeout_task] {
314 timeout_called++;
315 total_calls++;
316 timeout_task = this->loop_->PostTask(FROM_HERE, Bind(timeout_callback));
317 if (total_calls > 100)
318 this->loop_->BreakLoop();
319 });
320 timeout_task = this->loop_->PostTask(FROM_HERE, timeout_callback);
321
322 // Second, schedule several file descriptor watchers.
323 const int kNumTasks = 3;
324 ScopedPipe pipes[kNumTasks];
325 MessageLoop::TaskId tasks[kNumTasks];
326
327 int reads[kNumTasks] = {};
328 auto fd_callback = [this, &pipes, &reads, &total_calls](int i) {
329 reads[i]++;
330 total_calls++;
331 char c;
332 EXPECT_EQ(1, HANDLE_EINTR(read(pipes[i].reader, &c, 1)));
333 if (total_calls > 100)
334 this->loop_->BreakLoop();
335 };
336
337 for (int i = 0; i < kNumTasks; ++i) {
338 tasks[i] = this->loop_->WatchFileDescriptor(
339 FROM_HERE, pipes[i].reader, MessageLoop::kWatchRead,
340 true /* persistent */,
341 Bind(fd_callback, i));
342 // Make enough bytes available on each file descriptor. This should not
343 // block because we set the size of the file descriptor buffer when
344 // creating it.
345 std::vector<char> blob(1000, 'a');
346 EXPECT_EQ(blob.size(),
347 HANDLE_EINTR(write(pipes[i].writer, blob.data(), blob.size())));
348 }
349 this->loop_->Run();
350 EXPECT_GT(total_calls, 100);
351 // We run the loop up 100 times and expect each callback to run at least 10
352 // times. A good scheduler should balance these callbacks.
353 EXPECT_GE(timeout_called, 10);
354 EXPECT_TRUE(this->loop_->CancelTask(timeout_task));
355 for (int i = 0; i < kNumTasks; ++i) {
356 EXPECT_GE(reads[i], 10) << "Reading from pipes[" << i << "], fd "
357 << pipes[i].reader;
358 EXPECT_TRUE(this->loop_->CancelTask(tasks[i]));
359 }
360 }
361
362 } // namespace brillo
363