| 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 | 
|  |