Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1410)

Unified Diff: base/task_scheduler/task_tracker_unittest.cc

Issue 1705943002: TaskScheduler [5/9] Task Tracker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s_3_pq
Patch Set: expand tests Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/task_scheduler/task_tracker_unittest.cc
diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d72b4abfc0dc9509507f60757ac710d0abb96cf1
--- /dev/null
+++ b/base/task_scheduler/task_tracker_unittest.cc
@@ -0,0 +1,471 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task_scheduler/task_tracker.h"
+
+#include <queue>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task_scheduler/task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+class ThreadCallingShutdown : public SimpleThread {
+ public:
+ explicit ThreadCallingShutdown(TaskTracker* tracker)
+ : SimpleThread("ThreadCallingShutdown"),
+ tracker_(tracker),
+ has_returned_(false) {}
+
+ // Returns true once the call to Shutdown() has returned.
+ bool has_returned() const { return has_returned_; }
+
+ private:
+ void Run() override {
+ tracker_->Shutdown();
+ has_returned_ = true;
+ }
+
+ TaskTracker* const tracker_;
+ bool has_returned_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown);
+};
+
+class TaskSchedulerTaskTrackerTest
+ : public testing::Test,
+ public ::testing::WithParamInterface<TaskShutdownBehavior> {
gab 2016/03/09 21:53:25 You can use testing::TestWithParam<TaskShutdownBeh
fdoray 2016/03/15 17:28:09 Done.
+ public:
+ TaskSchedulerTaskTrackerTest() : num_tasks_executed_(0) {}
gab 2016/03/09 21:53:25 Can initialize member inline now with C++11 :-) (
fdoray 2016/03/15 17:28:09 Done.
+
+ // Creates a task with |shutdown_behavior|.
+ scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) {
+ return make_scoped_ptr(new Task(
+ FROM_HERE,
+ Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)),
+ TaskTraits().WithShutdownBehavior(shutdown_behavior)));
+ }
+
+ // Tries to post |task| via |tracker_|. If |tracker_| approves the operation,
+ // |task| is added to |posted_tasks_|.
+ void PostTaskViaTracker(scoped_ptr<Task> task) {
+ tracker_.PostTask(
+ Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, Unretained(this)),
+ std::move(task));
+ }
+
+ void RunNextPostedTaskViaTracker() {
gab 2016/03/09 21:53:25 All methods but this one can move to "protected" I
fdoray 2016/03/15 17:28:09 Done.
+ ASSERT_FALSE(posted_tasks_.empty());
+ tracker_.RunTask(posted_tasks_.front().get());
+ posted_tasks_.pop();
+ }
+
+ // Calls tracker_->Shutdown() on a new thread. When this returns, the
+ // Shutdown() method has been entered on the new thread, but it hasn't
+ // necessarily returned.
+ void CallShutdownAsync() {
+ DCHECK(!thread_calling_shutdown_.get());
+ thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_));
+ thread_calling_shutdown_->Start();
+ while (!tracker_.is_shutting_down_for_testing() &&
+ !tracker_.shutdown_completed()) {
+ PlatformThread::YieldCurrentThread();
+ }
+ }
+
+ void JoinAndExpectShutdownAsyncHasReturned() {
gab 2016/03/09 21:53:25 JoinAndExpectAsyncShutdownCompleted() ?
fdoray 2016/03/15 17:28:09 Done. Called it WaitForAsyncShutdownCompleted as y
+ DCHECK(thread_calling_shutdown_.get());
+ thread_calling_shutdown_->Join();
+ EXPECT_TRUE(thread_calling_shutdown_->has_returned());
+ EXPECT_TRUE(tracker_.shutdown_completed());
+ }
+
+ void ExpectShutdownAsyncHasNotReturned() {
gab 2016/03/09 21:53:25 VerifyAsyncShutdownInProgress()?
fdoray 2016/03/15 17:28:09 Done.
+ DCHECK(thread_calling_shutdown_.get());
+ EXPECT_FALSE(thread_calling_shutdown_->has_returned());
gab 2016/03/09 21:53:25 Add EXPECT_TRUE(tracker_.is_shutting_down_for_test
fdoray 2016/03/15 17:28:09 Done.
+ EXPECT_FALSE(tracker_.shutdown_completed());
+ }
+
+ protected:
+ TaskTracker tracker_;
+ size_t num_tasks_executed_;
+ std::queue<scoped_ptr<Task>> posted_tasks_;
+
+ private:
+ void PostTaskCallback(scoped_ptr<Task> task) {
+ posted_tasks_.push(std::move(task));
+ }
+
+ void RunTaskCallback() { ++num_tasks_executed_; }
+
+ scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
+};
+
+// A thread which calls
+// TaskSchedulerTaskTrackerTest::RunNextPostedTaskViaTracker() asynchronously.
+class ThreadRunningNextPostedTask : public SimpleThread {
+ public:
+ explicit ThreadRunningNextPostedTask(TaskSchedulerTaskTrackerTest* test)
+ : SimpleThread("ThreadRunningNextPostedTask"), test_(test) {}
+
+ private:
+ void Run() override { test_->RunNextPostedTaskViaTracker(); }
+
+ TaskSchedulerTaskTrackerTest* const test_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadRunningNextPostedTask);
+};
+
+} // namespace
+
+// This test is repeated for each TaskShutownBehavior.
+TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown) {
robliao 2016/03/09 22:31:46 If the parametrized tests are like the ones here (
fdoray 2016/03/15 17:28:09 Every test is parameterized now.
+ scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(std::move(task_to_post));
+ ASSERT_FALSE(posted_tasks_.empty());
+ EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
+
+ // Run the posted task.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+
+ // Shutdown() shouldn't block.
+ tracker_.Shutdown();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostAndRunLongTaskBeforeShutdown_ContinueOnShutdown) {
+ // Post a CONTINUE_ON_SHUTDOWN task that will block until |event| is signaled.
+ EXPECT_TRUE(posted_tasks_.empty());
+ WaitableEvent event(false, false);
+ PostTaskViaTracker(make_scoped_ptr(
+ new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
+ TaskTraits().WithShutdownBehavior(
+ TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))));
+ ASSERT_FALSE(posted_tasks_.empty());
gab 2016/03/09 21:53:25 Even better than verifying !empty() IMO here and e
fdoray 2016/03/15 17:28:09 Done.
+
+ // Run the task asynchronouly.
+ ThreadRunningNextPostedTask thread(this);
+ thread.Start();
+
+ // Shutdown() shouldn't block.
+ tracker_.Shutdown();
+
+ // Unblock the task.
+ event.Signal();
+ thread.Join();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostAndRunLongTaskBeforeShutdown_SkipOnShutdown) {
+ // Post a SKIP_ON_SHUTDOWN task that will block until |event| is signaled.
+ EXPECT_TRUE(posted_tasks_.empty());
+ WaitableEvent event(false, false);
+ PostTaskViaTracker(make_scoped_ptr(
+ new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
+ TaskTraits().WithShutdownBehavior(
+ TaskShutdownBehavior::SKIP_ON_SHUTDOWN))));
+ ASSERT_FALSE(posted_tasks_.empty());
+
+ // Run the task asynchronouly.
+ ThreadRunningNextPostedTask thread(this);
+ thread.Start();
+
+ // Shutdown() should block until the task has completed its execution.
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock the task.
+ event.Signal();
+ thread.Join();
+
+ // Shutdown() should now return.
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostAndRunLongTaskBeforeShutdown_BlockShutdown) {
+ // Post a BLOCK_SHUTDOWN task that will block until |event| is signaled.
+ EXPECT_TRUE(posted_tasks_.empty());
+ WaitableEvent event(false, false);
+ PostTaskViaTracker(make_scoped_ptr(
+ new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
+ TaskTraits().WithShutdownBehavior(
+ TaskShutdownBehavior::BLOCK_SHUTDOWN))));
+ ASSERT_FALSE(posted_tasks_.empty());
+
+ // Run the task asynchronouly.
+ ThreadRunningNextPostedTask thread(this);
+ thread.Start();
+
+ // Shutdown() should block until the task has completed its execution.
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock the task.
+ event.Signal();
+ thread.Join();
+
+ // Shutdown() should now return.
+ JoinAndExpectShutdownAsyncHasReturned();
+}
gab 2016/03/09 21:53:25 I'm surprised mixing TEST_F with TEST_P even works
fdoray 2016/03/15 17:28:09 Done.
+
+TEST_F(TaskSchedulerTaskTrackerTest,
gab 2016/03/09 21:53:25 Same thing as above for all remaining TEST_F's, tr
fdoray 2016/03/15 17:28:09 Done.
+ PostBeforeShutdownRunDuringShutdown_ContinueOnShutdown) {
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(std::move(task_to_post));
+ ASSERT_FALSE(posted_tasks_.empty());
+ EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
+
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to run task posted at the beginning of this test. It should not work.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(0U, num_tasks_executed_);
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostBeforeShutdownRunDuringShutdown_SkipOnShutdown) {
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(std::move(task_to_post));
+ ASSERT_FALSE(posted_tasks_.empty());
+ EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
+
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to run task posted at the beginning of this test. It should not work.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(0U, num_tasks_executed_);
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostBeforeShutdownRunDuringShutdown_BlockShutdown) {
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(std::move(task_to_post));
+ ASSERT_FALSE(posted_tasks_.empty());
+ EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
+
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to run the first task posted in this test. It should run successfully.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task.
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(2U, num_tasks_executed_);
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostBeforeShutdownRunAfterShutdown_ContinueOnShutdown) {
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(std::move(task_to_post));
+ ASSERT_FALSE(posted_tasks_.empty());
+ ASSERT_EQ(task_to_post_raw, posted_tasks_.front().get());
+
+ // This should return immediately.
+ tracker_.Shutdown();
+
+ // The task shouldn't be allowed to run.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(0U, num_tasks_executed_);
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostBeforeShutdownRunAfterShutdown_SkipOnShutdown) {
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(std::move(task_to_post));
+ ASSERT_FALSE(posted_tasks_.empty());
+ ASSERT_EQ(task_to_post_raw, posted_tasks_.front().get());
+
+ // This should return immediately.
+ tracker_.Shutdown();
+
+ // The task shouldn't be allowed to run.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(0U, num_tasks_executed_);
+}
+
+// It isn't possible to test running after shutdown a task that has been posted
+// before shutdown because Shutdown() won't return until the task has been
+// executed.
+
+TEST_F(TaskSchedulerTaskTrackerTest, RunAfterShutdown_BlockShutdown) {
+ tracker_.Shutdown();
+ EXPECT_DEBUG_DEATH(
+ tracker_.RunTask(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN).get()),
+ "");
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostAndRunDuringShutdown_ContinueOnShutdown) {
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ EXPECT_EQ(1U, posted_tasks_.size());
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to post a CONTINUE_ON_SHUTDOWN task via |tracker_|. This should fail.
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
+ EXPECT_EQ(1U, posted_tasks_.size());
+
+ // Don't try to run the task, because it hasn't been posted successfully.
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ ExpectShutdownAsyncHasNotReturned();
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_SkipOnShutdown) {
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ EXPECT_EQ(1U, posted_tasks_.size());
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to post a SKIP_ON_SHUTDOWN task via |tracker_|. This should fail.
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
+ EXPECT_EQ(1U, posted_tasks_.size());
+
+ // Don't try to run the task, because it hasn't been posted successfully.
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ ExpectShutdownAsyncHasNotReturned();
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_BlockShutdown) {
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ scoped_ptr<Task> block_shutdown_task = std::move(posted_tasks_.front());
+ posted_tasks_.pop();
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to post a BLOCK_SHUTDOWN task via |tracker_|. This should succeed.
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ EXPECT_EQ(1U, posted_tasks_.size());
+
+ // Try to run the task that was just posted. This should succeed.
+ EXPECT_EQ(0U, num_tasks_executed_);
+ RunNextPostedTaskViaTracker();
+ EXPECT_EQ(1U, num_tasks_executed_);
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning
+ // of the test.
+ ExpectShutdownAsyncHasNotReturned();
+ tracker_.RunTask(block_shutdown_task.get());
+ EXPECT_EQ(2U, num_tasks_executed_);
+ JoinAndExpectShutdownAsyncHasReturned();
+}
+
+// This test is repeated for each TaskShutownBehavior.
+TEST_P(TaskSchedulerTaskTrackerTest, PostAfterShutdown) {
+ // It is not possible to post a task after shutdown.
+ tracker_.Shutdown();
+ EXPECT_TRUE(posted_tasks_.empty());
+ PostTaskViaTracker(CreateTask(GetParam()));
+ EXPECT_TRUE(posted_tasks_.empty());
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ContinueOnShutdown,
+ TaskSchedulerTaskTrackerTest,
+ ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
+INSTANTIATE_TEST_CASE_P(
+ SkipOnShutdown,
+ TaskSchedulerTaskTrackerTest,
+ ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
+INSTANTIATE_TEST_CASE_P(
+ BlockShutdown,
+ TaskSchedulerTaskTrackerTest,
+ ::testing::Values(TaskShutdownBehavior::BLOCK_SHUTDOWN));
gab 2016/03/09 21:53:26 Oh nice, first time I see someone do it this way (
fdoray 2016/03/15 17:28:09 Acknowledged.
+
+} // namespace internal
+} // namespace base

Powered by Google App Engine
This is Rietveld 408576698