Chromium Code Reviews| 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..0b449f7054d298979c4cecbe4df2ec2aa0d0a0eb |
| --- /dev/null |
| +++ b/chrome/browser/after_startup_task_utils_unittest.cc |
| @@ -0,0 +1,188 @@ |
| +// 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), |
| + posted_task_count_(0), |
|
cmumford
2015/04/06 23:18:03
Nit: Use Non-Static Class Member Initializers
michaeln
2015/04/06 23:45:59
Done
|
| + ran_task_count_(0) {} |
| + |
| + 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: |
| + void RunWrappedTask(const base::Closure& task) { |
| + ++ran_task_count_; |
| + task.Run(); |
| + } |
| + |
| + scoped_refptr<TaskRunner> real_task_runner_; |
| + int posted_task_count_; |
| + int ran_task_count_; |
| +}; |
| + |
| +} // 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::UnsafeReset(); |
| + } |
| + |
| + // 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(); |
| + } |
| + |
| + 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. |
| + EXPECT_FALSE(GetIsBrowserStartupCompleteFromDBThread()); |
| + EXPECT_FALSE(AfterStartupTaskUtils::IsBrowserStartupComplete()); |
| + AfterStartupTaskUtils::SetBrowserStartupIsComplete(); |
|
cmumford
2015/04/06 23:18:03
Can you add a comment explaining this test relies
michaeln
2015/04/06 23:45:59
Done.
|
| + 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(&base::DoNothing)); |
| + AfterStartupTaskUtils::PostTask(FROM_HERE, db_thread_, |
| + base::Bind(&base::DoNothing)); |
| + PostAfterStartupTaskFromDBThread(FROM_HERE, ui_thread_, |
| + base::Bind(&base::DoNothing)); |
| + PostAfterStartupTaskFromDBThread(FROM_HERE, db_thread_, |
| + base::Bind(&base::DoNothing)); |
| + FlushDBThread(); |
| + RunLoop().RunUntilIdle(); |
| + EXPECT_EQ(0, db_thread_->total_task_count()); |
| + EXPECT_EQ(0, 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(); |
|
cmumford
2015/04/06 23:18:03
What do you think about maybe resetting only one o
michaeln
2015/04/06 23:45:58
Instead, I made some of the tasks verify they're r
|
| + |
| + // Tasks posted after startup should get posted immediately. |
|
cmumford
2015/04/06 23:18:03
Do you want to add EXPECT_EQ(0, db_thread_->total_
michaeln
2015/04/06 23:45:58
Done.
|
| + 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)); |
| + FlushDBThread(); |
| + 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()); |
| +} |