diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-23 00:25:39 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-23 00:25:39 +0000 |
commit | 3ecb2b58b0374c5da40752d7ab94d22f4803149f (patch) | |
tree | 4438f20890055a0188514bbce98e0edec0fb80f4 /chrome/browser/services | |
parent | f916f7c8ec22b4b2b865c632b8e4e08d7b73d798 (diff) | |
download | chromium_src-3ecb2b58b0374c5da40752d7ab94d22f4803149f.zip chromium_src-3ecb2b58b0374c5da40752d7ab94d22f4803149f.tar.gz chromium_src-3ecb2b58b0374c5da40752d7ab94d22f4803149f.tar.bz2 |
Start and stop the GCM service on demand
The GCM service will now be started when there is a consumer. It will be
automatically stopped when all consumers are gone. This does not change
the existing behavior that the GCM is always started for the signed-in
profile since invalidation consumes it.
BUG=356716
TEST=tests updated and new tests added
TBR=kalman@chromium.org
Review URL: https://codereview.chromium.org/296053011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272380 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/services')
-rw-r--r-- | chrome/browser/services/gcm/fake_gcm_app_handler.cc | 62 | ||||
-rw-r--r-- | chrome/browser/services/gcm/fake_gcm_app_handler.h | 63 | ||||
-rw-r--r-- | chrome/browser/services/gcm/gcm_driver.cc | 8 | ||||
-rw-r--r-- | chrome/browser/services/gcm/gcm_driver_unittest.cc | 241 | ||||
-rw-r--r-- | chrome/browser/services/gcm/gcm_profile_service_unittest.cc | 10 |
5 files changed, 276 insertions, 108 deletions
diff --git a/chrome/browser/services/gcm/fake_gcm_app_handler.cc b/chrome/browser/services/gcm/fake_gcm_app_handler.cc new file mode 100644 index 0000000..4e6c054 --- /dev/null +++ b/chrome/browser/services/gcm/fake_gcm_app_handler.cc @@ -0,0 +1,62 @@ +// 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 "chrome/browser/services/gcm/fake_gcm_app_handler.h" + +#include "base/run_loop.h" + +namespace gcm { + +FakeGCMAppHandler::FakeGCMAppHandler() : received_event_(NO_EVENT) { +} + +FakeGCMAppHandler::~FakeGCMAppHandler() { +} + +void FakeGCMAppHandler::WaitForNotification() { + run_loop_.reset(new base::RunLoop); + run_loop_->Run(); + run_loop_.reset(); +} + +void FakeGCMAppHandler::ShutdownHandler() { +} + +void FakeGCMAppHandler::OnMessage(const std::string& app_id, + const GCMClient::IncomingMessage& message) { + ClearResults(); + received_event_ = MESSAGE_EVENT; + app_id_ = app_id; + message_ = message; + if (run_loop_) + run_loop_->Quit(); +} + +void FakeGCMAppHandler::OnMessagesDeleted(const std::string& app_id) { + ClearResults(); + received_event_ = MESSAGES_DELETED_EVENT; + app_id_ = app_id; + if (run_loop_) + run_loop_->Quit(); +} + +void FakeGCMAppHandler::OnSendError( + const std::string& app_id, + const GCMClient::SendErrorDetails& send_error_details) { + ClearResults(); + received_event_ = SEND_ERROR_EVENT; + app_id_ = app_id; + send_error_details_ = send_error_details; + if (run_loop_) + run_loop_->Quit(); +} + +void FakeGCMAppHandler::ClearResults() { + received_event_ = NO_EVENT; + app_id_.clear(); + message_ = GCMClient::IncomingMessage(); + send_error_details_ = GCMClient::SendErrorDetails(); +} + +} // namespace gcm diff --git a/chrome/browser/services/gcm/fake_gcm_app_handler.h b/chrome/browser/services/gcm/fake_gcm_app_handler.h new file mode 100644 index 0000000..d422214 --- /dev/null +++ b/chrome/browser/services/gcm/fake_gcm_app_handler.h @@ -0,0 +1,63 @@ +// 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 CHROME_BROWSER_SERVICES_GCM_FAKE_GCM_APP_HANDLER_H_ +#define CHROME_BROWSER_SERVICES_GCM_FAKE_GCM_APP_HANDLER_H_ + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "components/gcm_driver/gcm_app_handler.h" + +namespace base { +class RunLoop; +} + +namespace gcm { + +class FakeGCMAppHandler : public GCMAppHandler { + public: + enum Event { + NO_EVENT, + MESSAGE_EVENT, + MESSAGES_DELETED_EVENT, + SEND_ERROR_EVENT + }; + + FakeGCMAppHandler(); + virtual ~FakeGCMAppHandler(); + + const Event& received_event() const { return received_event_; } + const std::string& app_id() const { return app_id_; } + const GCMClient::IncomingMessage& message() const { return message_; } + const GCMClient::SendErrorDetails& send_error_details() const { + return send_error_details_; + } + + void WaitForNotification(); + + // GCMAppHandler: + virtual void ShutdownHandler() OVERRIDE; + virtual void OnMessage(const std::string& app_id, + const GCMClient::IncomingMessage& message) OVERRIDE; + virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE; + virtual void OnSendError( + const std::string& app_id, + const GCMClient::SendErrorDetails& send_error_details) OVERRIDE; + + private: + void ClearResults(); + + scoped_ptr<base::RunLoop> run_loop_; + + Event received_event_; + std::string app_id_; + GCMClient::IncomingMessage message_; + GCMClient::SendErrorDetails send_error_details_; + + DISALLOW_COPY_AND_ASSIGN(FakeGCMAppHandler); +}; + +} // namespace gcm + +#endif // CHROME_BROWSER_SERVICES_GCM_FAKE_GCM_APP_HANDLER_H_ diff --git a/chrome/browser/services/gcm/gcm_driver.cc b/chrome/browser/services/gcm/gcm_driver.cc index 59860c0..96c21f4 100644 --- a/chrome/browser/services/gcm/gcm_driver.cc +++ b/chrome/browser/services/gcm/gcm_driver.cc @@ -475,6 +475,10 @@ void GCMDriver::RemoveAppHandler(const std::string& app_id) { DCHECK(!app_id.empty()); app_handlers_.erase(app_id); + + // Stops the GCM service when no app intends to consume it. + if (app_handlers_.empty()) + Stop(); } void GCMDriver::Register(const std::string& app_id, @@ -681,6 +685,10 @@ GCMClient::Result GCMDriver::EnsureStarted() { if (!gcm_enabled_) return GCMClient::GCM_DISABLED; + // Have any app requested the service? + if (app_handlers_.empty()) + return GCMClient::UNKNOWN_ERROR; + // Is the user signed in? const std::string account_id = identity_provider_->GetActiveAccountId(); if (account_id.empty()) diff --git a/chrome/browser/services/gcm/gcm_driver_unittest.cc b/chrome/browser/services/gcm/gcm_driver_unittest.cc index 706e42a..cd74a53 100644 --- a/chrome/browser/services/gcm/gcm_driver_unittest.cc +++ b/chrome/browser/services/gcm/gcm_driver_unittest.cc @@ -14,6 +14,7 @@ #include "base/strings/string_util.h" #include "base/test/test_simple_task_runner.h" #include "base/threading/thread.h" +#include "chrome/browser/services/gcm/fake_gcm_app_handler.h" #include "chrome/browser/services/gcm/fake_gcm_client.h" #include "chrome/browser/services/gcm/fake_gcm_client_factory.h" #include "chrome/browser/services/gcm/gcm_app_handler.h" @@ -51,100 +52,6 @@ std::vector<std::string> ToSenderList(const std::string& sender_ids) { return senders; } -class FakeGCMAppHandler : public GCMAppHandler { - public: - enum Event { - NO_EVENT, - MESSAGE_EVENT, - MESSAGES_DELETED_EVENT, - SEND_ERROR_EVENT - }; - - FakeGCMAppHandler(); - virtual ~FakeGCMAppHandler(); - - const Event& received_event() const { return received_event_; } - const std::string& app_id() const { return app_id_; } - const GCMClient::IncomingMessage& message() const { return message_; } - const GCMClient::SendErrorDetails& send_error_details() const { - return send_error_details_; - } - - void WaitForNotification(); - - // GCMAppHandler: - virtual void ShutdownHandler() OVERRIDE; - virtual void OnMessage(const std::string& app_id, - const GCMClient::IncomingMessage& message) OVERRIDE; - virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE; - virtual void OnSendError( - const std::string& app_id, - const GCMClient::SendErrorDetails& send_error_details) OVERRIDE; - - private: - void ClearResults(); - - scoped_ptr<base::RunLoop> run_loop_; - - Event received_event_; - std::string app_id_; - GCMClient::IncomingMessage message_; - GCMClient::SendErrorDetails send_error_details_; - - DISALLOW_COPY_AND_ASSIGN(FakeGCMAppHandler); -}; - -FakeGCMAppHandler::FakeGCMAppHandler() : received_event_(NO_EVENT) { -} - -FakeGCMAppHandler::~FakeGCMAppHandler() { -} - -void FakeGCMAppHandler::WaitForNotification() { - run_loop_.reset(new base::RunLoop); - run_loop_->Run(); - run_loop_.reset(); -} - -void FakeGCMAppHandler::ShutdownHandler() { -} - -void FakeGCMAppHandler::OnMessage(const std::string& app_id, - const GCMClient::IncomingMessage& message) { - ClearResults(); - received_event_ = MESSAGE_EVENT; - app_id_ = app_id; - message_ = message; - if (run_loop_) - run_loop_->Quit(); -} - -void FakeGCMAppHandler::OnMessagesDeleted(const std::string& app_id) { - ClearResults(); - received_event_ = MESSAGES_DELETED_EVENT; - app_id_ = app_id; - if (run_loop_) - run_loop_->Quit(); -} - -void FakeGCMAppHandler::OnSendError( - const std::string& app_id, - const GCMClient::SendErrorDetails& send_error_details) { - ClearResults(); - received_event_ = SEND_ERROR_EVENT; - app_id_ = app_id; - send_error_details_ = send_error_details; - if (run_loop_) - run_loop_->Quit(); -} - -void FakeGCMAppHandler::ClearResults() { - received_event_ = NO_EVENT; - app_id_.clear(); - message_ = GCMClient::IncomingMessage(); - send_error_details_ = GCMClient::SendErrorDetails(); -} - } // namespace class GCMDriverTest : public testing::Test { @@ -179,6 +86,8 @@ class GCMDriverTest : public testing::Test { FakeGCMClient* GetGCMClient(); void CreateDriver(FakeGCMClient::StartMode gcm_client_start_mode); + void AddAppHandlers(); + void RemoveAppHandlers(); void SignIn(const std::string& account_id); void SignOut(); @@ -295,10 +204,18 @@ void GCMDriverTest::CreateDriver( task_runner_)); gcm_app_handler_.reset(new FakeGCMAppHandler); +} + +void GCMDriverTest::AddAppHandlers() { driver_->AddAppHandler(kTestAppID1, gcm_app_handler_.get()); driver_->AddAppHandler(kTestAppID2, gcm_app_handler_.get()); } +void GCMDriverTest::RemoveAppHandlers() { + driver_->RemoveAppHandler(kTestAppID1); + driver_->RemoveAppHandler(kTestAppID2); +} + void GCMDriverTest::SignIn(const std::string& account_id) { token_service_.AddAccount(account_id); identity_provider_->LogIn(account_id); @@ -380,71 +297,103 @@ void GCMDriverTest::UnregisterCompleted(GCMClient::Result result) { } TEST_F(GCMDriverTest, CreateGCMDriverBeforeSignIn) { - // Create CreateGMCService first. + // Create GCMDriver first. GCM is not started. CreateDriver(FakeGCMClient::NO_DELAY_START); EXPECT_FALSE(driver()->IsStarted()); - // Sign in. This will kick off the check-in. + // Sign in. GCM is still not started. SignIn(kTestAccountID1); + EXPECT_FALSE(driver()->IsStarted()); + + // GCM will be started only after both sign-in and app handler being + AddAppHandlers(); EXPECT_TRUE(driver()->IsStarted()); } TEST_F(GCMDriverTest, CreateGCMDriverAfterSignIn) { - // Sign in. This will not initiate the check-in. + // Sign in. Nothings happens since GCMDriver is not created. SignIn(kTestAccountID1); - // Create GCMeService after sign-in. + // Create GCMDriver after sign-in. GCM is not started. CreateDriver(FakeGCMClient::NO_DELAY_START); + EXPECT_FALSE(driver()->IsStarted()); + + // GCM will be started only after both sign-in and app handler being + AddAppHandlers(); EXPECT_TRUE(driver()->IsStarted()); } TEST_F(GCMDriverTest, Shutdown) { CreateDriver(FakeGCMClient::NO_DELAY_START); + EXPECT_FALSE(HasAppHandlers()); + + AddAppHandlers(); EXPECT_TRUE(HasAppHandlers()); driver()->Shutdown(); EXPECT_FALSE(HasAppHandlers()); } -TEST_F(GCMDriverTest, SignInAndSignOutUnderPositiveChannelSignal) { +TEST_F(GCMDriverTest, SignInAndSignOutOnGCMEnabled) { + // By default, GCM is enabled. CreateDriver(FakeGCMClient::NO_DELAY_START); - SignIn(kTestAccountID1); + AddAppHandlers(); - // GCMClient should be loaded. + // GCMClient should be started after sign-in. + SignIn(kTestAccountID1); EXPECT_TRUE(driver()->IsGCMClientReady()); EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); + // GCMClient should be checked out after sign-out. SignOut(); + EXPECT_FALSE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); +} - // GCMClient should be checked out. +TEST_F(GCMDriverTest, SignInAndSignOutOnGCMDisabled) { + // By default, GCM is enabled. + CreateDriver(FakeGCMClient::NO_DELAY_START); + AddAppHandlers(); + + // Disable GCM. + driver()->Disable(); + + // GCMClient should not be started after sign-in. + SignIn(kTestAccountID1); + EXPECT_FALSE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status()); + + // Check-out should still be performed after sign-out. + SignOut(); EXPECT_FALSE(driver()->IsGCMClientReady()); EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); } TEST_F(GCMDriverTest, SignOutAndThenSignIn) { CreateDriver(FakeGCMClient::NO_DELAY_START); - SignIn(kTestAccountID1); + AddAppHandlers(); - // GCMClient should be loaded. + // GCMClient should be started after sign-in. + SignIn(kTestAccountID1); EXPECT_TRUE(driver()->IsGCMClientReady()); EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); + // GCMClient should be checked out after sign-out. SignOut(); - - // GCMClient should be checked out. EXPECT_FALSE(driver()->IsGCMClientReady()); EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); // Sign-in with a different account. SignIn(kTestAccountID2); - // GCMClient should be loaded again. + // GCMClient should be started again. EXPECT_TRUE(driver()->IsGCMClientReady()); EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); } TEST_F(GCMDriverTest, DisableAndReenableGCM) { CreateDriver(FakeGCMClient::NO_DELAY_START); + AddAppHandlers(); SignIn(kTestAccountID1); // GCMClient should be started. @@ -486,6 +435,50 @@ TEST_F(GCMDriverTest, DisableAndReenableGCM) { EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); } +TEST_F(GCMDriverTest, StartOrStopGCMOnDemand) { + CreateDriver(FakeGCMClient::NO_DELAY_START); + SignIn(kTestAccountID1); + + // GCMClient is not started. + EXPECT_FALSE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status()); + + // GCMClient is started after an app handler has been added. + driver()->AddAppHandler(kTestAppID1, gcm_app_handler()); + PumpIOLoop(); + PumpUILoop(); + EXPECT_TRUE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); + + // Add another app handler. + driver()->AddAppHandler(kTestAppID2, gcm_app_handler()); + PumpIOLoop(); + PumpUILoop(); + EXPECT_TRUE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); + + // GCMClient remains active after one app handler is gone. + driver()->RemoveAppHandler(kTestAppID1); + PumpIOLoop(); + PumpUILoop(); + EXPECT_TRUE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); + + // GCMClient should be stopped after the last app handler is gone. + driver()->RemoveAppHandler(kTestAppID2); + PumpIOLoop(); + PumpUILoop(); + EXPECT_FALSE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status()); + + // GCMClient is restarted after an app handler has been added. + driver()->AddAppHandler(kTestAppID2, gcm_app_handler()); + PumpIOLoop(); + PumpUILoop(); + EXPECT_TRUE(driver()->IsGCMClientReady()); + EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); +} + TEST_F(GCMDriverTest, RegisterFailed) { std::vector<std::string> sender_ids; sender_ids.push_back("sender1"); @@ -502,9 +495,19 @@ TEST_F(GCMDriverTest, RegisterFailed) { // Registration fails when the sign-in does not occur. driver()->Enable(); + AddAppHandlers(); Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); EXPECT_TRUE(registration_id().empty()); EXPECT_EQ(GCMClient::NOT_SIGNED_IN, registration_result()); + + ClearResults(); + + // Registration fails when the no app handler is added. + RemoveAppHandlers(); + SignIn(kTestAccountID1); + Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); + EXPECT_TRUE(registration_id().empty()); + EXPECT_EQ(GCMClient::UNKNOWN_ERROR, registration_result()); } TEST_F(GCMDriverTest, UnregisterFailed) { @@ -519,8 +522,17 @@ TEST_F(GCMDriverTest, UnregisterFailed) { // Unregistration fails when the sign-in does not occur. driver()->Enable(); + AddAppHandlers(); Unregister(kTestAppID1, GCMDriverTest::WAIT); EXPECT_EQ(GCMClient::NOT_SIGNED_IN, unregistration_result()); + + ClearResults(); + + // Unregistration fails when the no app handler is added. + RemoveAppHandlers(); + SignIn(kTestAccountID1); + Unregister(kTestAppID1, GCMDriverTest::WAIT); + EXPECT_EQ(GCMClient::UNKNOWN_ERROR, unregistration_result()); } TEST_F(GCMDriverTest, SendFailed) { @@ -538,17 +550,28 @@ TEST_F(GCMDriverTest, SendFailed) { ClearResults(); - // Registration fails when the sign-in does not occur. + // Sending fails when the sign-in does not occur. driver()->Enable(); + AddAppHandlers(); Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT); EXPECT_TRUE(send_message_id().empty()); EXPECT_EQ(GCMClient::NOT_SIGNED_IN, send_result()); + + ClearResults(); + + // Sending fails when the no app handler is added. + RemoveAppHandlers(); + SignIn(kTestAccountID1); + Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT); + EXPECT_TRUE(send_message_id().empty()); + EXPECT_EQ(GCMClient::UNKNOWN_ERROR, send_result()); } TEST_F(GCMDriverTest, GCMClientNotReadyBeforeRegistration) { // Make GCMClient not ready initially. CreateDriver(FakeGCMClient::DELAY_START); SignIn(kTestAccountID1); + AddAppHandlers(); // The registration is on hold until GCMClient is ready. std::vector<std::string> sender_ids; @@ -572,6 +595,7 @@ TEST_F(GCMDriverTest, GCMClientNotReadyBeforeSending) { // Make GCMClient not ready initially. CreateDriver(FakeGCMClient::DELAY_START); SignIn(kTestAccountID1); + AddAppHandlers(); // The sending is on hold until GCMClient is ready. GCMClient::OutgoingMessage message; @@ -615,6 +639,7 @@ void GCMDriverFunctionalTest::SetUp() { GCMDriverTest::SetUp(); CreateDriver(FakeGCMClient::NO_DELAY_START); + AddAppHandlers(); SignIn(kTestAccountID1); } diff --git a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc index e4d170d..7a6f260 100644 --- a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc +++ b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc @@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" +#include "chrome/browser/services/gcm/fake_gcm_app_handler.h" #include "chrome/browser/services/gcm/fake_gcm_client.h" #include "chrome/browser/services/gcm/fake_gcm_client_factory.h" #include "chrome/browser/services/gcm/fake_signin_manager.h" @@ -54,6 +55,7 @@ class GCMProfileServiceTest : public testing::Test { // testing::Test: virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; FakeGCMClient* GetGCMClient() const; @@ -83,6 +85,7 @@ class GCMProfileServiceTest : public testing::Test { content::TestBrowserThreadBundle thread_bundle_; scoped_ptr<TestingProfile> profile_; GCMProfileService* gcm_profile_service_; + scoped_ptr<FakeGCMAppHandler> gcm_app_handler_; std::string registration_id_; GCMClient::Result registration_result_; @@ -95,6 +98,7 @@ class GCMProfileServiceTest : public testing::Test { GCMProfileServiceTest::GCMProfileServiceTest() : gcm_profile_service_(NULL), + gcm_app_handler_(new FakeGCMAppHandler), registration_result_(GCMClient::UNKNOWN_ERROR), send_result_(GCMClient::UNKNOWN_ERROR) { } @@ -117,6 +121,8 @@ void GCMProfileServiceTest::SetUp() { GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile_.get(), &BuildGCMProfileService)); + gcm_profile_service_->driver()->AddAppHandler( + kTestAppID, gcm_app_handler_.get()); FakeSigninManager* signin_manager = static_cast<FakeSigninManager*>( SigninManagerFactory::GetInstance()->GetForProfile(profile_.get())); @@ -124,6 +130,10 @@ void GCMProfileServiceTest::SetUp() { base::RunLoop().RunUntilIdle(); } +void GCMProfileServiceTest::TearDown() { + gcm_profile_service_->driver()->RemoveAppHandler(kTestAppID); +} + void GCMProfileServiceTest::RegisterAndWaitForCompletion( const std::vector<std::string>& sender_ids) { base::RunLoop run_loop; |