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
26using base::Bind;
27using base::TimeDelta;
28
29namespace brillo {
30
31using TaskId = MessageLoop::TaskId;
32
33template <typename T>
34class MessageLoopTest : public ::testing::Test {
35 protected:
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
51template <>
52void MessageLoopTest<GlibMessageLoop>::MessageLoopSetUp() {
53  loop_.reset(new GlibMessageLoop());
54}
55
56template <>
57void 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.
64typedef ::testing::Types<
65  GlibMessageLoop,
66  BaseMessageLoop> MessageLoopTypes;
67TYPED_TEST_CASE(MessageLoopTest, MessageLoopTypes);
68
69
70TYPED_TEST(MessageLoopTest, CancelTaskInvalidValuesTest) {
71  EXPECT_FALSE(this->loop_->CancelTask(MessageLoop::kTaskIdNull));
72  EXPECT_FALSE(this->loop_->CancelTask(1234));
73}
74
75TYPED_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.
85TYPED_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
96TYPED_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.
114TYPED_TEST(MessageLoopTest, PostDelayedTaskWithoutLocation) {
115  this->loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta());
116  EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
117}
118
119TYPED_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
131TYPED_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.
148TYPED_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.
166TYPED_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
183TYPED_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
201TYPED_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.
229TYPED_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.
244TYPED_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.
259TYPED_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.
276TYPED_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, kNumTasks, &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.
305TYPED_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