Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/task_scheduler/task_tracker.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/macros.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/task_scheduler/task.h" | |
| 11 #include "base/task_scheduler/task_traits.h" | |
| 12 #include "base/threading/platform_thread.h" | |
| 13 #include "base/threading/simple_thread.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 namespace base { | |
|
robliao
2016/03/01 22:29:42
I think you need a test case where we block shutdo
fdoray
2016/03/02 00:38:41
Done. PostAndRunBlockedContinueOnShutdownTaskBefor
| |
| 17 namespace internal { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 class ThreadCallingShutdown : public SimpleThread { | |
| 22 public: | |
| 23 explicit ThreadCallingShutdown(TaskTracker* tracker) | |
| 24 : SimpleThread("ThreadCallingShutdown"), | |
| 25 tracker_(tracker), | |
| 26 has_returned_(false) {} | |
| 27 | |
| 28 // Returns true once the call to Shutdown() has returned. | |
| 29 bool has_returned() const { return has_returned_; } | |
| 30 | |
| 31 private: | |
| 32 void Run() override { | |
| 33 tracker_->Shutdown(); | |
| 34 has_returned_ = true; | |
| 35 } | |
| 36 | |
| 37 TaskTracker* tracker_; | |
| 38 bool has_returned_; | |
| 39 | |
| 40 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown); | |
| 41 }; | |
| 42 | |
| 43 class TaskSchedulerTaskTrackerTest : public testing::Test { | |
| 44 protected: | |
| 45 TaskSchedulerTaskTrackerTest() : num_run_tasks_(0) {} | |
| 46 | |
| 47 // Creates a task with |shutdown_behavior|. | |
| 48 scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) { | |
| 49 return make_scoped_ptr(new Task( | |
| 50 FROM_HERE, | |
| 51 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)), | |
| 52 TaskTraits().WithShutdownBehavior(shutdown_behavior))); | |
| 53 } | |
| 54 | |
| 55 // Tries to post |task| via |tracker_|. If |tracker_| approves the operation, | |
| 56 // returns the posted task. Otherwise, returns nullptr. | |
| 57 scoped_ptr<Task> PostTaskViaTracker(scoped_ptr<Task> task) { | |
| 58 scoped_ptr<Task> posted_task; | |
| 59 tracker_.PostTask(Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, | |
| 60 Unretained(this), &posted_task), | |
| 61 std::move(task)); | |
| 62 return posted_task; | |
|
gab
2016/03/01 22:18:47
This feels very weird... how about instead have a
fdoray
2016/03/02 00:38:41
Done. I now use an std::queue.
| |
| 63 } | |
| 64 | |
| 65 // Calls tracker_->Shutdown() on a new thread. When this returns, the | |
| 66 // Shutdown() method has been entered on the new thread, but it hasn't | |
| 67 // necessarily returned. | |
| 68 void CallShutdownAsync() { | |
| 69 DCHECK(!thread_calling_shutdown_.get()); | |
| 70 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_)); | |
| 71 thread_calling_shutdown_->Start(); | |
| 72 while (!tracker_.is_shutting_down_for_testing() && | |
| 73 !tracker_.shutdown_completed()) { | |
| 74 PlatformThread::YieldCurrentThread(); | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 void ExpectShutdownAsyncHasReturned() { | |
| 79 DCHECK(thread_calling_shutdown_.get()); | |
| 80 thread_calling_shutdown_->Join(); | |
|
robliao
2016/03/01 22:29:42
It would be unexpected to join with the duality be
fdoray
2016/03/02 00:38:41
Done.
| |
| 81 EXPECT_TRUE(thread_calling_shutdown_->has_returned()); | |
| 82 EXPECT_TRUE(tracker_.shutdown_completed()); | |
| 83 } | |
| 84 | |
| 85 void ExpectShutdownAsyncHasNotReturned() { | |
| 86 DCHECK(thread_calling_shutdown_.get()); | |
| 87 EXPECT_FALSE(thread_calling_shutdown_->has_returned()); | |
| 88 EXPECT_FALSE(tracker_.shutdown_completed()); | |
| 89 } | |
| 90 | |
| 91 TaskTracker tracker_; | |
| 92 size_t num_run_tasks_; | |
|
gab
2016/03/01 22:18:47
num_tasks_executed_ ?
fdoray
2016/03/02 00:38:41
Done.
| |
| 93 | |
| 94 private: | |
| 95 void PostTaskCallback(scoped_ptr<Task>* out_task, scoped_ptr<Task> in_task) { | |
| 96 *out_task = std::move(in_task); | |
| 97 } | |
| 98 | |
| 99 void RunTaskCallback() { ++num_run_tasks_; } | |
| 100 | |
| 101 scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_; | |
| 102 | |
| 103 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest); | |
| 104 }; | |
| 105 | |
| 106 } // namespace | |
| 107 | |
| 108 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 109 PostAndRunBeforeShutdown_ContinueOnShutdown) { | |
| 110 scoped_ptr<Task> task_to_post( | |
| 111 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
| 112 const Task* task_to_post_raw = task_to_post.get(); | |
| 113 | |
| 114 // Post the task. | |
| 115 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 116 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 117 | |
| 118 // Run the posted task. | |
| 119 tracker_.RunTask(posted_task.get()); | |
| 120 EXPECT_EQ(1U, num_run_tasks_); | |
|
gab
2016/03/01 22:18:47
EXPECT_EQ(0U, ...); as well before RunTask()?
fdoray
2016/03/02 00:38:41
Done.
| |
| 121 | |
| 122 // Shutdown() shouldn't block. | |
| 123 tracker_.Shutdown(); | |
| 124 } | |
| 125 | |
| 126 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown_SkipOnShutdown) { | |
| 127 scoped_ptr<Task> task_to_post( | |
| 128 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
| 129 const Task* task_to_post_raw = task_to_post.get(); | |
| 130 | |
| 131 // Post the task. | |
| 132 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 133 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 134 | |
| 135 // Run the posted task. | |
| 136 tracker_.RunTask(posted_task.get()); | |
| 137 EXPECT_EQ(1U, num_run_tasks_); | |
| 138 | |
| 139 // Shutdown() shouldn't block. | |
| 140 tracker_.Shutdown(); | |
| 141 } | |
| 142 | |
| 143 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown_BlockShutdown) { | |
| 144 scoped_ptr<Task> task_to_post( | |
| 145 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
| 146 const Task* task_to_post_raw = task_to_post.get(); | |
| 147 | |
| 148 // Post the task. | |
| 149 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 150 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 151 | |
| 152 // Run the posted task. | |
| 153 tracker_.RunTask(posted_task.get()); | |
| 154 EXPECT_EQ(1U, num_run_tasks_); | |
| 155 | |
| 156 // Shutdown() shouldn't block. | |
| 157 tracker_.Shutdown(); | |
| 158 } | |
| 159 | |
| 160 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 161 PostBeforeShutdownRunDuringShutdown_ContinueOnShutdown) { | |
| 162 scoped_ptr<Task> task_to_post( | |
| 163 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
| 164 const Task* task_to_post_raw = task_to_post.get(); | |
| 165 | |
| 166 // Post the task. | |
| 167 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 168 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 169 | |
| 170 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
| 171 // asynchronously. | |
| 172 scoped_ptr<Task> blocking_task( | |
| 173 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
| 174 CallShutdownAsync(); | |
| 175 ExpectShutdownAsyncHasNotReturned(); | |
| 176 | |
| 177 // Try to run |posted_task| via |tracker_|. It should not run. | |
| 178 tracker_.RunTask(posted_task.get()); | |
| 179 EXPECT_EQ(0U, num_run_tasks_); | |
| 180 ExpectShutdownAsyncHasNotReturned(); | |
| 181 | |
| 182 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
| 183 tracker_.RunTask(blocking_task.get()); | |
| 184 EXPECT_EQ(1U, num_run_tasks_); | |
| 185 ExpectShutdownAsyncHasReturned(); | |
| 186 } | |
| 187 | |
| 188 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 189 PostBeforeShutdownRunDuringShutdown_SkipOnShutdown) { | |
| 190 scoped_ptr<Task> task_to_post( | |
| 191 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
| 192 const Task* task_to_post_raw = task_to_post.get(); | |
| 193 | |
| 194 // Post the task. | |
| 195 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 196 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 197 | |
| 198 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
| 199 // asynchronously. | |
| 200 scoped_ptr<Task> blocking_task( | |
| 201 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
| 202 CallShutdownAsync(); | |
| 203 ExpectShutdownAsyncHasNotReturned(); | |
| 204 | |
| 205 // Try to run |posted_task| via |tracker_|. It should not run. | |
| 206 tracker_.RunTask(posted_task.get()); | |
| 207 EXPECT_EQ(0U, num_run_tasks_); | |
| 208 ExpectShutdownAsyncHasNotReturned(); | |
| 209 | |
| 210 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
| 211 tracker_.RunTask(blocking_task.get()); | |
| 212 EXPECT_EQ(1U, num_run_tasks_); | |
| 213 ExpectShutdownAsyncHasReturned(); | |
| 214 } | |
| 215 | |
| 216 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 217 PostBeforeShutdownRunDuringShutdown_BlockShutdown) { | |
| 218 scoped_ptr<Task> task_to_post( | |
| 219 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
| 220 const Task* task_to_post_raw = task_to_post.get(); | |
| 221 | |
| 222 // Post the task. | |
| 223 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 224 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 225 | |
| 226 // Call Shutdown() asynchronously. It should block before there is a pending | |
| 227 // BLOCK_SHUTDOWN task. | |
| 228 CallShutdownAsync(); | |
| 229 ExpectShutdownAsyncHasNotReturned(); | |
| 230 | |
| 231 // Run the posted task. | |
| 232 tracker_.RunTask(posted_task.get()); | |
| 233 EXPECT_EQ(1U, num_run_tasks_); | |
| 234 | |
| 235 // The async call to Shutdown() should now return. | |
| 236 ExpectShutdownAsyncHasReturned(); | |
| 237 } | |
| 238 | |
| 239 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 240 PostBeforeShutdownRunAfterShutdown_ContinueOnShutdown) { | |
| 241 scoped_ptr<Task> task_to_post( | |
| 242 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
| 243 const Task* task_to_post_raw = task_to_post.get(); | |
| 244 | |
| 245 // Post the task. | |
| 246 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 247 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 248 | |
| 249 // A call to Shutdown() should return immediately. | |
| 250 tracker_.Shutdown(); | |
| 251 | |
| 252 // Try to run |posted_task| via |tracker_|. It should not run. | |
| 253 tracker_.RunTask(posted_task.get()); | |
| 254 EXPECT_EQ(0U, num_run_tasks_); | |
| 255 } | |
| 256 | |
| 257 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 258 PostBeforeShutdownRunAfterShutdown_SkipOnShutdown) { | |
| 259 scoped_ptr<Task> task_to_post( | |
| 260 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
| 261 const Task* task_to_post_raw = task_to_post.get(); | |
| 262 | |
| 263 // Post the task. | |
| 264 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 265 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 266 | |
| 267 // A call to Shutdown() should return immediately. | |
| 268 tracker_.Shutdown(); | |
| 269 | |
| 270 // Try to run |posted_task| via |tracker_|. It should not run. | |
| 271 tracker_.RunTask(posted_task.get()); | |
| 272 EXPECT_EQ(0U, num_run_tasks_); | |
| 273 } | |
| 274 | |
| 275 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 276 PostBeforeShutdownRunAfterShutdown_BlockShutdown) { | |
|
robliao
2016/03/01 22:29:42
I'm not sure this test should be here as it's not
fdoray
2016/03/02 00:38:41
Now I test that we get the expected failure with E
| |
| 277 // It is not possible to run after shutdown a BLOCK_SHUTDOWN task that has | |
| 278 // been posted before shutdown because Shutdown() won't return when there are | |
| 279 // pending BLOCK_SHUTDOWN tasks. | |
|
gab
2016/03/01 22:18:47
I think your code actually handles this (+ a DCHEC
fdoray
2016/03/02 00:38:41
Done.
| |
| 280 } | |
| 281 | |
| 282 TEST_F(TaskSchedulerTaskTrackerTest, | |
| 283 PostAndRunDuringShutdown_ContinueOnShutdown) { | |
| 284 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
| 285 // asynchronously. | |
| 286 scoped_ptr<Task> blocking_task( | |
| 287 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
| 288 CallShutdownAsync(); | |
| 289 ExpectShutdownAsyncHasNotReturned(); | |
| 290 | |
| 291 // Try to post a CONTINUE_ON_SHUTDOWN task via |tracker_|. It should not work. | |
| 292 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
| 293 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)) | |
| 294 .get()); | |
| 295 | |
| 296 // Since |tracker_| hasn't allowed the task to be posted, it can't be run. | |
| 297 | |
| 298 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
| 299 ExpectShutdownAsyncHasNotReturned(); | |
| 300 tracker_.RunTask(blocking_task.get()); | |
| 301 EXPECT_EQ(1U, num_run_tasks_); | |
| 302 ExpectShutdownAsyncHasReturned(); | |
| 303 } | |
| 304 | |
| 305 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_SkipOnShutdown) { | |
| 306 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
| 307 // asynchronously. | |
| 308 scoped_ptr<Task> blocking_task( | |
| 309 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
| 310 CallShutdownAsync(); | |
| 311 ExpectShutdownAsyncHasNotReturned(); | |
| 312 | |
| 313 // Try to post a SKIP_ON_SHUTDOWN task via |tracker_|. It should not work. | |
| 314 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
| 315 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)) | |
| 316 .get()); | |
| 317 | |
| 318 // Since |tracker_| hasn't allowed the task to be posted, it can't be run. | |
| 319 | |
| 320 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
| 321 ExpectShutdownAsyncHasNotReturned(); | |
| 322 tracker_.RunTask(blocking_task.get()); | |
| 323 EXPECT_EQ(1U, num_run_tasks_); | |
| 324 ExpectShutdownAsyncHasReturned(); | |
| 325 } | |
| 326 | |
| 327 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_BlockShutdown) { | |
| 328 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
| 329 // asynchronously. | |
| 330 scoped_ptr<Task> blocking_task( | |
| 331 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
| 332 CallShutdownAsync(); | |
| 333 ExpectShutdownAsyncHasNotReturned(); | |
| 334 | |
| 335 // Post a BLOCK_SHUTDOWN task via |tracker_|. | |
| 336 scoped_ptr<Task> task_to_post( | |
| 337 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
| 338 const Task* task_to_post_raw = task_to_post.get(); | |
| 339 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
| 340 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
| 341 | |
| 342 // Run |posted_task| via |tracker_|. | |
| 343 tracker_.RunTask(posted_task.get()); | |
| 344 EXPECT_EQ(1U, num_run_tasks_); | |
| 345 ExpectShutdownAsyncHasNotReturned(); | |
| 346 | |
| 347 // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning | |
| 348 // of the test. | |
| 349 tracker_.RunTask(blocking_task.get()); | |
| 350 EXPECT_EQ(2U, num_run_tasks_); | |
| 351 ExpectShutdownAsyncHasReturned(); | |
| 352 } | |
| 353 | |
| 354 TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_ContinueOnShutdown) { | |
| 355 // It is not possible to post a task after shutdown. | |
| 356 tracker_.Shutdown(); | |
| 357 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
| 358 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)) | |
| 359 .get()); | |
| 360 } | |
| 361 | |
| 362 TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_SkipOnShutdown) { | |
| 363 // It is not possible to post a task after shutdown. | |
| 364 tracker_.Shutdown(); | |
| 365 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
| 366 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)) | |
| 367 .get()); | |
| 368 } | |
| 369 | |
| 370 TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_BlockShutdown) { | |
| 371 // It is not possible to post a task after shutdown. | |
| 372 tracker_.Shutdown(); | |
| 373 EXPECT_EQ(nullptr, | |
| 374 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)) | |
| 375 .get()); | |
| 376 } | |
|
gab
2016/03/01 22:18:47
To avoid the triad duplication for every test, how
robliao
2016/03/01 22:36:41
Duplication for tests should be okay. Given that w
fdoray
2016/03/02 00:38:41
I think it's a good idea to use a typed test to re
gab
2016/03/09 21:53:25
+1 to Francois' argument, readability is improved
| |
| 377 | |
| 378 } // namespace internal | |
| 379 } // namespace base | |
| OLD | NEW |