[GCM] Move extension specific tests out of gcm_profile_service_unit_test
These tests are moved to extension_gcm_profile_service_unittest.
Also did some cleanup.
BUG=356421
TEST=tests updated and new tests added
Review URL: https://codereview.chromium.org/213313006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261568 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.h b/chrome/browser/extensions/extension_gcm_app_handler.h
index af22e210..c1fac2d 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.h
+++ b/chrome/browser/extensions/extension_gcm_app_handler.h
@@ -47,6 +47,10 @@
const std::string& app_id,
const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
+ protected:
+ virtual void OnUnregisterCompleted(const std::string& app_id,
+ gcm::GCMClient::Result result);
+
private:
friend class BrowserContextKeyedAPIFactory<ExtensionGCMAppHandler>;
@@ -56,8 +60,6 @@
const content::NotificationDetails& details) OVERRIDE;
gcm::GCMProfileService* GetGCMProfileService() const;
- void OnUnregisterCompleted(const std::string& app_id,
- gcm::GCMClient::Result result);
// BrowserContextKeyedAPI implementation.
static const char* service_name() { return "ExtensionGCMAppHandler"; }
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
new file mode 100644
index 0000000..1adc3dc2
--- /dev/null
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -0,0 +1,303 @@
+// 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 "base/bind.h"
+#include "base/command_line.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/extensions/extension_gcm_app_handler.h"
+#include "chrome/browser/extensions/test_extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/services/gcm/gcm_client_mock.h"
+#include "chrome/browser/services/gcm/gcm_profile_service.h"
+#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
+#include "chrome/browser/services/gcm/gcm_profile_service_test_helper.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#else
+#include "components/signin/core/browser/signin_manager.h"
+#endif
+
+using namespace gcm;
+
+namespace extensions {
+
+namespace {
+
+const char kTestExtensionName[] = "FooBar";
+const char kTestingUsername[] = "[email protected]";
+
+} // namespace
+
+class FakeExtensionGCMAppHandler : public ExtensionGCMAppHandler {
+ public:
+ FakeExtensionGCMAppHandler(Profile* profile, Waiter* waiter)
+ : ExtensionGCMAppHandler(profile),
+ waiter_(waiter),
+ unregistration_result_(GCMClient::UNKNOWN_ERROR) {
+ }
+
+ virtual ~FakeExtensionGCMAppHandler() {
+ }
+
+ 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 {
+ }
+
+ virtual void OnUnregisterCompleted(const std::string& app_id,
+ GCMClient::Result result) OVERRIDE {
+ unregistration_result_ = result;
+ waiter_->SignalCompleted();
+ }
+
+ GCMClient::Result unregistration_result() const {
+ return unregistration_result_;
+ }
+
+ private:
+ Waiter* waiter_;
+ GCMClient::Result unregistration_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeExtensionGCMAppHandler);
+};
+
+class ExtensionGCMAppHandlerTest : public testing::Test {
+ public:
+ static KeyedService* BuildGCMProfileService(
+ content::BrowserContext* context) {
+ return new GCMProfileService(static_cast<Profile*>(context));
+ }
+
+ ExtensionGCMAppHandlerTest()
+ : extension_service_(NULL),
+ registration_result_(GCMClient::UNKNOWN_ERROR),
+ unregistration_result_(GCMClient::UNKNOWN_ERROR) {
+ }
+
+ virtual ~ExtensionGCMAppHandlerTest() {
+ }
+
+ // Overridden from test::Test:
+ virtual void SetUp() OVERRIDE {
+ // Make BrowserThread work in unittest.
+ thread_bundle_.reset(new content::TestBrowserThreadBundle(
+ content::TestBrowserThreadBundle::REAL_IO_THREAD));
+
+ // This is needed to create extension service under CrOS.
+#if defined(OS_CHROMEOS)
+ test_user_manager_.reset(new chromeos::ScopedTestUserManager());
+#endif
+
+ // Create a new profile.
+ TestingProfile::Builder builder;
+ builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
+ gcm::FakeSigninManager::Build);
+ profile_ = builder.Build();
+ signin_manager_ = static_cast<gcm::FakeSigninManager*>(
+ SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
+
+ // Create extension service in order to uninstall the extension.
+ TestExtensionSystem* extension_system(
+ static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())));
+ extension_system->CreateExtensionService(
+ CommandLine::ForCurrentProcess(), base::FilePath(), false);
+ extension_service_ = extension_system->Get(profile())->extension_service();
+
+ // Enable GCM such that tests could be run on all channels.
+ profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true);
+
+ // Create GCMProfileService that talks with fake GCMClient.
+ GCMProfileService* gcm_profile_service = static_cast<GCMProfileService*>(
+ GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile(),
+ &ExtensionGCMAppHandlerTest::BuildGCMProfileService));
+ scoped_ptr<GCMClientFactory> gcm_client_factory(
+ new FakeGCMClientFactory(GCMClientMock::NO_DELAY_LOADING));
+ gcm_profile_service->Initialize(gcm_client_factory.Pass());
+
+ // Create a fake version of ExtensionGCMAppHandler.
+ gcm_app_handler_.reset(new FakeExtensionGCMAppHandler(profile(), &waiter_));
+ }
+
+ virtual void TearDown() OVERRIDE {
+#if defined(OS_CHROMEOS)
+ test_user_manager_.reset();
+#endif
+
+ waiter_.PumpUILoop();
+ }
+
+ // Returns a barebones test extension.
+ scoped_refptr<Extension> CreateExtension() {
+#if defined(OS_WIN)
+ base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
+#elif defined(OS_POSIX)
+ base::FilePath path(FILE_PATH_LITERAL("/foo"));
+#endif
+
+ base::DictionaryValue manifest;
+ manifest.SetString(manifest_keys::kVersion, "1.0.0.0");
+ manifest.SetString(manifest_keys::kName, kTestExtensionName);
+ base::ListValue* permission_list = new base::ListValue;
+ permission_list->Append(base::Value::CreateStringValue("gcm"));
+ manifest.Set(manifest_keys::kPermissions, permission_list);
+
+ std::string error;
+ scoped_refptr<Extension> extension = Extension::Create(
+ path.AppendASCII(kTestExtensionName),
+ Manifest::INVALID_LOCATION,
+ manifest,
+ Extension::NO_FLAGS,
+ &error);
+ EXPECT_TRUE(extension.get()) << error;
+ EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kGcm));
+
+ return extension;
+ }
+
+ void LoadExtension(const Extension* extension) {
+ extension_service_->AddExtension(extension);
+ }
+
+ void DisableExtension(const Extension* extension) {
+ extension_service_->DisableExtension(
+ extension->id(), Extension::DISABLE_USER_ACTION);
+ }
+
+ void EnableExtension(const Extension* extension) {
+ extension_service_->EnableExtension(extension->id());
+ }
+
+ void UninstallExtension(const Extension* extension) {
+ extension_service_->UninstallExtension(extension->id(), false, NULL);
+ }
+
+ void SignIn(const std::string& username) {
+ signin_manager_->SignIn(username);
+ waiter_.PumpIOLoop();
+ }
+
+ void SignOut() {
+ signin_manager_->SignOut();
+ waiter_.PumpIOLoop();
+ }
+
+ void Register(const std::string& app_id,
+ const std::vector<std::string>& sender_ids) {
+ GetGCMProfileService()->Register(
+ app_id,
+ sender_ids,
+ base::Bind(&ExtensionGCMAppHandlerTest::RegisterCompleted,
+ base::Unretained(this)));
+ }
+
+ void RegisterCompleted(const std::string& registration_id,
+ GCMClient::Result result) {
+ registration_result_ = result;
+ waiter_.SignalCompleted();
+ }
+
+ GCMProfileService* GetGCMProfileService() const {
+ return GCMProfileServiceFactory::GetForProfile(profile());
+ }
+
+ bool HasAppHandlers(const std::string& app_id) const {
+ return GetGCMProfileService()->app_handlers_.count(app_id);
+ }
+
+ Profile* profile() const { return profile_.get(); }
+ Waiter* waiter() { return &waiter_; }
+ FakeExtensionGCMAppHandler* gcm_app_handler() const {
+ return gcm_app_handler_.get();
+ }
+ GCMClient::Result registration_result() const { return registration_result_; }
+ GCMClient::Result unregistration_result() const {
+ return unregistration_result_;
+ }
+
+ private:
+ scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
+ scoped_ptr<TestingProfile> profile_;
+ ExtensionService* extension_service_; // Not owned.
+ gcm::FakeSigninManager* signin_manager_; // Not owned.
+
+ // This is needed to create extension service under CrOS.
+#if defined(OS_CHROMEOS)
+ chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
+ chromeos::ScopedTestCrosSettings test_cros_settings_;
+ scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
+#endif
+
+ Waiter waiter_;
+ scoped_ptr<FakeExtensionGCMAppHandler> gcm_app_handler_;
+ GCMClient::Result registration_result_;
+ GCMClient::Result unregistration_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionGCMAppHandlerTest);
+};
+
+TEST_F(ExtensionGCMAppHandlerTest, AddAndRemoveAppHandler) {
+ scoped_refptr<Extension> extension(CreateExtension());
+
+ // App handler is added when extension is loaded.
+ LoadExtension(extension);
+ waiter()->PumpUILoop();
+ EXPECT_TRUE(HasAppHandlers(extension->id()));
+
+ // App handler is removed when extension is unloaded.
+ DisableExtension(extension);
+ waiter()->PumpUILoop();
+ EXPECT_FALSE(HasAppHandlers(extension->id()));
+
+ // App handler is added when extension is reloaded.
+ EnableExtension(extension);
+ waiter()->PumpUILoop();
+ EXPECT_TRUE(HasAppHandlers(extension->id()));
+
+ // App handler is removed when extension is uninstalled.
+ UninstallExtension(extension);
+ waiter()->PumpUILoop();
+ EXPECT_FALSE(HasAppHandlers(extension->id()));
+}
+
+TEST_F(ExtensionGCMAppHandlerTest, UnregisterOnExtensionUninstall) {
+ scoped_refptr<Extension> extension(CreateExtension());
+ LoadExtension(extension);
+
+ // Sign-in is needed for registration.
+ SignIn(kTestingUsername);
+
+ // Kick off registration.
+ std::vector<std::string> sender_ids;
+ sender_ids.push_back("sender1");
+ Register(extension->id(), sender_ids);
+ waiter()->WaitUntilCompleted();
+ EXPECT_EQ(GCMClient::SUCCESS, registration_result());
+
+ // Unregistration should be triggered when the extension is uninstalled.
+ UninstallExtension(extension);
+ waiter()->WaitUntilCompleted();
+ EXPECT_EQ(GCMClient::SUCCESS, gcm_app_handler()->unregistration_result());
+}
+
+} // namespace extensions
diff --git a/chrome/browser/services/gcm/gcm_client_mock.cc b/chrome/browser/services/gcm/gcm_client_mock.cc
index 3292f3fa..3b58cda 100644
--- a/chrome/browser/services/gcm/gcm_client_mock.cc
+++ b/chrome/browser/services/gcm/gcm_client_mock.cc
@@ -13,12 +13,10 @@
namespace gcm {
-GCMClientMock::GCMClientMock(LoadingDelay loading_delay,
- ErrorSimulation error_simulation)
+GCMClientMock::GCMClientMock(LoadingDelay loading_delay)
: delegate_(NULL),
status_(UNINITIALIZED),
loading_delay_(loading_delay),
- error_simulation_(error_simulation),
weak_ptr_factory_(this) {
}
@@ -67,10 +65,7 @@
const std::vector<std::string>& sender_ids) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- std::string registration_id;
- if (error_simulation_ == ALWAYS_SUCCEED)
- registration_id = GetRegistrationIdFromSenderIds(sender_ids);
-
+ std::string registration_id = GetRegistrationIdFromSenderIds(sender_ids);
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&GCMClientMock::RegisterFinished,
diff --git a/chrome/browser/services/gcm/gcm_client_mock.h b/chrome/browser/services/gcm/gcm_client_mock.h
index 2a1004a..2cdc104 100644
--- a/chrome/browser/services/gcm/gcm_client_mock.h
+++ b/chrome/browser/services/gcm/gcm_client_mock.h
@@ -25,14 +25,8 @@
DELAY_LOADING,
};
- enum ErrorSimulation {
- ALWAYS_SUCCEED,
- FORCE_ERROR
- };
-
// |loading_delay| denotes if the check-in should be delayed.
- // |error_simulation| denotes if we should simulate server error.
- GCMClientMock(LoadingDelay loading_delay, ErrorSimulation error_simulation);
+ explicit GCMClientMock(LoadingDelay loading_delay);
virtual ~GCMClientMock();
// Overridden from GCMClient:
@@ -88,7 +82,6 @@
Delegate* delegate_;
Status status_;
LoadingDelay loading_delay_;
- ErrorSimulation error_simulation_;
base::WeakPtrFactory<GCMClientMock> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GCMClientMock);
diff --git a/chrome/browser/services/gcm/gcm_profile_service.h b/chrome/browser/services/gcm/gcm_profile_service.h
index 39b72663..3817b0e 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.h
+++ b/chrome/browser/services/gcm/gcm_profile_service.h
@@ -27,6 +27,10 @@
class Value;
}
+namespace extensions {
+class ExtensionGCMAppHandlerTest;
+}
+
namespace user_prefs {
class PrefRegistrySyncable;
}
@@ -131,6 +135,7 @@
private:
friend class GCMProfileServiceTestConsumer;
+ friend class extensions::ExtensionGCMAppHandlerTest;
class DelayedTaskController;
class IOWorker;
diff --git a/chrome/browser/services/gcm/gcm_profile_service_test_helper.cc b/chrome/browser/services/gcm/gcm_profile_service_test_helper.cc
new file mode 100644
index 0000000..2379482
--- /dev/null
+++ b/chrome/browser/services/gcm/gcm_profile_service_test_helper.cc
@@ -0,0 +1,119 @@
+// 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/gcm_profile_service_test_helper.h"
+
+#include "base/bind.h"
+#include "base/prefs/pref_service.h"
+#include "base/run_loop.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/chrome_signin_client_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace gcm {
+
+Waiter::Waiter() {
+}
+
+Waiter::~Waiter() {
+}
+
+void Waiter::WaitUntilCompleted() {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+}
+
+void Waiter::SignalCompleted() {
+ if (run_loop_ && run_loop_->running())
+ run_loop_->Quit();
+}
+
+void Waiter::PumpUILoop() {
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
+void Waiter::PumpIOLoop() {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&Waiter::OnIOLoopPump, base::Unretained(this)));
+
+ WaitUntilCompleted();
+}
+
+void Waiter::PumpIOLoopCompleted() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ SignalCompleted();
+}
+
+void Waiter::OnIOLoopPump() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&Waiter::OnIOLoopPumpCompleted, base::Unretained(this)));
+}
+
+void Waiter::OnIOLoopPumpCompleted() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&Waiter::PumpIOLoopCompleted,
+ base::Unretained(this)));
+}
+
+// static
+KeyedService* FakeSigninManager::Build(content::BrowserContext* context) {
+ return new FakeSigninManager(static_cast<Profile*>(context));
+}
+
+FakeSigninManager::FakeSigninManager(Profile* profile)
+#if defined(OS_CHROMEOS)
+ : SigninManagerBase(
+ ChromeSigninClientFactory::GetInstance()->GetForProfile(profile)),
+#else
+ : SigninManager(
+ ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)),
+#endif
+ profile_(profile) {
+ Initialize(NULL);
+}
+
+FakeSigninManager::~FakeSigninManager() {
+}
+
+void FakeSigninManager::SignIn(const std::string& username) {
+ SetAuthenticatedUsername(username);
+ FOR_EACH_OBSERVER(Observer,
+ observer_list_,
+ GoogleSigninSucceeded(username, std::string()));
+}
+
+void FakeSigninManager::SignOut() {
+ std::string username = GetAuthenticatedUsername();
+ clear_authenticated_username();
+ profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername);
+ FOR_EACH_OBSERVER(Observer, observer_list_, GoogleSignedOut(username));
+}
+
+FakeGCMClientFactory::FakeGCMClientFactory(
+ GCMClientMock::LoadingDelay gcm_client_loading_delay)
+ : gcm_client_loading_delay_(gcm_client_loading_delay) {
+}
+
+FakeGCMClientFactory::~FakeGCMClientFactory() {
+}
+
+scoped_ptr<GCMClient> FakeGCMClientFactory::BuildInstance() {
+ return scoped_ptr<GCMClient>(new GCMClientMock(gcm_client_loading_delay_));
+}
+
+} // namespace gcm
diff --git a/chrome/browser/services/gcm/gcm_profile_service_test_helper.h b/chrome/browser/services/gcm/gcm_profile_service_test_helper.h
new file mode 100644
index 0000000..66eea37
--- /dev/null
+++ b/chrome/browser/services/gcm/gcm_profile_service_test_helper.h
@@ -0,0 +1,94 @@
+// 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_GCM_PROFILE_SERVICE_TEST_HELPER_H_
+#define CHROME_BROWSER_SERVICES_GCM_GCM_PROFILE_SERVICE_TEST_HELPER_H_
+
+#include <string>
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/services/gcm/gcm_client_factory.h"
+#include "chrome/browser/services/gcm/gcm_client_mock.h"
+#include "components/signin/core/browser/signin_manager.h"
+
+class KeyedService;
+class Profile;
+namespace base {
+class RunLoop;
+}
+namespace content {
+class BrowserContext;
+}
+
+namespace gcm {
+
+// Helper class for asynchronous waiting.
+class Waiter {
+ public:
+ Waiter();
+ ~Waiter();
+
+ // Waits until the asynchrnous operation finishes.
+ void WaitUntilCompleted();
+
+ // Signals that the asynchronous operation finishes.
+ void SignalCompleted();
+
+ // Runs until UI loop becomes idle.
+ void PumpUILoop();
+
+ // Runs until IO loop becomes idle.
+ void PumpIOLoop();
+
+ private:
+ void PumpIOLoopCompleted();
+ void OnIOLoopPump();
+ void OnIOLoopPumpCompleted();
+
+ scoped_ptr<base::RunLoop> run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(Waiter);
+};
+
+#if defined(OS_CHROMEOS)
+class FakeSigninManager : public SigninManagerBase {
+#else
+class FakeSigninManager : public SigninManager {
+#endif
+ public:
+ static KeyedService* Build(content::BrowserContext* context);
+
+ explicit FakeSigninManager(Profile* profile);
+ virtual ~FakeSigninManager();
+
+ void SignIn(const std::string& username);
+#if defined(OS_CHROMEOS)
+ void SignOut();
+#else
+ virtual void SignOut() OVERRIDE;
+#endif
+
+ private:
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeSigninManager);
+};
+
+class FakeGCMClientFactory : public GCMClientFactory {
+ public:
+ explicit FakeGCMClientFactory(
+ GCMClientMock::LoadingDelay gcm_client_loading_delay);
+ virtual ~FakeGCMClientFactory();
+
+ virtual scoped_ptr<GCMClient> BuildInstance() OVERRIDE;
+
+ private:
+ GCMClientMock::LoadingDelay gcm_client_loading_delay_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeGCMClientFactory);
+};
+
+} // namespace gcm
+
+#endif // CHROME_BROWSER_SERVICES_GCM_GCM_PROFILE_SERVICE_TEST_HELPER_H_
diff --git a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
index db5719a..9be82fe 100644
--- a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
@@ -2,56 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <algorithm>
-#include <map>
-
#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
-#include "base/run_loop.h"
-#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/extension_gcm_app_handler.h"
-#include "chrome/browser/extensions/state_store.h"
-#include "chrome/browser/extensions/test_extension_service.h"
-#include "chrome/browser/extensions/test_extension_system.h"
#include "chrome/browser/services/gcm/gcm_app_handler.h"
#include "chrome/browser/services/gcm/gcm_client_factory.h"
#include "chrome/browser/services/gcm/gcm_client_mock.h"
#include "chrome/browser/services/gcm/gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
-#include "chrome/browser/signin/chrome_signin_client.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
+#include "chrome/browser/services/gcm/gcm_profile_service_test_helper.h"
#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
-#include "components/os_crypt/os_crypt.h"
-#include "components/signin/core/browser/signin_manager_base.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/device_settings_service.h"
-#else
-#include "components/signin/core/browser/signin_manager.h"
-#endif
-
-using namespace extensions;
-
namespace gcm {
namespace {
-const char kTestExtensionName[] = "FooBar";
const char kTestingUsername[] = "[email protected]";
const char kTestingUsername2[] = "[email protected]";
const char kTestingUsername3[] = "[email protected]";
@@ -62,108 +33,13 @@
std::vector<std::string> ToSenderList(const std::string& sender_ids) {
std::vector<std::string> senders;
- base::StringTokenizer tokenizer(sender_ids, ",");
- while (tokenizer.GetNext())
- senders.push_back(tokenizer.token());
+ Tokenize(sender_ids, ",", &senders);
return senders;
}
-// Helper class for asynchrnous waiting.
-class Waiter {
- public:
- Waiter() {}
- virtual ~Waiter() {}
-
- // Waits until the asynchrnous operation finishes.
- void WaitUntilCompleted() {
- run_loop_.reset(new base::RunLoop);
- run_loop_->Run();
- }
-
- // Signals that the asynchronous operation finishes.
- void SignalCompleted() {
- if (run_loop_ && run_loop_->running())
- run_loop_->Quit();
- }
-
- // Runs until UI loop becomes idle.
- void PumpUILoop() {
- base::MessageLoop::current()->RunUntilIdle();
- }
-
- // Runs until IO loop becomes idle.
- void PumpIOLoop() {
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(&Waiter::OnIOLoopPump, base::Unretained(this)));
-
- WaitUntilCompleted();
- }
-
- private:
- void PumpIOLoopCompleted() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
- SignalCompleted();
- }
-
- void OnIOLoopPump() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(&Waiter::OnIOLoopPumpCompleted, base::Unretained(this)));
- }
-
- void OnIOLoopPumpCompleted() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::UI,
- FROM_HERE,
- base::Bind(&Waiter::PumpIOLoopCompleted,
- base::Unretained(this)));
- }
-
- scoped_ptr<base::RunLoop> run_loop_;
-};
-
-class FakeSigninManager : public SigninManagerBase {
- public:
- explicit FakeSigninManager(Profile* profile)
- : SigninManagerBase(
- ChromeSigninClientFactory::GetInstance()->GetForProfile(profile)),
- profile_(profile) {
- Initialize(NULL);
- }
-
- virtual ~FakeSigninManager() {
- }
-
- void SignIn(const std::string& username) {
- SetAuthenticatedUsername(username);
- FOR_EACH_OBSERVER(Observer,
- observer_list_,
- GoogleSigninSucceeded(username, std::string()));
- }
-
- void SignOut() {
- std::string username = GetAuthenticatedUsername();
- clear_authenticated_username();
- profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername);
- FOR_EACH_OBSERVER(Observer, observer_list_, GoogleSignedOut(username));
- }
-
- private:
- Profile* profile_;
-};
-
} // namespace
-// TODO(jianli): Move extension specific tests to a separate file.
-class FakeGCMAppHandler : public ExtensionGCMAppHandler {
+class FakeGCMAppHandler : public GCMAppHandler {
public:
enum Event {
NO_EVENT,
@@ -172,15 +48,17 @@
SEND_ERROR_EVENT
};
- FakeGCMAppHandler(Profile* profile, Waiter* waiter)
- : ExtensionGCMAppHandler(profile),
- waiter_(waiter),
+ explicit FakeGCMAppHandler(Waiter* waiter)
+ : waiter_(waiter),
received_event_(NO_EVENT) {
}
virtual ~FakeGCMAppHandler() {
}
+ virtual void ShutdownHandler() OVERRIDE {
+ }
+
virtual void OnMessage(const std::string& app_id,
const GCMClient::IncomingMessage& message) OVERRIDE {
clear_results();
@@ -238,42 +116,8 @@
GCMClient::SendErrorDetails send_error_details_;
};
-class FakeGCMClientFactory : public GCMClientFactory {
- public:
- FakeGCMClientFactory(
- GCMClientMock::LoadingDelay gcm_client_loading_delay,
- GCMClientMock::ErrorSimulation gcm_client_error_simulation)
- : gcm_client_loading_delay_(gcm_client_loading_delay),
- gcm_client_error_simulation_(gcm_client_error_simulation),
- gcm_client_(NULL) {
- }
-
- virtual ~FakeGCMClientFactory() {
- }
-
- virtual scoped_ptr<GCMClient> BuildInstance() OVERRIDE {
- gcm_client_ = new GCMClientMock(gcm_client_loading_delay_,
- gcm_client_error_simulation_);
- return scoped_ptr<GCMClient>(gcm_client_);
- }
-
- GCMClientMock* gcm_client() const { return gcm_client_; }
-
- private:
- GCMClientMock::LoadingDelay gcm_client_loading_delay_;
- GCMClientMock::ErrorSimulation gcm_client_error_simulation_;
- GCMClientMock* gcm_client_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeGCMClientFactory);
-};
-
class GCMProfileServiceTestConsumer {
public:
- static KeyedService* BuildFakeSigninManager(
- content::BrowserContext* context) {
- return new FakeSigninManager(static_cast<Profile*>(context));
- }
-
static KeyedService* BuildGCMProfileService(
content::BrowserContext* context) {
return new GCMProfileService(static_cast<Profile*>(context));
@@ -281,37 +125,18 @@
explicit GCMProfileServiceTestConsumer(Waiter* waiter)
: waiter_(waiter),
- extension_service_(NULL),
signin_manager_(NULL),
gcm_client_loading_delay_(GCMClientMock::NO_DELAY_LOADING),
- gcm_client_error_simulation_(GCMClientMock::ALWAYS_SUCCEED),
- registration_result_(GCMClient::SUCCESS),
- has_persisted_registration_info_(false),
- send_result_(GCMClient::SUCCESS) {
+ registration_result_(GCMClient::UNKNOWN_ERROR),
+ unregistration_result_(GCMClient::UNKNOWN_ERROR),
+ send_result_(GCMClient::UNKNOWN_ERROR) {
// Create a new profile.
TestingProfile::Builder builder;
- builder.AddTestingFactory(
- SigninManagerFactory::GetInstance(),
- GCMProfileServiceTestConsumer::BuildFakeSigninManager);
+ builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
+ FakeSigninManager::Build);
profile_ = builder.Build();
-
- SigninManagerBase* signin_manager =
- SigninManagerFactory::GetInstance()->GetForProfile(profile_.get());
- signin_manager_ = static_cast<FakeSigninManager*>(signin_manager);
-
- // Create extension service in order to uninstall the extension.
- extensions::TestExtensionSystem* extension_system(
- static_cast<extensions::TestExtensionSystem*>(
- extensions::ExtensionSystem::Get(profile())));
- extension_system->CreateExtensionService(
- CommandLine::ForCurrentProcess(), base::FilePath(), false);
- extension_service_ = extension_system->Get(profile())->extension_service();
-
- // EventRouter is needed for GcmJsEventRouter.
- if (!extension_system->event_router()) {
- extension_system->SetEventRouter(scoped_ptr<EventRouter>(
- new EventRouter(profile(), ExtensionPrefs::Get(profile()))));
- }
+ signin_manager_ = static_cast<FakeSigninManager*>(
+ SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
// Enable GCM such that tests could be run on all channels.
profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true);
@@ -322,55 +147,15 @@
GetGCMProfileService()->RemoveAppHandler(kTestingAppId2);
}
- // Returns a barebones test extension.
- scoped_refptr<Extension> CreateExtension() {
-#if defined(OS_WIN)
- base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
-#elif defined(OS_POSIX)
- base::FilePath path(FILE_PATH_LITERAL("/foo"));
-#endif
-
- base::DictionaryValue manifest;
- manifest.SetString(manifest_keys::kVersion, "1.0.0.0");
- manifest.SetString(manifest_keys::kName, kTestExtensionName);
- base::ListValue* permission_list = new base::ListValue;
- permission_list->Append(base::Value::CreateStringValue("gcm"));
- manifest.Set(manifest_keys::kPermissions, permission_list);
-
- std::string error;
- scoped_refptr<Extension> extension =
- Extension::Create(path.AppendASCII(kTestExtensionName),
- Manifest::INVALID_LOCATION,
- manifest,
- Extension::NO_FLAGS,
- &error);
- EXPECT_TRUE(extension.get()) << error;
- EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kGcm));
-
- extension_service_->AddExtension(extension.get());
- return extension;
- }
-
- void UninstallExtension(const extensions::Extension* extension) {
- extension_service_->UninstallExtension(extension->id(), false, NULL);
- }
-
- void ReloadExtension(const extensions::Extension* extension) {
- extension_service_->UnloadExtension(
- extension->id(), UnloadedExtensionInfo::REASON_TERMINATE);
- extension_service_->AddExtension(extension);
- }
-
void CreateGCMProfileServiceInstance() {
GCMProfileService* gcm_profile_service = static_cast<GCMProfileService*>(
GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(), &GCMProfileServiceTestConsumer::BuildGCMProfileService));
scoped_ptr<GCMClientFactory> gcm_client_factory(
- new FakeGCMClientFactory(gcm_client_loading_delay_,
- gcm_client_error_simulation_));
+ new FakeGCMClientFactory(gcm_client_loading_delay_));
gcm_profile_service->Initialize(gcm_client_factory.Pass());
- gcm_app_handler_.reset(new FakeGCMAppHandler(profile(), waiter_));
+ gcm_app_handler_.reset(new FakeGCMAppHandler(waiter_));
gcm_profile_service->AddAppHandler(kTestingAppId, gcm_app_handler());
gcm_profile_service->AddAppHandler(kTestingAppId2, gcm_app_handler());
@@ -463,9 +248,6 @@
void set_gcm_client_loading_delay(GCMClientMock::LoadingDelay delay) {
gcm_client_loading_delay_ = delay;
}
- void set_gcm_client_error_simulation(GCMClientMock::ErrorSimulation error) {
- gcm_client_error_simulation_ = error;
- }
const std::string& registration_id() const { return registration_id_; }
GCMClient::Result registration_result() const { return registration_result_; }
@@ -490,16 +272,13 @@
private:
Waiter* waiter_; // Not owned.
scoped_ptr<TestingProfile> profile_;
- ExtensionService* extension_service_; // Not owned.
FakeSigninManager* signin_manager_; // Not owned.
scoped_ptr<FakeGCMAppHandler> gcm_app_handler_;
GCMClientMock::LoadingDelay gcm_client_loading_delay_;
- GCMClientMock::ErrorSimulation gcm_client_error_simulation_;
std::string registration_id_;
GCMClient::Result registration_result_;
- bool has_persisted_registration_info_;
GCMClient::Result unregistration_result_;
@@ -523,28 +302,13 @@
thread_bundle_.reset(new content::TestBrowserThreadBundle(
content::TestBrowserThreadBundle::REAL_IO_THREAD));
- // This is needed to create extension service under CrOS.
-#if defined(OS_CHROMEOS)
- test_user_manager_.reset(new chromeos::ScopedTestUserManager());
-#endif
-
- // OSCrypt ends up needing access to the keychain on OS X. So use the mock
- // keychain to prevent prompts.
-#if defined(OS_MACOSX)
- OSCrypt::UseMockKeychain(true);
-#endif
-
// Create a main profile consumer.
consumer_.reset(new GCMProfileServiceTestConsumer(&waiter_));
}
virtual void TearDown() OVERRIDE {
-#if defined(OS_CHROMEOS)
- test_user_manager_.reset();
-#endif
-
consumer_.reset();
- base::RunLoop().RunUntilIdle();
+ PumpUILoop();
}
void WaitUntilCompleted() {
@@ -571,12 +335,6 @@
private:
scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
-#if defined(OS_CHROMEOS)
- chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
- chromeos::ScopedTestCrosSettings test_cros_settings_;
- scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
-#endif
-
scoped_ptr<GCMProfileServiceTestConsumer> consumer_;
DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceTest);
@@ -895,40 +653,24 @@
}
TEST_F(GCMProfileServiceSingleProfileTest,
- GCMClientReadyAfterReadingRegistration) {
- scoped_refptr<Extension> extension(consumer()->CreateExtension());
-
- std::vector<std::string> sender_ids;
- sender_ids.push_back("sender1");
- consumer()->Register(extension->id(), sender_ids);
-
- WaitUntilCompleted();
- EXPECT_FALSE(consumer()->registration_id().empty());
- EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
- std::string old_registration_id = consumer()->registration_id();
-
- // Clears the results that would be set by the Register callback in
- // preparation to call register 2nd time.
- consumer()->clear_registration_result();
-
- // Simulate start-up by recreating GCMProfileService.
+ GCMClientNotReadyBeforeRegistration) {
+ // Make GCMClient not ready initially.
consumer()->set_gcm_client_loading_delay(GCMClientMock::DELAY_LOADING);
consumer()->CreateGCMProfileServiceInstance();
- // Simulate start-up by reloading extension.
- consumer()->ReloadExtension(extension);
-
- // Read the registration info from the extension's state store.
- // This would hold up because GCMClient is in loading state.
- consumer()->Register(extension->id(), sender_ids);
- base::RunLoop().RunUntilIdle();
+ // The registration is on hold until GCMClient is ready.
+ std::vector<std::string> sender_ids;
+ sender_ids.push_back("sender1");
+ consumer()->Register(kTestingAppId, sender_ids);
+ PumpIOLoop();
EXPECT_TRUE(consumer()->registration_id().empty());
EXPECT_EQ(GCMClient::UNKNOWN_ERROR, consumer()->registration_result());
// Register operation will be invoked after GCMClient becomes ready.
consumer()->GetGCMClient()->PerformDelayedLoading();
- WaitUntilCompleted();
- EXPECT_EQ(old_registration_id, consumer()->registration_id());
+ PumpIOLoop(); // The 1st pump is to wait till the delayed loading is done.
+ PumpIOLoop(); // The 2nd pump is to wait till the registration is done.
+ EXPECT_FALSE(consumer()->registration_id().empty());
EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
@@ -944,22 +686,6 @@
EXPECT_EQ(GCMClient::NOT_SIGNED_IN, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceSingleProfileTest, UnregisterImplicitly) {
- scoped_refptr<Extension> extension(consumer()->CreateExtension());
-
- std::vector<std::string> sender_ids;
- sender_ids.push_back("sender1");
- consumer()->Register(extension->id(), sender_ids);
-
- WaitUntilCompleted();
- EXPECT_FALSE(consumer()->registration_id().empty());
- EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
-
- // Uninstall the extension.
- consumer()->UninstallExtension(extension);
- base::MessageLoop::current()->RunUntilIdle();
-}
-
TEST_F(GCMProfileServiceSingleProfileTest, UnregisterExplicitly) {
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
@@ -1059,6 +785,29 @@
EXPECT_EQ(GCMClient::SUCCESS, consumer()->send_result());
}
+TEST_F(GCMProfileServiceSingleProfileTest, GCMClientNotReadyBeforeSending) {
+ // Make GCMClient not ready initially.
+ consumer()->set_gcm_client_loading_delay(GCMClientMock::DELAY_LOADING);
+ consumer()->CreateGCMProfileServiceInstance();
+
+ // The sending is on hold until GCMClient is ready.
+ GCMClient::OutgoingMessage message;
+ message.id = "1";
+ message.data["key1"] = "value1";
+ message.data["key2"] = "value2";
+ consumer()->Send(kTestingAppId, kUserId, message);
+ PumpIOLoop();
+ EXPECT_TRUE(consumer()->send_message_id().empty());
+ EXPECT_EQ(GCMClient::UNKNOWN_ERROR, consumer()->send_result());
+
+ // Register operation will be invoked after GCMClient becomes ready.
+ consumer()->GetGCMClient()->PerformDelayedLoading();
+ PumpIOLoop();
+ PumpIOLoop();
+ EXPECT_EQ(consumer()->send_message_id(), message.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->send_result());
+}
+
TEST_F(GCMProfileServiceSingleProfileTest, SendAfterSignOut) {
// This will trigger check-out.
consumer()->SignOut();
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 91e5bd3..539dc98 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -939,6 +939,7 @@
'browser/extensions/extension_function_test_utils.cc',
'browser/extensions/extension_function_test_utils.h',
'browser/extensions/extension_garbage_collector_unittest.cc',
+ 'browser/extensions/extension_gcm_app_handler_unittest.cc',
'browser/extensions/extension_icon_image_unittest.cc',
'browser/extensions/extension_icon_manager_unittest.cc',
'browser/extensions/extension_message_bubble_controller_unittest.cc',
@@ -1263,6 +1264,8 @@
'browser/search_engines/template_url_unittest.cc',
'browser/services/gcm/gcm_client_mock.cc',
'browser/services/gcm/gcm_client_mock.h',
+ 'browser/services/gcm/gcm_profile_service_test_helper.cc',
+ 'browser/services/gcm/gcm_profile_service_test_helper.h',
'browser/services/gcm/gcm_profile_service_unittest.cc',
'browser/sessions/persistent_tab_restore_service_unittest.cc',
'browser/sessions/restore_on_startup_policy_handler_unittest.cc',