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

Unified Diff: content/browser/startup_task_runner_unittest.cc

Issue 19957002: Run the later parts of startup as UI thread tasks (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Run the later parts of startup as UI thread tasks - one more Mac fix Created 7 years, 5 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: content/browser/startup_task_runner_unittest.cc
diff --git a/content/browser/startup_task_runner_unittest.cc b/content/browser/startup_task_runner_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2ca7a9652084b879c9261685ff11861f3d1c9b0b
--- /dev/null
+++ b/content/browser/startup_task_runner_unittest.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2013 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 "content/browser/startup_task_runner.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/task_runner.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+using base::Closure;
+using testing::_;
+using testing::Assign;
+using testing::Invoke;
+using testing::WithArg;
+
+bool observer_called = false;
Yaron 2013/07/30 18:53:22 Nit: I think it's common to place these members as
aberent 2013/07/31 17:24:49 Normally I would, but these would have to be stati
+int observer_result;
+
+class StartupTaskRunnerTest : public testing::Test {
+ private:
Yaron 2013/07/30 18:53:22 Nit: A little unorthodox. Please move private to t
aberent 2013/07/31 17:24:49 Done.
+
+ int last_task_;
+
+ public:
+
+ virtual void SetUp() {
+ last_task_ = 0;
+ observer_called = false;
+ }
+
+ int Task1() {
+ last_task_ = 1;
+ return 0;
+ }
+
+ int Task2() {
+ last_task_ = 2;
+ return 0;
+ }
+
+ int Task3() {
Yaron 2013/07/30 18:53:22 Nit: renaming FailingTask (and the local variable
aberent 2013/07/31 17:24:49 Done.
+ // Task returning failure
+ last_task_ = 3;
+ return 1;
+ }
+
+ int GetLastTask() { return last_task_; }
+};
+
+void Observer(int result) {
+ observer_called = true;
+ observer_result = result;
+}
+
+// We can't use the real message loop, even if we want to, since doing so on
+// Android requires a complex Java infrastructure. The test would have to built
+// as a content_shell test; but content_shell startup invokes the class we are
+// trying to test.
+//
+// The mocks are not directly in TaskRunnerProxy because reference counted
+// objects seem to confuse the mocking framework
+
+class MockTaskRunner {
+ public:
+ MOCK_METHOD3(
+ PostDelayedTask,
+ bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
+ MOCK_METHOD3(
+ PostNonNestableDelayedTask,
+ bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
+};
+
+class TaskRunnerProxy : public base::SingleThreadTaskRunner {
+ public:
+ TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
+ virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; }
+ virtual bool PostDelayedTask(const tracked_objects::Location& location,
+ const Closure& closure,
+ base::TimeDelta delta) OVERRIDE {
+ return mock_->PostDelayedTask(location, closure, delta);
+ }
+ virtual bool PostNonNestableDelayedTask(
+ const tracked_objects::Location& location,
+ const Closure& closure,
+ base::TimeDelta delta) OVERRIDE {
+ return mock_->PostNonNestableDelayedTask(location, closure, delta);
+ }
+
+ private:
+ MockTaskRunner* mock_;
+ virtual ~TaskRunnerProxy() {}
+};
+
+TEST_F(StartupTaskRunnerTest, SynchronousExecution) {
+ MockTaskRunner mock_runner;
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
+
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
+ EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
+
+ scoped_refptr<StartupTaskRunner> runner =
+ new StartupTaskRunner(false, Observer, proxy);
+
+ StartupTask task1 =
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
+ runner->AddTask(task1);
+ EXPECT_EQ(GetLastTask(), 0);
+ StartupTask task2 =
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
+ runner->AddTask(task2);
+
+ // Nothing should run until we tell them to.
+ EXPECT_EQ(GetLastTask(), 0);
+ runner->StartRunningTasks();
+
+ // On an immediate StartupTaskRunner the tasks should now all have run.
+ EXPECT_EQ(GetLastTask(), 2);
+
+ EXPECT_TRUE(observer_called);
+ EXPECT_EQ(observer_result, 0);
+}
+
+TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) {
+ MockTaskRunner mock_runner;
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
+
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
+ EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
+
+ scoped_refptr<StartupTaskRunner> runner =
+ new StartupTaskRunner(false, Observer, proxy);
+
+ StartupTask task3 =
+ base::Bind(&StartupTaskRunnerTest::Task3, base::Unretained(this));
+ runner->AddTask(task3);
+ EXPECT_EQ(GetLastTask(), 0);
+ StartupTask task2 =
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
+ runner->AddTask(task2);
+
+ // Nothing should run until we tell them to.
+ EXPECT_EQ(GetLastTask(), 0);
+ runner->StartRunningTasks();
+
+ // Only the first task should have run, since it failed
+ EXPECT_EQ(GetLastTask(), 3);
+
+ EXPECT_TRUE(observer_called);
+ EXPECT_EQ(observer_result, 1);
+}
+base::Closure task;
Yaron 2013/07/30 18:53:22 Nit: member variabe as well.
aberent 2013/07/31 17:24:49 Could only be static member variable since used by
+
+// I couldn't get gMock's SaveArg to compile, hence had to save the argument
+// this way
+bool SaveTaskArg(const Closure& arg) {
+ task = arg;
+ return true;
+}
+
+TEST_F(StartupTaskRunnerTest, AsynchronousExecution) {
+
+ MockTaskRunner mock_runner;
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
+
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
+ EXPECT_CALL(
+ mock_runner,
+ PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
+ .Times(testing::Between(2, 3))
+ .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
+
+ scoped_refptr<StartupTaskRunner> runner =
+ new StartupTaskRunner(true, Observer, proxy);
+
+ StartupTask task1 =
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
+ runner->AddTask(task1);
+ StartupTask task2 =
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
+ runner->AddTask(task2);
+
+ // Nothing should run until we tell them to.
+ EXPECT_EQ(GetLastTask(), 0);
+ runner->StartRunningTasks();
+
+ // No tasks should have run yet, since we the message loop hasn't run.
+ EXPECT_EQ(GetLastTask(), 0);
+
+ // Fake the actual message loop. Each time a task is run a new task should
+ // be added to the queue, hence updating "task". The loop should actually run
+ // at most 3 times (once for each task plus possibly once for the observer),
+ // the "4" is a backstop.
+ for (int i = 0; i < 4 && !observer_called; i++) {
+ task.Run();
+ EXPECT_EQ(i + 1, GetLastTask());
+ }
+ EXPECT_TRUE(observer_called);
+ EXPECT_EQ(observer_result, 0);
+}
+
+TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) {
+
+ MockTaskRunner mock_runner;
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
+
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
+ EXPECT_CALL(
+ mock_runner,
+ PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
+ .Times(testing::Between(1, 2))
+ .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
+
+ scoped_refptr<StartupTaskRunner> runner =
+ new StartupTaskRunner(true, Observer, proxy);
+
+ StartupTask task3 =
+ base::Bind(&StartupTaskRunnerTest::Task3, base::Unretained(this));
+ runner->AddTask(task3);
+ StartupTask task2 =
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
+ runner->AddTask(task2);
+
+ // Nothing should run until we tell them to.
+ EXPECT_EQ(GetLastTask(), 0);
+ runner->StartRunningTasks();
+
+ // No tasks should have run yet, since we the message loop hasn't run.
+ EXPECT_EQ(GetLastTask(), 0);
+
+ // Fake the actual message loop. Each time a task is run a new task should
+ // be added to the queue, hence updating "task". The loop should actually run
+ // at most twice (once for the failed task plus possibly once for the
+ // observer), the "4" is a backstop.
+ for (int i = 0; i < 4 && !observer_called; i++) {
+ task.Run();
+ }
+ EXPECT_EQ(GetLastTask(), 3);
+
+ EXPECT_TRUE(observer_called);
+ EXPECT_EQ(observer_result, 1);
+}
+} // namespace
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698