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

Unified Diff: chrome/common/cancelable_task_tracker_unittest.cc

Issue 11417077: Rewrite CancelableTaskTracker unit tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 8 years, 1 month 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
« no previous file with comments | « chrome/common/cancelable_task_tracker.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/common/cancelable_task_tracker_unittest.cc
diff --git a/chrome/common/cancelable_task_tracker_unittest.cc b/chrome/common/cancelable_task_tracker_unittest.cc
index c6a7a8583e0cc370deab7bcfd6160087a670045b..4c76fdd825e28ed35263bb44773f04648de01a34 100644
--- a/chrome/common/cancelable_task_tracker_unittest.cc
+++ b/chrome/common/cancelable_task_tracker_unittest.cc
@@ -4,393 +4,435 @@
#include "chrome/common/cancelable_task_tracker.h"
-#include "base/basictypes.h"
+#include <cstddef>
+#include <deque>
+
#include "base/bind.h"
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/waitable_event.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.h"
+#include "base/run_loop.h"
+#include "base/task_runner.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
-using base::Bind;
-using base::Closure;
-using base::Owned;
-using base::TaskRunner;
-using base::Thread;
-using base::Unretained;
-using base::WaitableEvent;
-
namespace {
-class WaitableEventScoper {
+// Test TaskRunner implementation that simply stores posted tasks in a
+// queue.
+//
+// TOOD(akalin): Pull this out into its own file once something else
+// needs it.
+class FakeNonThreadSafeTaskRunner : public base::TaskRunner {
public:
- explicit WaitableEventScoper(WaitableEvent* event) : event_(event) {}
- ~WaitableEventScoper() {
- if (event_)
- event_->Signal();
+ // base::TaskRunner implementation.
+ // Stores posted tasks in a FIFO, ignoring |delay|.
+ virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) OVERRIDE {
+ tasks_.push_back(task);
+ return true;
}
- private:
- WaitableEvent* event_;
- DISALLOW_COPY_AND_ASSIGN(WaitableEventScoper);
-};
-class CancelableTaskTrackerTest : public testing::Test {
- protected:
- CancelableTaskTrackerTest()
- : task_id_(CancelableTaskTracker::kBadTaskId),
- test_data_(0),
- task_thread_start_event_(true, false) {}
-
- virtual void SetUp() {
- task_thread_.reset(new Thread("task thread"));
- client_thread_.reset(new Thread("client thread"));
- task_thread_->Start();
- client_thread_->Start();
-
- task_thread_runner_ = task_thread_->message_loop_proxy();
- client_thread_runner_ = client_thread_->message_loop_proxy();
-
- // Create tracker on client thread.
- WaitableEvent tracker_created(true, false);
- client_thread_runner_->PostTask(
- FROM_HERE,
- Bind(&CancelableTaskTrackerTest::CreateTrackerOnClientThread,
- Unretained(this), &tracker_created));
- tracker_created.Wait();
-
- // Block server thread so we can prepare the test.
- task_thread_runner_->PostTask(
- FROM_HERE,
- Bind(&WaitableEvent::Wait, Unretained(&task_thread_start_event_)));
+ virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
+ return true;
}
- virtual void TearDown() {
- UnblockTaskThread();
-
- // Destroy tracker on client thread.
- WaitableEvent tracker_destroyed(true, false);
- client_thread_runner_->PostTask(
- FROM_HERE,
- Bind(&CancelableTaskTrackerTest::DestroyTrackerOnClientThread,
- Unretained(this), &tracker_destroyed));
-
- // This will also wait for any pending tasks on client thread.
- tracker_destroyed.Wait();
-
- client_thread_->Stop();
- task_thread_->Stop();
+ size_t GetPendingTaskCount() const {
+ return tasks_.size();
}
- void RunOnClientAndWait(
- void (*func)(CancelableTaskTrackerTest*, WaitableEvent*)) {
- WaitableEvent event(true, false);
- client_thread_runner_->PostTask(FROM_HERE,
- Bind(func, Unretained(this), &event));
- event.Wait();
+ void RunUntilIdle() {
+ // Use a while loop since a task may post more tasks.
+ while (!tasks_.empty()) {
+ base::Closure task = tasks_.front();
+ tasks_.pop_front();
+ task.Run();
+ }
}
- public:
- // Client thread posts tasks and runs replies.
- scoped_refptr<TaskRunner> client_thread_runner_;
+ protected:
+ virtual ~FakeNonThreadSafeTaskRunner() {}
- // Task thread runs tasks.
- scoped_refptr<TaskRunner> task_thread_runner_;
+ private:
+ std::deque<base::Closure> tasks_;
+};
- // |tracker_| can only live on client thread.
- scoped_ptr<CancelableTaskTracker> tracker_;
+class CancelableTaskTrackerTest : public testing::Test {
+ protected:
+ virtual ~CancelableTaskTrackerTest() {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
- CancelableTaskTracker::TaskId task_id_;
+ CancelableTaskTracker task_tracker_;
- void UnblockTaskThread() {
- task_thread_start_event_.Signal();
- }
+ private:
+ // Needed by CancelableTaskTracker methods.
+ MessageLoop message_loop_;
+};
- //////////////////////////////////////////////////////////////////////////////
- // Testing data and related functions
- int test_data_; // Defaults to 0.
+void AddFailureAt(const tracked_objects::Location& location) {
+ ADD_FAILURE_AT(location.file_name(), location.line_number());
+}
- Closure IncreaseTestDataAndSignalClosure(WaitableEvent* event) {
- return Bind(&CancelableTaskTrackerTest::IncreaseDataAndSignal,
- &test_data_, event);
- }
+// Returns a closure that fails if run.
+base::Closure MakeExpectedNotRunClosure(
+ const tracked_objects::Location& location) {
+ return base::Bind(&AddFailureAt, location);
+}
- Closure IncreaseTestDataIfNotCanceledAndSignalClosure(
- const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb,
- WaitableEvent* event) {
- return Bind(&CancelableTaskTrackerTest::IncreaseDataIfNotCanceledAndSignal,
- &test_data_, is_canceled_cb, event);
+// A helper class for MakeExpectedRunClosure() that fails if it is
+// destroyed without Run() having been called. This class may be used
+// from multiple threads as long as Run() is called at most once
+// before destruction.
+class RunChecker {
+ public:
+ explicit RunChecker(const tracked_objects::Location& location)
+ : location_(location),
+ called_(false) {}
+
+ ~RunChecker() {
+ if (!called_) {
+ ADD_FAILURE_AT(location_.file_name(), location_.line_number());
+ }
}
- Closure DecreaseTestDataClosure(WaitableEvent* event) {
- return Bind(&CancelableTaskTrackerTest::DecreaseData,
- Owned(new WaitableEventScoper(event)), &test_data_);
+ void Run() {
+ called_ = true;
}
private:
- void CreateTrackerOnClientThread(WaitableEvent* event) {
- tracker_.reset(new CancelableTaskTracker());
- event->Signal();
- }
-
- void DestroyTrackerOnClientThread(WaitableEvent* event) {
- tracker_.reset();
- event->Signal();
- }
+ tracked_objects::Location location_;
+ bool called_;
+};
- static void IncreaseDataAndSignal(int* data, WaitableEvent* event) {
- (*data)++;
- if (event)
- event->Signal();
- }
+// Returns a closure that fails on destruction if it hasn't been run.
+base::Closure MakeExpectedRunClosure(
+ const tracked_objects::Location& location) {
+ return base::Bind(&RunChecker::Run, base::Owned(new RunChecker(location)));
+}
- static void IncreaseDataIfNotCanceledAndSignal(
- int* data,
- const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb,
- WaitableEvent* event) {
- if (!is_canceled_cb.Run())
- (*data)++;
- if (event)
- event->Signal();
- }
+// With the task tracker, post a task, a task with a reply, and get a
+// new task id without canceling any of them. The tasks and the reply
+// should run and the "is canceled" callback should return false.
+TEST_F(CancelableTaskTrackerTest, NoCancel) {
+ base::Thread worker_thread("worker thread");
+ ASSERT_TRUE(worker_thread.Start());
- static void DecreaseData(WaitableEventScoper* event_scoper, int* data) {
- (*data) -= 2;
- }
+ ignore_result(
+ task_tracker_.PostTask(
+ worker_thread.message_loop_proxy(),
+ FROM_HERE,
+ MakeExpectedRunClosure(FROM_HERE)));
- scoped_ptr<Thread> client_thread_;
- scoped_ptr<Thread> task_thread_;
+ ignore_result(
+ task_tracker_.PostTaskAndReply(
+ worker_thread.message_loop_proxy(),
+ FROM_HERE,
+ MakeExpectedRunClosure(FROM_HERE),
+ MakeExpectedRunClosure(FROM_HERE)));
- WaitableEvent task_thread_start_event_;
-};
+ CancelableTaskTracker::IsCanceledCallback is_canceled;
+ ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
-#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+ worker_thread.Stop();
-typedef CancelableTaskTrackerTest CancelableTaskTrackerDeathTest;
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
-TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
- // The default style "fast" does not support multi-threaded tests.
- ::testing::FLAGS_gtest_death_test_style = "threadsafe";
-
- EXPECT_DEATH(
- tracker_->PostTask(task_thread_runner_,
- FROM_HERE,
- DecreaseTestDataClosure(NULL)),
- "");
+ EXPECT_FALSE(is_canceled.Run());
}
-void CancelOnDifferentThread_Test(CancelableTaskTrackerTest* test,
- WaitableEvent* event) {
- test->task_id_ = test->tracker_->PostTask(
- test->task_thread_runner_,
- FROM_HERE,
- test->DecreaseTestDataClosure(event));
- EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+// Post a task with the task tracker but cancel it before running the
+// task runner. The task should not run.
+TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
- // Canceling a non-existed task is noop.
- test->tracker_->TryCancel(test->task_id_ + 1);
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.PostTask(
+ fake_task_runner.get(),
+ FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE));
+ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- test->UnblockTaskThread();
-}
+ EXPECT_EQ(1U, fake_task_runner->GetPendingTaskCount());
-TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
- // The default style "fast" does not support multi-threaded tests.
- ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ task_tracker_.TryCancel(task_id);
- // Post a task and we'll try canceling it on a different thread.
- RunOnClientAndWait(&CancelOnDifferentThread_Test);
+ fake_task_runner->RunUntilIdle();
+}
- // Canceling on the wrong thread.
- EXPECT_DEATH(tracker_->TryCancel(task_id_), "");
+// Post a task with reply with the task tracker and cancel it before
+// running the task runner. Neither the task nor the reply should
+// run.
+TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
- // Even canceling a non-existant task will crash.
- EXPECT_DEATH(tracker_->TryCancel(task_id_ + 1), "");
-}
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.PostTaskAndReply(
+ fake_task_runner.get(),
+ FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE),
+ MakeExpectedNotRunClosure(FROM_HERE));
+ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
-void TrackerCancelAllOnDifferentThread_Test(
- CancelableTaskTrackerTest* test, WaitableEvent* event) {
- test->task_id_ = test->tracker_->PostTask(
- test->task_thread_runner_,
- FROM_HERE,
- test->DecreaseTestDataClosure(event));
- EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
- test->UnblockTaskThread();
+ task_tracker_.TryCancel(task_id);
+
+ fake_task_runner->RunUntilIdle();
}
-TEST_F(CancelableTaskTrackerDeathTest, TrackerCancelAllOnDifferentThread) {
- // The default style "fast" does not support multi-threaded tests.
- ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+// Post a task with reply with the task tracker and cancel it after
+// running the task runner but before running the current message
+// loop. The task should run but the reply should not.
+TEST_F(CancelableTaskTrackerTest, CancelReply) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
- // |tracker_| can only live on client thread.
- EXPECT_DEATH(tracker_.reset(), "");
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.PostTaskAndReply(
+ fake_task_runner.get(),
+ FROM_HERE,
+ MakeExpectedRunClosure(FROM_HERE),
+ MakeExpectedNotRunClosure(FROM_HERE));
+ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- RunOnClientAndWait(&TrackerCancelAllOnDifferentThread_Test);
+ fake_task_runner->RunUntilIdle();
- EXPECT_DEATH(tracker_->TryCancelAll(), "");
- EXPECT_DEATH(tracker_.reset(), "");
+ task_tracker_.TryCancel(task_id);
}
-#endif // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) &&
- // GTEST_HAS_DEATH_TEST
+// Post a task with reply with the task tracker on a worker thread and
+// cancel it before running the current message loop. The task should
+// run but the reply should not.
+TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
+ base::Thread worker_thread("worker thread");
+ ASSERT_TRUE(worker_thread.Start());
-void Canceled_Test(CancelableTaskTrackerTest* test, WaitableEvent* event) {
- test->task_id_ = test->tracker_->PostTask(
- test->task_thread_runner_,
- FROM_HERE,
- test->DecreaseTestDataClosure(event));
- EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.PostTaskAndReply(
+ worker_thread.message_loop_proxy(),
+ FROM_HERE,
+ base::Bind(&base::DoNothing),
+ MakeExpectedNotRunClosure(FROM_HERE));
+ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- test->tracker_->TryCancel(test->task_id_);
- test->UnblockTaskThread();
-}
+ task_tracker_.TryCancel(task_id);
-TEST_F(CancelableTaskTrackerTest, Canceled) {
- RunOnClientAndWait(&Canceled_Test);
- EXPECT_EQ(0, test_data_);
+ worker_thread.Stop();
}
-void SignalAndWaitThenIncrease(WaitableEvent* start_event,
- WaitableEvent* continue_event,
- int* data) {
- start_event->Signal();
- continue_event->Wait();
- (*data)++;
+void ExpectIsCanceled(
+ const CancelableTaskTracker::IsCanceledCallback& is_canceled,
+ bool expected_is_canceled) {
+ EXPECT_EQ(expected_is_canceled, is_canceled.Run());
}
-void CancelWhileTaskRunning_Test(CancelableTaskTrackerTest* test,
- WaitableEvent* event) {
- WaitableEvent task_start_event(true, false);
- WaitableEvent* task_continue_event = new WaitableEvent(true, false);
+// Create a new task ID and check its status on a separate thread
+// before and after canceling. The is-canceled callback should be
+// thread-safe (i.e., nothing should blow up).
+TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
+ CancelableTaskTracker::IsCanceledCallback is_canceled;
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.NewTrackedTaskId(&is_canceled);
- test->task_id_ = test->tracker_->PostTaskAndReply(
- test->task_thread_runner_,
- FROM_HERE,
- Bind(&SignalAndWaitThenIncrease,
- &task_start_event, Owned(task_continue_event), &test->test_data_),
- test->DecreaseTestDataClosure(event));
- EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+ EXPECT_FALSE(is_canceled.Run());
- test->UnblockTaskThread();
- task_start_event.Wait();
+ base::Thread other_thread("other thread");
+ ASSERT_TRUE(other_thread.Start());
+ other_thread.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&ExpectIsCanceled, is_canceled, false));
+ other_thread.Stop();
- // Now task is running. Let's try to cancel.
- test->tracker_->TryCancel(test->task_id_);
+ task_tracker_.TryCancel(task_id);
- // Let task continue.
- task_continue_event->Signal();
+ ASSERT_TRUE(other_thread.Start());
+ other_thread.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&ExpectIsCanceled, is_canceled, true));
+ other_thread.Stop();
}
-TEST_F(CancelableTaskTrackerTest, CancelWhileTaskRunning) {
- RunOnClientAndWait(&CancelWhileTaskRunning_Test);
+// With the task tracker, post a task, a task with a reply, get a new
+// task id, and then cancel all of them. None of the tasks nor the
+// reply should run and the "is canceled" callback should return
+// true.
+TEST_F(CancelableTaskTrackerTest, CancelAll) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
- // Task will continue running but reply will be canceled.
- EXPECT_EQ(1, test_data_);
-}
+ ignore_result(
+ task_tracker_.PostTask(
+ fake_task_runner,
+ FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE)));
-void NotCanceled_Test(CancelableTaskTrackerTest* test, WaitableEvent* event) {
- test->task_id_ = test->tracker_->PostTaskAndReply(
- test->task_thread_runner_,
- FROM_HERE,
- test->IncreaseTestDataAndSignalClosure(NULL),
- test->DecreaseTestDataClosure(event));
- EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+ ignore_result(
+ task_tracker_.PostTaskAndReply(
+ fake_task_runner,
+ FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE),
+ MakeExpectedNotRunClosure(FROM_HERE)));
- test->UnblockTaskThread();
-}
+ CancelableTaskTracker::IsCanceledCallback is_canceled;
+ ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
-TEST_F(CancelableTaskTrackerTest, NotCanceled) {
- RunOnClientAndWait(&NotCanceled_Test);
- EXPECT_EQ(-1, test_data_);
-}
+ task_tracker_.TryCancelAll();
-void TrackerDestructed_Test(CancelableTaskTrackerTest* test,
- WaitableEvent* event) {
- test->task_id_ = test->tracker_->PostTaskAndReply(
- test->task_thread_runner_,
- FROM_HERE,
- test->IncreaseTestDataAndSignalClosure(NULL),
- test->DecreaseTestDataClosure(event));
- EXPECT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+ fake_task_runner->RunUntilIdle();
- test->tracker_.reset();
- test->UnblockTaskThread();
-}
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
-TEST_F(CancelableTaskTrackerTest, TrackerDestructed) {
- RunOnClientAndWait(&TrackerDestructed_Test);
- EXPECT_EQ(0, test_data_);
+ EXPECT_TRUE(is_canceled.Run());
}
-void TrackerDestructedAfterTask_Test(CancelableTaskTrackerTest* test,
- WaitableEvent* event) {
- WaitableEvent task_done_event(true, false);
- test->task_id_ = test->tracker_->PostTaskAndReply(
- test->task_thread_runner_,
- FROM_HERE,
- test->IncreaseTestDataAndSignalClosure(&task_done_event),
- test->DecreaseTestDataClosure(event));
- ASSERT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+// With the task tracker, post a task, a task with a reply, get a new
+// task id, and then cancel all of them. None of the tasks nor the
+// reply should run and the "is canceled" callback should return
+// true.
+TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
+
+ CancelableTaskTracker::IsCanceledCallback is_canceled;
+
+ {
+ // Create another task tracker with a smaller scope.
+ CancelableTaskTracker task_tracker;
+
+ ignore_result(
+ task_tracker.PostTask(
+ fake_task_runner,
+ FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE)));
+
+ ignore_result(
+ task_tracker.PostTaskAndReply(
+ fake_task_runner,
+ FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE),
+ MakeExpectedNotRunClosure(FROM_HERE)));
+
+ ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+ }
- test->UnblockTaskThread();
+ fake_task_runner->RunUntilIdle();
- task_done_event.Wait();
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
- // At this point, task is already finished on task thread but reply has not
- // started yet (because this function is still running on client thread).
- // Now delete the tracker to cancel reply.
- test->tracker_.reset();
+ EXPECT_FALSE(is_canceled.Run());
}
-TEST_F(CancelableTaskTrackerTest, TrackerDestructedAfterTask) {
- RunOnClientAndWait(&TrackerDestructedAfterTask_Test);
- EXPECT_EQ(1, test_data_);
-}
+// The death tests below make sure that calling task tracker member
+// functions from a thread different from its owner thread DCHECKs in
+// debug mode.
-void CheckTrackedTaskIdOnSameThread_Test(CancelableTaskTrackerTest* test,
- WaitableEvent* event) {
- CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
- test->task_id_ = test->tracker_->NewTrackedTaskId(&is_canceled_cb);
- ASSERT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
+ protected:
+ CancelableTaskTrackerDeathTest() {
+ // The default style "fast" does not support multi-threaded tests.
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ }
- EXPECT_FALSE(is_canceled_cb.Run());
+ virtual ~CancelableTaskTrackerDeathTest() {}
+};
- test->tracker_->TryCancel(test->task_id_);
- EXPECT_TRUE(is_canceled_cb.Run());
+// Duplicated from base/threading/thread_checker.h so that we can be
+// good citizens there and undef the macro.
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+// Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
+void MaybeRunDeadlyTaskTrackerMemberFunction(
+ CancelableTaskTracker* task_tracker,
+ const base::Callback<void(CancelableTaskTracker*)>& fn) {
+ // CancelableTask uses DCHECKs with its ThreadChecker (itself only
+ // enabled in debug mode).
+#if ENABLE_THREAD_CHECKER
+ EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
+#endif
+}
- test->task_id_ = test->tracker_->NewTrackedTaskId(&is_canceled_cb);
- EXPECT_FALSE(is_canceled_cb.Run());
+void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
+ ignore_result(
+ task_tracker->PostTask(
+ scoped_refptr<FakeNonThreadSafeTaskRunner>(
+ new FakeNonThreadSafeTaskRunner()),
+ FROM_HERE, base::Bind(&base::DoNothing)));
+}
- // Destroy tracker will cancel all tasks.
- test->tracker_.reset();
- EXPECT_TRUE(is_canceled_cb.Run());
+TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
+ base::Thread bad_thread("bad thread");
+ ASSERT_TRUE(bad_thread.Start());
- event->Signal();
+ bad_thread.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ base::Unretained(&task_tracker_),
+ base::Bind(&PostDoNothingTask)));
}
-TEST_F(CancelableTaskTrackerTest, CheckTrackedTaskIdOnSameThread) {
- RunOnClientAndWait(&CheckTrackedTaskIdOnSameThread_Test);
+void TryCancel(CancelableTaskTracker::TaskId task_id,
+ CancelableTaskTracker* task_tracker) {
+ task_tracker->TryCancel(task_id);
}
-void CheckTrackedTaskIdOnDifferentThread_Test(CancelableTaskTrackerTest* test,
- WaitableEvent* event) {
- CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
- test->task_id_ = test->tracker_->NewTrackedTaskId(&is_canceled_cb);
- ASSERT_NE(CancelableTaskTracker::kBadTaskId, test->task_id_);
+TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
+
+ base::Thread bad_thread("bad thread");
+ ASSERT_TRUE(bad_thread.Start());
- // Post task to task thread.
- test->task_thread_runner_->PostTask(
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.PostTask(
+ fake_task_runner.get(),
+ FROM_HERE,
+ base::Bind(&base::DoNothing));
+ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+ bad_thread.message_loop_proxy()->PostTask(
FROM_HERE,
- test->IncreaseTestDataIfNotCanceledAndSignalClosure(is_canceled_cb,
- event));
- is_canceled_cb.Reset(); // So the one in task thread runner is the last ref,
- // and will be destroyed on task thread.
+ base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ base::Unretained(&task_tracker_),
+ base::Bind(&TryCancel, task_id)));
- test->tracker_->TryCancel(test->task_id_);
- test->UnblockTaskThread();
+ fake_task_runner->RunUntilIdle();
}
-TEST_F(CancelableTaskTrackerTest, CheckTrackedTaskIdOnDifferentThread) {
- RunOnClientAndWait(&CheckTrackedTaskIdOnDifferentThread_Test);
- EXPECT_EQ(0, test_data_);
+TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
+ scoped_refptr<FakeNonThreadSafeTaskRunner> fake_task_runner(
+ new FakeNonThreadSafeTaskRunner());
+
+ base::Thread bad_thread("bad thread");
+ ASSERT_TRUE(bad_thread.Start());
+
+ CancelableTaskTracker::TaskId task_id =
+ task_tracker_.PostTask(
+ fake_task_runner.get(),
+ FROM_HERE,
+ base::Bind(&base::DoNothing));
+ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+ bad_thread.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ base::Unretained(&task_tracker_),
+ base::Bind(&CancelableTaskTracker::TryCancelAll)));
+
+ fake_task_runner->RunUntilIdle();
}
} // namespace
« no previous file with comments | « chrome/common/cancelable_task_tracker.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698