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