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: 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 <> 52 void MessageLoopTest<GlibMessageLoop>::MessageLoopSetUp() { 53 loop_.reset(new GlibMessageLoop()); 54 } 55 56 template <> 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 70 TYPED_TEST(MessageLoopTest, CancelTaskInvalidValuesTest) { 71 EXPECT_FALSE(this->loop_->CancelTask(MessageLoop::kTaskIdNull)); 72 EXPECT_FALSE(this->loop_->CancelTask(1234)); 73 } 74 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. 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 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. 114 TYPED_TEST(MessageLoopTest, PostDelayedTaskWithoutLocation) { 115 this->loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta()); 116 EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100)); 117 } 118 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 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. 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. 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 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 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. 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. 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. 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. 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. 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