| Index: chrome/browser/after_startup_task_utils_unittest.cc
|
| diff --git a/chrome/browser/after_startup_task_utils_unittest.cc b/chrome/browser/after_startup_task_utils_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bc6971d779a2cb634c194240fc9c19103217a851
|
| --- /dev/null
|
| +++ b/chrome/browser/after_startup_task_utils_unittest.cc
|
| @@ -0,0 +1,199 @@
|
| +// Copyright 2015 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 "chrome/browser/after_startup_task_utils.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/message_loop/message_loop_proxy.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/task_runner_util.h"
|
| +#include "base/threading/thread.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using base::RunLoop;
|
| +using content::BrowserThread;
|
| +using content::TestBrowserThreadBundle;
|
| +
|
| +namespace {
|
| +
|
| +class WrappedTaskRunner : public base::TaskRunner {
|
| + public:
|
| + explicit WrappedTaskRunner(const scoped_refptr<TaskRunner>& real_runner)
|
| + : real_task_runner_(real_runner) {}
|
| +
|
| + bool PostDelayedTask(const tracked_objects::Location& from_here,
|
| + const base::Closure& task,
|
| + base::TimeDelta delay) override {
|
| + ++posted_task_count_;
|
| + return real_task_runner_->PostDelayedTask(
|
| + from_here, base::Bind(&WrappedTaskRunner::RunWrappedTask, this, task),
|
| + base::TimeDelta()); // Squash all delays so our tests complete asap.
|
| + }
|
| +
|
| + bool RunsTasksOnCurrentThread() const override {
|
| + return real_task_runner_->RunsTasksOnCurrentThread();
|
| + }
|
| +
|
| + base::TaskRunner* real_runner() const { return real_task_runner_.get(); }
|
| +
|
| + int total_task_count() const { return posted_task_count_ + ran_task_count_; }
|
| + int posted_task_count() const { return posted_task_count_; }
|
| + int ran_task_count() const { return ran_task_count_; }
|
| +
|
| + void reset_task_counts() {
|
| + posted_task_count_ = 0;
|
| + ran_task_count_ = 0;
|
| + }
|
| +
|
| + private:
|
| + ~WrappedTaskRunner() override {}
|
| +
|
| + void RunWrappedTask(const base::Closure& task) {
|
| + ++ran_task_count_;
|
| + task.Run();
|
| + }
|
| +
|
| + scoped_refptr<TaskRunner> real_task_runner_;
|
| + int posted_task_count_ = 0;
|
| + int ran_task_count_ = 0;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class AfterStartupTaskTest : public testing::Test {
|
| + public:
|
| + AfterStartupTaskTest()
|
| + : browser_thread_bundle_(TestBrowserThreadBundle::REAL_DB_THREAD) {
|
| + ui_thread_ = new WrappedTaskRunner(
|
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI));
|
| + db_thread_ = new WrappedTaskRunner(
|
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
|
| + AfterStartupTaskUtils::UnsafeResetForTesting();
|
| + }
|
| +
|
| + // Hop to the db thread and call IsBrowserStartupComplete.
|
| + bool GetIsBrowserStartupCompleteFromDBThread() {
|
| + RunLoop run_loop;
|
| + bool is_complete;
|
| + base::PostTaskAndReplyWithResult(
|
| + db_thread_->real_runner(), FROM_HERE,
|
| + base::Bind(&AfterStartupTaskUtils::IsBrowserStartupComplete),
|
| + base::Bind(&AfterStartupTaskTest::GotIsOnBrowserStartupComplete,
|
| + &run_loop, &is_complete));
|
| + run_loop.Run();
|
| + return is_complete;
|
| + }
|
| +
|
| + // Hop to the db thread and call PostAfterStartupTask.
|
| + void PostAfterStartupTaskFromDBThread(
|
| + const tracked_objects::Location& from_here,
|
| + const scoped_refptr<base::TaskRunner>& task_runner,
|
| + const base::Closure& task) {
|
| + RunLoop run_loop;
|
| + db_thread_->real_runner()->PostTaskAndReply(
|
| + FROM_HERE, base::Bind(&AfterStartupTaskUtils::PostTask, from_here,
|
| + task_runner, task),
|
| + base::Bind(&RunLoop::Quit, base::Unretained(&run_loop)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + // Make sure all tasks posted to the DB thread get run.
|
| + void FlushDBThread() {
|
| + RunLoop run_loop;
|
| + db_thread_->real_runner()->PostTaskAndReply(
|
| + FROM_HERE, base::Bind(&base::DoNothing),
|
| + base::Bind(&RunLoop::Quit, base::Unretained(&run_loop)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + static void VerifyExpectedThread(BrowserThread::ID id) {
|
| + EXPECT_TRUE(BrowserThread::CurrentlyOn(id));
|
| + }
|
| +
|
| + protected:
|
| + scoped_refptr<WrappedTaskRunner> ui_thread_;
|
| + scoped_refptr<WrappedTaskRunner> db_thread_;
|
| +
|
| + private:
|
| + static void GotIsOnBrowserStartupComplete(RunLoop* loop,
|
| + bool* out,
|
| + bool is_complete) {
|
| + *out = is_complete;
|
| + loop->Quit();
|
| + }
|
| +
|
| + TestBrowserThreadBundle browser_thread_bundle_;
|
| +};
|
| +
|
| +TEST_F(AfterStartupTaskTest, IsStartupComplete) {
|
| + // Check IsBrowserStartupComplete on a background thread first to
|
| + // verify that it does not allocate the underlying flag on that thread.
|
| + // That allocation thread correctness part of this test relies on
|
| + // the DCHECK in CancellationFlag::Set().
|
| + EXPECT_FALSE(GetIsBrowserStartupCompleteFromDBThread());
|
| + EXPECT_FALSE(AfterStartupTaskUtils::IsBrowserStartupComplete());
|
| + AfterStartupTaskUtils::SetBrowserStartupIsComplete();
|
| + EXPECT_TRUE(AfterStartupTaskUtils::IsBrowserStartupComplete());
|
| + EXPECT_TRUE(GetIsBrowserStartupCompleteFromDBThread());
|
| +}
|
| +
|
| +TEST_F(AfterStartupTaskTest, PostTask) {
|
| + // Nothing should be posted prior to startup completion.
|
| + EXPECT_FALSE(AfterStartupTaskUtils::IsBrowserStartupComplete());
|
| + AfterStartupTaskUtils::PostTask(
|
| + FROM_HERE, ui_thread_,
|
| + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread,
|
| + BrowserThread::UI));
|
| + AfterStartupTaskUtils::PostTask(
|
| + FROM_HERE, db_thread_,
|
| + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread,
|
| + BrowserThread::DB));
|
| + PostAfterStartupTaskFromDBThread(
|
| + FROM_HERE, ui_thread_,
|
| + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread,
|
| + BrowserThread::UI));
|
| + PostAfterStartupTaskFromDBThread(
|
| + FROM_HERE, db_thread_,
|
| + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread,
|
| + BrowserThread::DB));
|
| + RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(0, db_thread_->total_task_count() + ui_thread_->total_task_count());
|
| +
|
| + // Queued tasks should be posted upon setting the flag.
|
| + AfterStartupTaskUtils::SetBrowserStartupIsComplete();
|
| + EXPECT_EQ(2, db_thread_->posted_task_count());
|
| + EXPECT_EQ(2, ui_thread_->posted_task_count());
|
| + FlushDBThread();
|
| + RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(2, db_thread_->ran_task_count());
|
| + EXPECT_EQ(2, ui_thread_->ran_task_count());
|
| +
|
| + db_thread_->reset_task_counts();
|
| + ui_thread_->reset_task_counts();
|
| + EXPECT_EQ(0, db_thread_->total_task_count() + ui_thread_->total_task_count());
|
| +
|
| + // Tasks posted after startup should get posted immediately.
|
| + AfterStartupTaskUtils::PostTask(FROM_HERE, ui_thread_,
|
| + base::Bind(&base::DoNothing));
|
| + AfterStartupTaskUtils::PostTask(FROM_HERE, db_thread_,
|
| + base::Bind(&base::DoNothing));
|
| + EXPECT_EQ(1, db_thread_->posted_task_count());
|
| + EXPECT_EQ(1, ui_thread_->posted_task_count());
|
| + PostAfterStartupTaskFromDBThread(FROM_HERE, ui_thread_,
|
| + base::Bind(&base::DoNothing));
|
| + PostAfterStartupTaskFromDBThread(FROM_HERE, db_thread_,
|
| + base::Bind(&base::DoNothing));
|
| + EXPECT_EQ(2, db_thread_->posted_task_count());
|
| + EXPECT_EQ(2, ui_thread_->posted_task_count());
|
| + FlushDBThread();
|
| + RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(2, db_thread_->ran_task_count());
|
| + EXPECT_EQ(2, ui_thread_->ran_task_count());
|
| +}
|
|
|