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

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: fix PostTask comment 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..a45f15777d3fccde742d8f0582075f87fc8c2037
--- /dev/null
+++ b/base/task_scheduler/task_tracker_unittest.cc
@@ -0,0 +1,379 @@
+// 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 "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.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 {
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
+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* tracker_;
+ bool has_returned_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown);
+};
+
+class TaskSchedulerTaskTrackerTest : public testing::Test {
+ protected:
+ TaskSchedulerTaskTrackerTest() : num_run_tasks_(0) {}
+
+ // 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,
+ // returns the posted task. Otherwise, returns nullptr.
+ scoped_ptr<Task> PostTaskViaTracker(scoped_ptr<Task> task) {
+ scoped_ptr<Task> posted_task;
+ tracker_.PostTask(Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback,
+ Unretained(this), &posted_task),
+ std::move(task));
+ 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.
+ }
+
+ // 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 ExpectShutdownAsyncHasReturned() {
+ DCHECK(thread_calling_shutdown_.get());
+ 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.
+ EXPECT_TRUE(thread_calling_shutdown_->has_returned());
+ EXPECT_TRUE(tracker_.shutdown_completed());
+ }
+
+ void ExpectShutdownAsyncHasNotReturned() {
+ DCHECK(thread_calling_shutdown_.get());
+ EXPECT_FALSE(thread_calling_shutdown_->has_returned());
+ EXPECT_FALSE(tracker_.shutdown_completed());
+ }
+
+ TaskTracker tracker_;
+ size_t num_run_tasks_;
gab 2016/03/01 22:18:47 num_tasks_executed_ ?
fdoray 2016/03/02 00:38:41 Done.
+
+ private:
+ void PostTaskCallback(scoped_ptr<Task>* out_task, scoped_ptr<Task> in_task) {
+ *out_task = std::move(in_task);
+ }
+
+ void RunTaskCallback() { ++num_run_tasks_; }
+
+ scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
+};
+
+} // namespace
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostAndRunBeforeShutdown_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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Run the posted task.
+ tracker_.RunTask(posted_task.get());
+ 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.
+
+ // Shutdown() shouldn't block.
+ tracker_.Shutdown();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown_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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Run the posted task.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+
+ // Shutdown() shouldn't block.
+ tracker_.Shutdown();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown_BlockShutdown) {
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+
+ // Post the task.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Run the posted task.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+
+ // Shutdown() shouldn't block.
+ tracker_.Shutdown();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ 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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ scoped_ptr<Task> blocking_task(
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to run |posted_task| via |tracker_|. It should not run.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(0U, num_run_tasks_);
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ tracker_.RunTask(blocking_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+ ExpectShutdownAsyncHasReturned();
+}
+
+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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ scoped_ptr<Task> blocking_task(
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to run |posted_task| via |tracker_|. It should not run.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(0U, num_run_tasks_);
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ tracker_.RunTask(blocking_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+ ExpectShutdownAsyncHasReturned();
+}
+
+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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Call Shutdown() asynchronously. It should block before there is a pending
+ // BLOCK_SHUTDOWN task.
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Run the posted task.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+
+ // The async call to Shutdown() should now return.
+ ExpectShutdownAsyncHasReturned();
+}
+
+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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // A call to Shutdown() should return immediately.
+ tracker_.Shutdown();
+
+ // Try to run |posted_task| via |tracker_|. It should not run.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(0U, num_run_tasks_);
+}
+
+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.
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // A call to Shutdown() should return immediately.
+ tracker_.Shutdown();
+
+ // Try to run |posted_task| via |tracker_|. It should not run.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(0U, num_run_tasks_);
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ 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
+ // It is not possible to run after shutdown a BLOCK_SHUTDOWN task that has
+ // been posted before shutdown because Shutdown() won't return when there are
+ // 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.
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest,
+ PostAndRunDuringShutdown_ContinueOnShutdown) {
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ scoped_ptr<Task> blocking_task(
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to post a CONTINUE_ON_SHUTDOWN task via |tracker_|. It should not work.
+ EXPECT_EQ(nullptr, PostTaskViaTracker(
+ CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))
+ .get());
+
+ // Since |tracker_| hasn't allowed the task to be posted, it can't be run.
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ ExpectShutdownAsyncHasNotReturned();
+ tracker_.RunTask(blocking_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+ ExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_SkipOnShutdown) {
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ scoped_ptr<Task> blocking_task(
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Try to post a SKIP_ON_SHUTDOWN task via |tracker_|. It should not work.
+ EXPECT_EQ(nullptr, PostTaskViaTracker(
+ CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN))
+ .get());
+
+ // Since |tracker_| hasn't allowed the task to be posted, it can't be run.
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task.
+ ExpectShutdownAsyncHasNotReturned();
+ tracker_.RunTask(blocking_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+ ExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_BlockShutdown) {
+ // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
+ // asynchronously.
+ scoped_ptr<Task> blocking_task(
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)));
+ CallShutdownAsync();
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Post a BLOCK_SHUTDOWN task via |tracker_|.
+ scoped_ptr<Task> task_to_post(
+ CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
+ const Task* task_to_post_raw = task_to_post.get();
+ scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post)));
+ ASSERT_EQ(task_to_post_raw, posted_task.get());
+
+ // Run |posted_task| via |tracker_|.
+ tracker_.RunTask(posted_task.get());
+ EXPECT_EQ(1U, num_run_tasks_);
+ ExpectShutdownAsyncHasNotReturned();
+
+ // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning
+ // of the test.
+ tracker_.RunTask(blocking_task.get());
+ EXPECT_EQ(2U, num_run_tasks_);
+ ExpectShutdownAsyncHasReturned();
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_ContinueOnShutdown) {
+ // It is not possible to post a task after shutdown.
+ tracker_.Shutdown();
+ EXPECT_EQ(nullptr, PostTaskViaTracker(
+ CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))
+ .get());
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_SkipOnShutdown) {
+ // It is not possible to post a task after shutdown.
+ tracker_.Shutdown();
+ EXPECT_EQ(nullptr, PostTaskViaTracker(
+ CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN))
+ .get());
+}
+
+TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_BlockShutdown) {
+ // It is not possible to post a task after shutdown.
+ tracker_.Shutdown();
+ EXPECT_EQ(nullptr,
+ PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))
+ .get());
+}
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
+
+} // namespace internal
+} // namespace base

Powered by Google App Engine
This is Rietveld 408576698