[GCM] Extracting Delayed Task Controller from GCMDesktopDriver

* Extracting DelayedTaskController from GCMDesktopDriver
* Renaming it to GCMDelayedTaskController
* Adding tests for GCMDelayedTaskController

BUG=374969
[email protected]

Review URL: https://codereview.chromium.org/551163002

Cr-Commit-Position: refs/heads/master@{#294185}
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 0ad25cd..b8af7817 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -123,6 +123,7 @@
             'gcm_driver/gcm_account_mapper_unittest.cc',
             'gcm_driver/gcm_channel_status_request_unittest.cc',
             'gcm_driver/gcm_client_impl_unittest.cc',
+            'gcm_driver/gcm_delayed_task_controller_unittest.cc',
             'gcm_driver/gcm_driver_desktop_unittest.cc',
             'gcm_driver/gcm_stats_recorder_impl_unittest.cc',
             'google/core/browser/google_util_unittest.cc',
@@ -585,6 +586,7 @@
                 'gcm_driver/gcm_account_mapper_unittest.cc',
                 'gcm_driver/gcm_channel_status_request_unittest.cc',
                 'gcm_driver/gcm_client_impl_unittest.cc',
+                'gcm_driver/gcm_delayed_task_controller_unittest.cc',
                 'gcm_driver/gcm_driver_desktop_unittest.cc',
                 'feedback/feedback_common_unittest.cc',
                 'feedback/feedback_data_unittest.cc',
diff --git a/components/gcm_driver.gypi b/components/gcm_driver.gypi
index f91e85c..1e9559f4 100644
--- a/components/gcm_driver.gypi
+++ b/components/gcm_driver.gypi
@@ -41,6 +41,8 @@
         'gcm_driver/gcm_client_impl.h',
         'gcm_driver/gcm_connection_observer.cc',
         'gcm_driver/gcm_connection_observer.h',
+        'gcm_driver/gcm_delayed_task_controller.cc',
+        'gcm_driver/gcm_delayed_task_controller.h',
         'gcm_driver/gcm_driver.cc',
         'gcm_driver/gcm_driver.h',
         'gcm_driver/gcm_driver_android.cc',
@@ -75,6 +77,8 @@
             'gcm_driver/gcm_client_factory.h',
             'gcm_driver/gcm_client_impl.cc',
             'gcm_driver/gcm_client_impl.h',
+            'gcm_driver/gcm_delayed_task_controller.cc',
+            'gcm_driver/gcm_delayed_task_controller.h',
             'gcm_driver/gcm_driver_desktop.cc',
             'gcm_driver/gcm_driver_desktop.h',
             'gcm_driver/gcm_stats_recorder_impl.cc',
diff --git a/components/gcm_driver/BUILD.gn b/components/gcm_driver/BUILD.gn
index 9a1941b..45dd2a2 100644
--- a/components/gcm_driver/BUILD.gn
+++ b/components/gcm_driver/BUILD.gn
@@ -24,6 +24,8 @@
     "gcm_client_impl.h",
     "gcm_connection_observer.cc",
     "gcm_connection_observer.h",
+    "gcm_delayed_task_controller.cc",
+    "gcm_delayed_task_controller.h",
     "gcm_driver.cc",
     "gcm_driver.h",
     "gcm_driver_android.cc",
@@ -52,6 +54,8 @@
       "gcm_client_factory.h",
       "gcm_client_impl.cc",
       "gcm_client_impl.h",
+      "gcm_delayed_task_controller.cc",
+      "gcm_delayed_task_controller.h",
       "gcm_driver_desktop.cc",
       "gcm_driver_desktop.h",
       "gcm_stats_recorder_impl.cc",
diff --git a/components/gcm_driver/gcm_delayed_task_controller.cc b/components/gcm_driver/gcm_delayed_task_controller.cc
new file mode 100644
index 0000000..0506a348
--- /dev/null
+++ b/components/gcm_driver/gcm_delayed_task_controller.cc
@@ -0,0 +1,38 @@
+// Copyright 2014 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 "components/gcm_driver/gcm_delayed_task_controller.h"
+
+#include "base/logging.h"
+
+namespace gcm {
+
+GCMDelayedTaskController::GCMDelayedTaskController() : ready_(false) {
+}
+
+GCMDelayedTaskController::~GCMDelayedTaskController() {
+}
+
+void GCMDelayedTaskController::AddTask(const base::Closure& task) {
+  delayed_tasks_.push_back(task);
+}
+
+void GCMDelayedTaskController::SetReady() {
+  ready_ = true;
+  RunTasks();
+}
+
+bool GCMDelayedTaskController::CanRunTaskWithoutDelay() const {
+  return ready_;
+}
+
+void GCMDelayedTaskController::RunTasks() {
+  DCHECK(ready_);
+
+  for (size_t i = 0; i < delayed_tasks_.size(); ++i)
+    delayed_tasks_[i].Run();
+  delayed_tasks_.clear();
+}
+
+}  // namespace gcm
diff --git a/components/gcm_driver/gcm_delayed_task_controller.h b/components/gcm_driver/gcm_delayed_task_controller.h
new file mode 100644
index 0000000..0b01348
--- /dev/null
+++ b/components/gcm_driver/gcm_delayed_task_controller.h
@@ -0,0 +1,42 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_GCM_DRIVER_GCM_DELAYED_TASK_CONTROLLER_H_
+#define COMPONENTS_GCM_DRIVER_GCM_DELAYED_TASK_CONTROLLER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+
+namespace gcm {
+
+// Helper class to save tasks to run until we're ready to execute them.
+class GCMDelayedTaskController {
+ public:
+  GCMDelayedTaskController();
+  ~GCMDelayedTaskController();
+
+  // Adds a task that will be invoked once we're ready.
+  void AddTask(const base::Closure& task);
+
+  // Sets ready status, which will release all of the pending tasks.
+  void SetReady();
+
+  // Returns true if it is ready to perform tasks.
+  bool CanRunTaskWithoutDelay() const;
+
+ private:
+  void RunTasks();
+
+  // Flag that indicates that controlled component is ready.
+  bool ready_;
+
+  std::vector<base::Closure> delayed_tasks_;
+
+  DISALLOW_COPY_AND_ASSIGN(GCMDelayedTaskController);
+};
+
+}  // namespace gcm
+
+#endif  // COMPONENTS_GCM_DRIVER_GCM_DELAYED_TASK_CONTROLLER_H_
diff --git a/components/gcm_driver/gcm_delayed_task_controller_unittest.cc b/components/gcm_driver/gcm_delayed_task_controller_unittest.cc
new file mode 100644
index 0000000..9b49d42
--- /dev/null
+++ b/components/gcm_driver/gcm_delayed_task_controller_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2014 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 "components/gcm_driver/gcm_delayed_task_controller.h"
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gcm {
+
+class GCMDelayedTaskControllerTest : public testing::Test {
+ public:
+  GCMDelayedTaskControllerTest();
+  virtual ~GCMDelayedTaskControllerTest();
+
+  void TestTask();
+
+  GCMDelayedTaskController* controller() { return controller_.get(); }
+
+  int number_of_triggered_tasks() const { return number_of_triggered_tasks_; }
+
+ private:
+  scoped_ptr<GCMDelayedTaskController> controller_;
+  int number_of_triggered_tasks_;
+};
+
+GCMDelayedTaskControllerTest::GCMDelayedTaskControllerTest()
+    : controller_(new GCMDelayedTaskController), number_of_triggered_tasks_(0) {
+}
+
+GCMDelayedTaskControllerTest::~GCMDelayedTaskControllerTest() {
+}
+
+void GCMDelayedTaskControllerTest::TestTask() {
+  ++number_of_triggered_tasks_;
+}
+
+// Tests that a newly created controller forced tasks to be delayed, while
+// calling SetReady allows tasks to execute.
+TEST_F(GCMDelayedTaskControllerTest, SetReadyWithNoTasks) {
+  EXPECT_FALSE(controller()->CanRunTaskWithoutDelay());
+  EXPECT_EQ(0, number_of_triggered_tasks());
+
+  controller()->SetReady();
+  EXPECT_TRUE(controller()->CanRunTaskWithoutDelay());
+  EXPECT_EQ(0, number_of_triggered_tasks());
+}
+
+// Tests that tasks are triggered when controlles is set to ready.
+TEST_F(GCMDelayedTaskControllerTest, PendingTasksTriggeredWhenSetReady) {
+  controller()->AddTask(base::Bind(&GCMDelayedTaskControllerTest::TestTask,
+                                   base::Unretained(this)));
+  controller()->AddTask(base::Bind(&GCMDelayedTaskControllerTest::TestTask,
+                                   base::Unretained(this)));
+
+  controller()->SetReady();
+  EXPECT_EQ(2, number_of_triggered_tasks());
+}
+
+}  // namespace gcm
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc
index 001b018..67229665 100644
--- a/components/gcm_driver/gcm_driver_desktop.cc
+++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -15,6 +15,7 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "components/gcm_driver/gcm_app_handler.h"
 #include "components/gcm_driver/gcm_client_factory.h"
+#include "components/gcm_driver/gcm_delayed_task_controller.h"
 #include "components/gcm_driver/system_encryptor.h"
 #include "google_apis/gcm/engine/account_mapping.h"
 #include "net/base/ip_endpoint.h"
@@ -22,62 +23,6 @@
 
 namespace gcm {
 
-// Helper class to save tasks to run until we're ready to execute them.
-class GCMDriverDesktop::DelayedTaskController {
- public:
-  DelayedTaskController();
-  ~DelayedTaskController();
-
-  // Adds a task that will be invoked once we're ready.
-  void AddTask(const base::Closure& task);
-
-  // Sets ready status. It is ready only when check-in is completed and
-  // the GCMClient is fully initialized.
-  void SetReady();
-
-  // Returns true if it is ready to perform tasks.
-  bool CanRunTaskWithoutDelay() const;
-
- private:
-  void RunTasks();
-
-  // Flag that indicates that GCM is ready.
-  bool ready_;
-
-  std::vector<base::Closure> delayed_tasks_;
-
-  DISALLOW_COPY_AND_ASSIGN(DelayedTaskController);
-};
-
-GCMDriverDesktop::DelayedTaskController::DelayedTaskController()
-    : ready_(false) {
-}
-
-GCMDriverDesktop::DelayedTaskController::~DelayedTaskController() {
-}
-
-void GCMDriverDesktop::DelayedTaskController::AddTask(
-    const base::Closure& task) {
-  delayed_tasks_.push_back(task);
-}
-
-void GCMDriverDesktop::DelayedTaskController::SetReady() {
-  ready_ = true;
-  RunTasks();
-}
-
-bool GCMDriverDesktop::DelayedTaskController::CanRunTaskWithoutDelay() const {
-  return ready_;
-}
-
-void GCMDriverDesktop::DelayedTaskController::RunTasks() {
-  DCHECK(ready_);
-
-  for (size_t i = 0; i < delayed_tasks_.size(); ++i)
-    delayed_tasks_[i].Run();
-  delayed_tasks_.clear();
-}
-
 class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
  public:
   // Called on UI thread.
@@ -676,7 +621,7 @@
     return GCMClient::NOT_SIGNED_IN;
 
   DCHECK(!delayed_task_controller_);
-  delayed_task_controller_.reset(new DelayedTaskController);
+  delayed_task_controller_.reset(new GCMDelayedTaskController);
 
   // Note that we need to pass weak pointer again since the existing weak
   // pointer in IOWorker might have been invalidated when check-out occurs.
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h
index 04bc22d1..3199a48a 100644
--- a/components/gcm_driver/gcm_driver_desktop.h
+++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -36,6 +36,7 @@
 
 class GCMAppHandler;
 class GCMClientFactory;
+class GCMDelayedTaskController;
 
 // GCMDriver implementation for desktop and Chrome OS, using GCMClient.
 class GCMDriverDesktop : public GCMDriver {
@@ -94,7 +95,6 @@
                         const GCMClient::OutgoingMessage& message) OVERRIDE;
 
  private:
-  class DelayedTaskController;
   class IOWorker;
 
   //  Stops the GCM service. It can be restarted by calling EnsureStarted again.
@@ -146,7 +146,7 @@
   scoped_refptr<base::SequencedTaskRunner> ui_thread_;
   scoped_refptr<base::SequencedTaskRunner> io_thread_;
 
-  scoped_ptr<DelayedTaskController> delayed_task_controller_;
+  scoped_ptr<GCMDelayedTaskController> delayed_task_controller_;
 
   // For all the work occurring on the IO thread. Must be destroyed on the IO
   // thread.