summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-24 07:24:45 +0000
committerjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-24 07:24:45 +0000
commitc7f7b530b5710dce3e3fcba0954e077bc604f129 (patch)
tree0fa30f3c177ed2fcc05162c54fbb747351b4f2d1
parent134ea7d78230d9fd40b81a45ede45d3cb6d1bafa (diff)
downloadchromium_src-c7f7b530b5710dce3e3fcba0954e077bc604f129.zip
chromium_src-c7f7b530b5710dce3e3fcba0954e077bc604f129.tar.gz
chromium_src-c7f7b530b5710dce3e3fcba0954e077bc604f129.tar.bz2
[GCM] Add more GCM tests and fix bugs found by these tests
Add more test cases to cover more cases, including: 1) sign-in, sign-out and resign-in 2) multi-profile BUG=284553 TEST=new tests Review URL: https://codereview.chromium.org/134643007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246799 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/api/gcm/gcm_api.cc3
-rw-r--r--chrome/browser/services/gcm/gcm_client_mock.cc35
-rw-r--r--chrome/browser/services/gcm/gcm_profile_service.cc36
-rw-r--r--chrome/browser/services/gcm/gcm_profile_service.h8
-rw-r--r--chrome/browser/services/gcm/gcm_profile_service_unittest.cc1355
-rw-r--r--google_apis/gcm/gcm_client.h2
6 files changed, 1064 insertions, 375 deletions
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.cc b/chrome/browser/extensions/api/gcm/gcm_api.cc
index 6bd2a47..2034c40 100644
--- a/chrome/browser/extensions/api/gcm/gcm_api.cc
+++ b/chrome/browser/extensions/api/gcm/gcm_api.cc
@@ -30,6 +30,7 @@ const size_t kGooglePrefixLength = arraysize(kGoogleRestrictedPrefix) - 1;
// Error messages.
const char kInvalidParameter[] =
"Function was called with invalid parameters.";
+const char kNotSignedIn[] = "Profile was not signed in.";
const char kAsyncOperationPending[] =
"Asynchronous operation is pending.";
const char kNetworkError[] = "Network error occured.";
@@ -48,6 +49,8 @@ const char* GcmResultToError(gcm::GCMClient::Result result) {
return "";
case gcm::GCMClient::INVALID_PARAMETER:
return kInvalidParameter;
+ case gcm::GCMClient::NOT_SIGNED_IN:
+ return kNotSignedIn;
case gcm::GCMClient::ASYNC_OPERATION_PENDING:
return kAsyncOperationPending;
case gcm::GCMClient::NETWORK_ERROR:
diff --git a/chrome/browser/services/gcm/gcm_client_mock.cc b/chrome/browser/services/gcm/gcm_client_mock.cc
index 35da43d..ea89924 100644
--- a/chrome/browser/services/gcm/gcm_client_mock.cc
+++ b/chrome/browser/services/gcm/gcm_client_mock.cc
@@ -157,16 +157,20 @@ GCMClient::CheckinInfo GCMClientMock::GetCheckinInfoFromUsername(
// static
std::string GCMClientMock::GetRegistrationIdFromSenderIds(
const std::vector<std::string>& sender_ids) {
+ // GCMProfileService normalizes the sender IDs by making them sorted.
+ std::vector<std::string> normalized_sender_ids = sender_ids;
+ std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
+
// Simulate the registration_id by concaternating all sender IDs.
// Set registration_id to empty to denote an error if sender_ids contains a
// hint.
std::string registration_id;
if (sender_ids.size() != 1 ||
sender_ids[0].find("error") == std::string::npos) {
- for (size_t i = 0; i < sender_ids.size(); ++i) {
+ for (size_t i = 0; i < normalized_sender_ids.size(); ++i) {
if (i > 0)
registration_id += ",";
- registration_id += sender_ids[i];
+ registration_id += normalized_sender_ids[i];
}
}
return registration_id;
@@ -176,27 +180,32 @@ GCMClient::Delegate* GCMClientMock::GetDelegate(
const std::string& username) const {
std::map<std::string, Delegate*>::const_iterator iter =
delegates_.find(username);
- DCHECK(iter != delegates_.end());
- return iter->second;
+ return iter == delegates_.end() ? NULL : iter->second;
}
void GCMClientMock::CheckInFinished(std::string username,
CheckinInfo checkin_info) {
- GetDelegate(username)->OnCheckInFinished(
+ GCMClient::Delegate* delegate = GetDelegate(username);
+ DCHECK(delegate);
+ delegate->OnCheckInFinished(
checkin_info, checkin_info.IsValid() ? SUCCESS : SERVER_ERROR);
}
void GCMClientMock::RegisterFinished(std::string username,
std::string app_id,
std::string registrion_id) {
- GetDelegate(username)->OnRegisterFinished(
+ GCMClient::Delegate* delegate = GetDelegate(username);
+ DCHECK(delegate);
+ delegate->OnRegisterFinished(
app_id, registrion_id, registrion_id.empty() ? SERVER_ERROR : SUCCESS);
}
void GCMClientMock::SendFinished(std::string username,
std::string app_id,
std::string message_id) {
- GetDelegate(username)->OnSendFinished(app_id, message_id, SUCCESS);
+ GCMClient::Delegate* delegate = GetDelegate(username);
+ DCHECK(delegate);
+ delegate->OnSendFinished(app_id, message_id, SUCCESS);
// Simulate send error if message id contains a hint.
if (message_id.find("error") != std::string::npos) {
@@ -214,17 +223,23 @@ void GCMClientMock::SendFinished(std::string username,
void GCMClientMock::MessageReceived(std::string username,
std::string app_id,
IncomingMessage message) {
- GetDelegate(username)->OnMessageReceived(app_id, message);
+ GCMClient::Delegate* delegate = GetDelegate(username);
+ if (delegate)
+ delegate->OnMessageReceived(app_id, message);
}
void GCMClientMock::MessagesDeleted(std::string username, std::string app_id) {
- GetDelegate(username)->OnMessagesDeleted(app_id);
+ GCMClient::Delegate* delegate = GetDelegate(username);
+ if (delegate)
+ delegate->OnMessagesDeleted(app_id);
}
void GCMClientMock::MessageSendError(std::string username,
std::string app_id,
std::string message_id) {
- GetDelegate(username)->OnMessageSendError(app_id, message_id, NETWORK_ERROR);
+ GCMClient::Delegate* delegate = GetDelegate(username);
+ if (delegate)
+ delegate->OnMessageSendError(app_id, message_id, NETWORK_ERROR);
}
void GCMClientMock::LoadingCompleted() {
diff --git a/chrome/browser/services/gcm/gcm_profile_service.cc b/chrome/browser/services/gcm/gcm_profile_service.cc
index a13f180..77fabbc 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service.cc
@@ -206,7 +206,7 @@ class GCMProfileService::IOWorker
// Called on IO thread.
void Initialize();
void SetUser(const std::string& username);
- void RemoveUser(const std::string& username);
+ void RemoveUser();
void CheckIn();
void SetCheckinInfo(const GCMClient::CheckinInfo& checkin_info);
void CheckOut();
@@ -367,14 +367,13 @@ void GCMProfileService::IOWorker::SetUser(const std::string& username) {
gcm_client_->SetUserDelegate(username_, this);
}
-void GCMProfileService::IOWorker::RemoveUser(const std::string& username) {
+void GCMProfileService::IOWorker::RemoveUser() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- DCHECK(!username.empty());
if (username_.empty())
return;
- username_.clear();
gcm_client_->SetUserDelegate(username_, NULL);
+ username_.clear();
}
void GCMProfileService::IOWorker::CheckIn() {
@@ -393,8 +392,8 @@ void GCMProfileService::IOWorker::SetCheckinInfo(
void GCMProfileService::IOWorker::CheckOut() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- username_.clear();
checkin_info_.Reset();
+ RemoveUser();
}
void GCMProfileService::IOWorker::Register(
@@ -479,8 +478,7 @@ GCMProfileService::~GCMProfileService() {
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&GCMProfileService::IOWorker::RemoveUser,
- io_worker_,
- username_));
+ io_worker_));
}
void GCMProfileService::Initialize() {
@@ -524,6 +522,12 @@ void GCMProfileService::Register(const std::string& app_id,
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!app_id.empty() && !sender_ids.empty() && !callback.is_null());
+ // If the profile was not signed in, bail out.
+ if (username_.empty()) {
+ callback.Run(std::string(), GCMClient::NOT_SIGNED_IN);
+ return;
+ }
+
// If previous register operation is still in progress, bail out.
if (register_callbacks_.find(app_id) != register_callbacks_.end()) {
callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
@@ -590,6 +594,12 @@ void GCMProfileService::Send(const std::string& app_id,
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!app_id.empty() && !receiver_id.empty() && !callback.is_null());
+ // If the profile was not signed in, bail out.
+ if (username_.empty()) {
+ callback.Run(std::string(), GCMClient::NOT_SIGNED_IN);
+ return;
+ }
+
// If the message with send ID is still in progress, bail out.
std::pair<std::string, std::string> key(app_id, message.id);
if (send_callbacks_.find(key) != send_callbacks_.end()) {
@@ -833,12 +843,20 @@ void GCMProfileService::MessageReceived(const std::string& app_id,
GCMClient::IncomingMessage message) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ // Drop the event if signed out.
+ if (username_.empty())
+ return;
+
GetEventRouter(app_id)->OnMessage(app_id, message);
}
void GCMProfileService::MessagesDeleted(const std::string& app_id) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ // Drop the event if signed out.
+ if (username_.empty())
+ return;
+
GetEventRouter(app_id)->OnMessagesDeleted(app_id);
}
@@ -847,6 +865,10 @@ void GCMProfileService::MessageSendError(const std::string& app_id,
GCMClient::Result result) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ // Drop the event if signed out.
+ if (username_.empty())
+ return;
+
GetEventRouter(app_id)->OnSendError(app_id, message_id, result);
}
diff --git a/chrome/browser/services/gcm/gcm_profile_service.h b/chrome/browser/services/gcm/gcm_profile_service.h
index b364460..a0aae0e 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.h
+++ b/chrome/browser/services/gcm/gcm_profile_service.h
@@ -35,7 +35,7 @@ class PrefRegistrySyncable;
namespace gcm {
class GCMEventRouter;
-class GCMProfileServiceTest;
+class GCMProfileServiceTestConsumer;
// Acts as a bridge between GCM API and GCMClient layer. It is profile based.
class GCMProfileService : public BrowserContextKeyedService,
@@ -99,11 +99,7 @@ class GCMProfileService : public BrowserContextKeyedService,
static bool enable_gcm_for_testing_;
private:
- friend class GCMProfileServiceTest;
- friend class GCMProfileServiceRegisterTest;
- FRIEND_TEST_ALL_PREFIXES(GCMProfileServiceTest, CheckInFromPrefsStore);
- FRIEND_TEST_ALL_PREFIXES(GCMProfileServiceTest, CheckOut);
- FRIEND_TEST_ALL_PREFIXES(GCMProfileServiceRegisterTest, Unregister);
+ friend class GCMProfileServiceTestConsumer;
class DelayedTaskController;
class IOWorker;
diff --git a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
index bec467c..4b2e3b6 100644
--- a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
@@ -3,12 +3,15 @@
// found in the LICENSE file.
#include <algorithm>
+#include <map>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
+#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/run_loop.h"
+#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/state_store.h"
#include "chrome/browser/extensions/test_extension_service.h"
#include "chrome/browser/extensions/test_extension_system.h"
@@ -17,13 +20,15 @@
#include "chrome/browser/services/gcm/gcm_event_router.h"
#include "chrome/browser/services/gcm/gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
-#include "chrome/browser/signin/fake_signin_manager.h"
+#include "chrome/browser/signin/signin_manager_base.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/features/feature_channel.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "components/webdata/encryptor/encryptor.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
@@ -39,15 +44,102 @@ using namespace extensions;
namespace gcm {
+namespace {
+
const char kTestExtensionName[] = "FooBar";
-const char kTestingUsername[] = "user@example.com";
-const char kTestingAppId[] = "test1";
+const char kTestingUsername[] = "user1@example.com";
+const char kTestingUsername2[] = "user2@example.com";
+const char kTestingUsername3[] = "user3@example.com";
+const char kTestingAppId[] = "TestApp1";
+const char kTestingAppId2[] = "TestApp2";
const char kTestingSha1Cert[] = "testing_cert1";
-const char kUserId[] = "user2";
+const char kUserId[] = "user1";
+const char kUserId2[] = "user2";
+
+// 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();
+ }
-class GCMProfileServiceTest;
+ // Signals that the asynchronous operation finishes.
+ void SignalCompleted() {
+ if (run_loop_ && run_loop_->running())
+ run_loop_->Quit();
+ }
+
+ // Runs until IO loop becomes idle.
+ void PumpIOLoop() {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&Waiter::OnIOLoopPump, base::Unretained(this)));
+
+ WaitUntilCompleted();
+ }
-class GCMEventRouterMock : public GCMEventRouter {
+ private:
+ void PumpIOLoopCompleted() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ SignalCompleted();
+ }
+
+ void OnIOLoopPump() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ base::MessageLoop::current()->RunUntilIdle();
+
+ 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) {
+ Initialize(profile, NULL);
+ }
+
+ virtual ~FakeSigninManager() {
+ }
+
+ void SignIn(const std::string& username) {
+ SetAuthenticatedUsername(username);
+
+ GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(),
+ std::string());
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
+ content::Source<Profile>(profile_),
+ content::Details<const GoogleServiceSigninSuccessDetails>(&details));
+ }
+
+ void SignOut() {
+ clear_authenticated_username();
+
+ GoogleServiceSignoutDetails details(GetAuthenticatedUsername());
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+ content::Source<Profile>(profile_),
+ content::Details<const GoogleServiceSignoutDetails>(&details));
+ }
+};
+
+} // namespace
+
+class FakeGCMEventRouter : public GCMEventRouter {
public:
enum Event {
NO_EVENT,
@@ -56,64 +148,91 @@ class GCMEventRouterMock : public GCMEventRouter {
SEND_ERROR_EVENT
};
- explicit GCMEventRouterMock(GCMProfileServiceTest* test);
- virtual ~GCMEventRouterMock();
+ explicit FakeGCMEventRouter(Waiter* waiter)
+ : waiter_(waiter),
+ received_event_(NO_EVENT),
+ send_error_result_(GCMClient::SUCCESS) {
+ }
+
+ virtual ~FakeGCMEventRouter() {
+ }
virtual void OnMessage(const std::string& app_id,
- const GCMClient::IncomingMessage& message) OVERRIDE;
- virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
+ const GCMClient::IncomingMessage& message) OVERRIDE {
+ clear_results();
+ received_event_ = MESSAGE_EVENT;
+ app_id_ = app_id;
+ message_ = message;
+ waiter_->SignalCompleted();
+ }
+
+ virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE {
+ clear_results();
+ received_event_ = MESSAGES_DELETED_EVENT;
+ app_id_ = app_id;
+ waiter_->SignalCompleted();
+ }
+
virtual void OnSendError(const std::string& app_id,
const std::string& message_id,
- GCMClient::Result result) OVERRIDE;
+ GCMClient::Result result) OVERRIDE {
+ clear_results();
+ received_event_ = SEND_ERROR_EVENT;
+ app_id_ = app_id;
+ send_error_message_id_ = message_id;
+ send_error_result_ = result;
+ waiter_->SignalCompleted();
+ }
Event received_event() const { return received_event_; }
const std::string& app_id() const { return app_id_; }
- const GCMClient::IncomingMessage incoming_message() const {
- return incoming_message_;
- }
+ const GCMClient::IncomingMessage& message() const { return message_; }
const std::string& send_message_id() const { return send_error_message_id_; }
GCMClient::Result send_result() const { return send_error_result_; }
+ void clear_results() {
+ received_event_ = NO_EVENT;
+ app_id_.clear();
+ message_.data.clear();
+ send_error_message_id_.clear();
+ send_error_result_ = GCMClient::UNKNOWN_ERROR;
+ }
+
private:
- GCMProfileServiceTest* test_;
+ Waiter* waiter_;
Event received_event_;
std::string app_id_;
- GCMClient::IncomingMessage incoming_message_;
+ GCMClient::IncomingMessage message_;
std::string send_error_message_id_;
GCMClient::Result send_error_result_;
};
-class GCMProfileServiceTest : public testing::Test,
- public GCMProfileService::TestingDelegate {
+class GCMProfileServiceTestConsumer : public GCMProfileService::TestingDelegate{
public:
- static BrowserContextKeyedService* BuildGCMProfileService(
- content::BrowserContext* profile) {
- return new GCMProfileService(static_cast<Profile*>(profile));
+ static BrowserContextKeyedService* BuildFakeSigninManager(
+ content::BrowserContext* context) {
+ return new FakeSigninManager(static_cast<Profile*>(context));
}
- static GCMClient* BuildGCMClient() {
- ANNOTATE_SCOPED_MEMORY_LEAK;
- return new GCMClientMock();
- }
-
- GCMProfileServiceTest() : extension_service_(NULL) {
- }
-
- virtual ~GCMProfileServiceTest() {
+ static BrowserContextKeyedService* BuildGCMProfileService(
+ content::BrowserContext* context) {
+ return new GCMProfileService(static_cast<Profile*>(context));
}
- // Overridden from test::Test:
- virtual void SetUp() OVERRIDE {
+ explicit GCMProfileServiceTestConsumer(Waiter* waiter)
+ : waiter_(waiter),
+ extension_service_(NULL),
+ signin_manager_(NULL),
+ registration_result_(GCMClient::SUCCESS),
+ has_persisted_registration_info_(false),
+ send_result_(GCMClient::SUCCESS) {
+ // Create a new profile.
profile_.reset(new TestingProfile);
- // 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
+ // Use a fake version of SigninManager.
+ signin_manager_ = static_cast<FakeSigninManager*>(
+ SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile(), &GCMProfileServiceTestConsumer::BuildFakeSigninManager));
// Create extension service in order to uninstall the extension.
extensions::TestExtensionSystem* extension_system(
@@ -123,70 +242,15 @@ class GCMProfileServiceTest : public testing::Test,
CommandLine::ForCurrentProcess(), base::FilePath(), false);
extension_service_ = extension_system->Get(profile())->extension_service();
- // Mock a signed-in user.
- SigninManagerBase* signin_manager =
- SigninManagerFactory::GetForProfile(profile());
- signin_manager->SetAuthenticatedUsername(kTestingUsername);
-
- // Encryptor ends up needing access to the keychain on OS X. So use the mock
- // keychain to prevent prompts.
-#if defined(OS_MACOSX)
- Encryptor::UseMockKeychain(true);
-#endif
-
- // Mock a GCMClient.
- GCMClientFactory::SetTestingFactory(&GCMProfileServiceTest::BuildGCMClient);
-
- // Mock a GCMEventRouter.
- gcm_event_router_mock_.reset(new GCMEventRouterMock(this));
-
- // This will create GCMProfileService that causes check-in to be initiated.
+ // Allow a testing delegate to be passed to GCMProfileService instance.
GCMProfileService::enable_gcm_for_testing_ = true;
CreateGCMProfileServiceInstance();
- // Wait till the asynchronous check-in is done.
- WaitForCompleted();
- }
-
- virtual void TearDown() OVERRIDE {
-#if defined(OS_CHROMEOS)
- test_user_manager_.reset();
-#endif
-
- extension_service_ = NULL;
- profile_.reset();
- base::RunLoop().RunUntilIdle();
- }
-
- // Overridden from GCMProfileService::TestingDelegate:
- virtual GCMEventRouter* GetEventRouter() const OVERRIDE {
- return gcm_event_router_mock_.get();
- }
-
- void CreateGCMProfileServiceInstance() {
- GCMProfileService* gcm_profile_service = static_cast<GCMProfileService*>(
- GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
- profile(), &GCMProfileServiceTest::BuildGCMProfileService));
- gcm_profile_service->set_testing_delegate(this);
- gcm_profile_service->Initialize();
- }
-
- virtual void CheckInFinished(const GCMClient::CheckinInfo& checkin_info,
- GCMClient::Result result) OVERRIDE {
- checkin_info_ = checkin_info;
- SignalCompleted();
- }
-
- // Waits until the asynchrnous operation finishes.
- void WaitForCompleted() {
- run_loop_.reset(new base::RunLoop);
- run_loop_->Run();
+ // Mock a GCMEventRouter.
+ gcm_event_router_.reset(new FakeGCMEventRouter(waiter_));
}
- // Signals that the asynchrnous operation finishes.
- void SignalCompleted() {
- if (run_loop_ && run_loop_->running())
- run_loop_->Quit();
+ virtual ~GCMProfileServiceTestConsumer() {
}
// Returns a barebones test extension.
@@ -220,27 +284,227 @@ class GCMProfileServiceTest : public testing::Test,
return extension;
}
- Profile* profile() const { return profile_.get(); }
+ 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));
+ gcm_profile_service->set_testing_delegate(this);
+ gcm_profile_service->Initialize();
+ }
+
+ void CheckIn(const std::string& username) {
+ signin_manager_->SignIn(username);
+
+ // This will cause GCMProfileService to be created if not yet. This will
+ // also kick off the check-in if not yet.
+ GetGCMProfileService();
+
+ // Wait till the asynchronous check-in is done.
+ waiter_->WaitUntilCompleted();
+ }
+
+ void Register(const std::string& app_id,
+ const std::vector<std::string>& sender_ids) {
+ GetGCMProfileService()->Register(
+ app_id,
+ sender_ids,
+ kTestingSha1Cert,
+ base::Bind(&GCMProfileServiceTestConsumer::RegisterCompleted,
+ base::Unretained(this)));
+ }
+
+ void RegisterCompleted(const std::string& registration_id,
+ GCMClient::Result result) {
+ registration_id_ = registration_id;
+ registration_result_ = result;
+ waiter_->SignalCompleted();
+ }
+
+ bool HasPersistedRegistrationInfo(const std::string& app_id) {
+ StateStore* storage = ExtensionSystem::Get(profile())->state_store();
+ if (!storage)
+ return false;
+ has_persisted_registration_info_ = false;
+ storage->GetExtensionValue(
+ app_id,
+ GCMProfileService::GetPersistentRegisterKeyForTesting(),
+ base::Bind(
+ &GCMProfileServiceTestConsumer::ReadRegistrationInfoFinished,
+ base::Unretained(this)));
+ waiter_->WaitUntilCompleted();
+ return has_persisted_registration_info_;
+ }
+
+ void ReadRegistrationInfoFinished(scoped_ptr<base::Value> value) {
+ has_persisted_registration_info_ = value.get() != NULL;
+ waiter_->SignalCompleted();
+ }
+
+ void Send(const std::string& app_id,
+ const std::string& receiver_id,
+ const GCMClient::OutgoingMessage& message) {
+ GetGCMProfileService()->Send(
+ app_id,
+ receiver_id,
+ message,
+ base::Bind(&GCMProfileServiceTestConsumer::SendCompleted,
+ base::Unretained(this)));
+ }
+
+ void SendCompleted(const std::string& message_id, GCMClient::Result result) {
+ send_message_id_ = message_id;
+ send_result_ = result;
+ waiter_->SignalCompleted();
+ }
GCMProfileService* GetGCMProfileService() const {
return GCMProfileServiceFactory::GetForProfile(profile());
}
- protected:
+ const std::string& GetUsername() const {
+ return GetGCMProfileService()->username_;
+ }
+
+ bool ExistsCachedRegistrationInfo() const {
+ return !GetGCMProfileService()->registration_info_map_.empty();
+ }
+
+ Profile* profile() const { return profile_.get(); }
+ FakeSigninManager* signin_manager() const { return signin_manager_; }
+ FakeGCMEventRouter* gcm_event_router() const {
+ return gcm_event_router_.get();
+ }
+
+ GCMClient::CheckinInfo checkin_info() const { return checkin_info_; }
+ const std::string& registration_id() const { return registration_id_; }
+ GCMClient::Result registration_result() const { return registration_result_; }
+ const std::string& send_message_id() const { return send_message_id_; }
+ GCMClient::Result send_result() const { return send_result_; }
+
+ void clear_checkin_info() { checkin_info_.Reset(); }
+ void clear_registration_result() {
+ registration_id_.clear();
+ registration_result_ = GCMClient::UNKNOWN_ERROR;
+ }
+ void clear_send_result() {
+ send_message_id_.clear();
+ send_result_ = GCMClient::UNKNOWN_ERROR;;
+ }
+
+ private:
+ // Overridden from GCMProfileService::TestingDelegate:
+ virtual GCMEventRouter* GetEventRouter() const OVERRIDE {
+ return gcm_event_router_.get();
+ }
+
+ virtual void CheckInFinished(const GCMClient::CheckinInfo& checkin_info,
+ GCMClient::Result result) OVERRIDE {
+ checkin_info_ = checkin_info;
+ waiter_->SignalCompleted();
+ }
+
+ Waiter* waiter_; // Not owned.
scoped_ptr<TestingProfile> profile_;
- scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
ExtensionService* extension_service_; // Not owned.
- scoped_ptr<base::RunLoop> run_loop_;
- scoped_ptr<GCMEventRouterMock> gcm_event_router_mock_;
+ FakeSigninManager* signin_manager_; // Not owned.
+ scoped_ptr<FakeGCMEventRouter> gcm_event_router_;
+
GCMClient::CheckinInfo checkin_info_;
+ std::string registration_id_;
+ GCMClient::Result registration_result_;
+ bool has_persisted_registration_info_;
+
+ std::string send_message_id_;
+ GCMClient::Result send_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceTestConsumer);
+};
+
+class GCMProfileServiceTest : public testing::Test {
+ public:
+ static GCMClient* BuildGCMClient() {
+ ANNOTATE_SCOPED_MEMORY_LEAK;
+ return new GCMClientMock();
+ }
+
+ GCMProfileServiceTest() {
+ }
+
+ virtual ~GCMProfileServiceTest() {
+ }
+
+ // 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
+
+ // Encryptor ends up needing access to the keychain on OS X. So use the mock
+ // keychain to prevent prompts.
+#if defined(OS_MACOSX)
+ Encryptor::UseMockKeychain(true);
+#endif
+
+ // Mock a GCMClient.
+ GCMClientFactory::SetTestingFactory(&GCMProfileServiceTest::BuildGCMClient);
+
+ // 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();
+ }
+
+ void WaitUntilCompleted() {
+ waiter_.WaitUntilCompleted();
+ }
+
+ void SignalCompleted() {
+ waiter_.SignalCompleted();
+ }
+
+ void PumpIOLoop() {
+ waiter_.PumpIOLoop();
+ }
+
+ Profile* profile() const { return consumer_->profile(); }
+ GCMProfileServiceTestConsumer* consumer() const { return consumer_.get(); }
+
+ protected:
+ Waiter waiter_;
+
+ 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
- private:
+ scoped_ptr<GCMProfileServiceTestConsumer> consumer_;
+
DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceTest);
};
@@ -262,39 +526,6 @@ class ScopedGCMClientMockSimulateServerError {
DISALLOW_COPY_AND_ASSIGN(ScopedGCMClientMockSimulateServerError);
};
-GCMEventRouterMock::GCMEventRouterMock(GCMProfileServiceTest* test)
- : test_(test),
- received_event_(NO_EVENT),
- send_error_result_(GCMClient::SUCCESS) {
-}
-
-GCMEventRouterMock::~GCMEventRouterMock() {
-}
-
-void GCMEventRouterMock::OnMessage(const std::string& app_id,
- const GCMClient::IncomingMessage& message) {
- received_event_ = MESSAGE_EVENT;
- app_id_ = app_id;
- incoming_message_ = message;
- test_->SignalCompleted();
-}
-
-void GCMEventRouterMock::OnMessagesDeleted(const std::string& app_id) {
- received_event_ = MESSAGES_DELETED_EVENT;
- app_id_ = app_id;
- test_->SignalCompleted();
-}
-
-void GCMEventRouterMock::OnSendError(const std::string& app_id,
- const std::string& message_id,
- GCMClient::Result result) {
- received_event_ = SEND_ERROR_EVENT;
- app_id_ = app_id;
- send_error_message_id_ = message_id;
- send_error_result_ = result;
- test_->SignalCompleted();
-}
-
TEST_F(GCMProfileServiceTest, Incognito) {
EXPECT_TRUE(GCMProfileServiceFactory::GetForProfile(profile()));
@@ -309,20 +540,92 @@ TEST_F(GCMProfileServiceTest, Incognito) {
incognito_profile.get()));
}
-TEST_F(GCMProfileServiceTest, CheckIn) {
- EXPECT_TRUE(checkin_info_.IsValid());
+TEST_F(GCMProfileServiceTest, CreateGCMProfileServiceBeforeProfileSignIn) {
+ // This will cause GCMProfileService to be created. No check-in should be
+ // initiated at this moment since the profile has not been signed in yet.
+ consumer()->GetGCMProfileService();
+ EXPECT_TRUE(consumer()->GetUsername().empty());
+ EXPECT_FALSE(consumer()->checkin_info().IsValid());
+
+ // Sign in to a profile. This will kick off the check-in.
+ consumer()->signin_manager()->SignIn(kTestingUsername);
+
+ // Wait till the asynchronous check-in is done.
+ WaitUntilCompleted();
+
+ // Verify the check-in result.
+ EXPECT_TRUE(consumer()->checkin_info().IsValid());
GCMClient::CheckinInfo expected_checkin_info =
GCMClientMock::GetCheckinInfoFromUsername(kTestingUsername);
- EXPECT_EQ(expected_checkin_info.android_id, checkin_info_.android_id);
- EXPECT_EQ(expected_checkin_info.secret, checkin_info_.secret);
+ EXPECT_EQ(expected_checkin_info.android_id,
+ consumer()->checkin_info().android_id);
+ EXPECT_EQ(expected_checkin_info.secret, consumer()->checkin_info().secret);
}
-TEST_F(GCMProfileServiceTest, CheckInFromPrefsStore) {
+TEST_F(GCMProfileServiceTest, CreateGCMProfileServiceAfterProfileSignIn) {
+ // Sign in to a profile. This will not initiate the check-in.
+ consumer()->signin_manager()->SignIn(kTestingUsername);
+
+ // This will cause GCMProfileService to be created and the check-in to be
+ // invoked.
+ consumer()->GetGCMProfileService();
+ EXPECT_FALSE(consumer()->GetUsername().empty());
+ EXPECT_FALSE(consumer()->checkin_info().IsValid());
+
+ // Wait till the asynchronous check-in is done.
+ WaitUntilCompleted();
+
+ // Verify the check-in result.
+ EXPECT_TRUE(consumer()->checkin_info().IsValid());
+
+ GCMClient::CheckinInfo expected_checkin_info =
+ GCMClientMock::GetCheckinInfoFromUsername(kTestingUsername);
+ EXPECT_EQ(expected_checkin_info.android_id,
+ consumer()->checkin_info().android_id);
+ EXPECT_EQ(expected_checkin_info.secret, consumer()->checkin_info().secret);
+}
+
+TEST_F(GCMProfileServiceTest, RegsiterWhenNotSignedIn) {
+ std::vector<std::string> sender_ids;
+ sender_ids.push_back("sender1");
+ consumer()->Register(kTestingAppId, sender_ids);
+
+ EXPECT_TRUE(consumer()->registration_id().empty());
+ EXPECT_EQ(GCMClient::NOT_SIGNED_IN, consumer()->registration_result());
+}
+
+TEST_F(GCMProfileServiceTest, SendWhenNotSignedIn) {
+ GCMClient::OutgoingMessage message;
+ message.id = "1";
+ message.data["key1"] = "value1";
+ consumer()->Send(kTestingAppId, kUserId, message);
+
+ EXPECT_TRUE(consumer()->send_message_id().empty());
+ EXPECT_EQ(GCMClient::NOT_SIGNED_IN, consumer()->send_result());
+}
+
+// Tests single-profile. CheckIn is initiated by default.
+class GCMProfileServiceSingleProfileTest : public GCMProfileServiceTest {
+ public:
+ GCMProfileServiceSingleProfileTest() {
+ }
+
+ virtual ~GCMProfileServiceSingleProfileTest() {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ GCMProfileServiceTest::SetUp();
+
+ consumer()->CheckIn(kTestingUsername);
+ }
+};
+
+TEST_F(GCMProfileServiceSingleProfileTest, CheckInFromPrefsStore) {
// The first check-in should be successful.
- EXPECT_TRUE(checkin_info_.IsValid());
- GCMClient::CheckinInfo saved_checkin_info = checkin_info_;
- checkin_info_.Reset();
+ EXPECT_TRUE(consumer()->checkin_info().IsValid());
+ GCMClient::CheckinInfo saved_checkin_info = consumer()->checkin_info();
+ consumer()->clear_checkin_info();
// Check-in should not reach the server. Forcing GCMClient server error should
// help catch this.
@@ -330,138 +633,99 @@ TEST_F(GCMProfileServiceTest, CheckInFromPrefsStore) {
// Recreate GCMProfileService to test reading the check-in info from the
// prefs store.
- CreateGCMProfileServiceInstance();
+ consumer()->CreateGCMProfileServiceInstance();
- EXPECT_EQ(saved_checkin_info.android_id, checkin_info_.android_id);
- EXPECT_EQ(saved_checkin_info.secret, checkin_info_.secret);
+ EXPECT_EQ(saved_checkin_info.android_id,
+ consumer()->checkin_info().android_id);
+ EXPECT_EQ(saved_checkin_info.secret, consumer()->checkin_info().secret);
}
-TEST_F(GCMProfileServiceTest, CheckOut) {
+TEST_F(GCMProfileServiceSingleProfileTest, CheckOut) {
EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(prefs::kGCMUserAccountID));
EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(prefs::kGCMUserToken));
- GetGCMProfileService()->RemoveUser();
+ // This will trigger check-out.
+ consumer()->signin_manager()->SignOut();
EXPECT_FALSE(profile()->GetPrefs()->HasPrefPath(prefs::kGCMUserAccountID));
EXPECT_FALSE(profile()->GetPrefs()->HasPrefPath(prefs::kGCMUserToken));
}
-class GCMProfileServiceRegisterTest : public GCMProfileServiceTest {
- public:
- GCMProfileServiceRegisterTest()
- : result_(GCMClient::SUCCESS),
- has_persisted_registration_info_(false) {
- }
-
- virtual ~GCMProfileServiceRegisterTest() {
- }
-
- void Register(const std::string& app_id,
- const std::vector<std::string>& sender_ids) {
- GetGCMProfileService()->Register(
- app_id,
- sender_ids,
- kTestingSha1Cert,
- base::Bind(&GCMProfileServiceRegisterTest::RegisterCompleted,
- base::Unretained(this)));
- }
-
- void RegisterCompleted(const std::string& registration_id,
- GCMClient::Result result) {
- registration_id_ = registration_id;
- result_ = result;
- SignalCompleted();
- }
-
- bool HasPersistedRegistrationInfo(const std::string& app_id) {
- StateStore* storage = ExtensionSystem::Get(profile())->state_store();
- if (!storage)
- return false;
- has_persisted_registration_info_ = false;
- storage->GetExtensionValue(
- app_id,
- GCMProfileService::GetPersistentRegisterKeyForTesting(),
- base::Bind(
- &GCMProfileServiceRegisterTest::ReadRegistrationInfoFinished,
- base::Unretained(this)));
- WaitForCompleted();
- return has_persisted_registration_info_;
- }
+TEST_F(GCMProfileServiceSingleProfileTest, CheckOutAndThenCheckIn) {
+ // The first check-in should be successful.
+ EXPECT_TRUE(consumer()->checkin_info().IsValid());
- void ReadRegistrationInfoFinished(scoped_ptr<base::Value> value) {
- has_persisted_registration_info_ = value.get() != NULL;
- SignalCompleted();
- }
+ // This will trigger check-out.
+ consumer()->signin_manager()->SignOut();
- protected:
- std::string registration_id_;
- GCMClient::Result result_;
- bool has_persisted_registration_info_;
+ // Sign-in with a different username.
+ consumer()->CheckIn(kTestingUsername2);
- private:
- DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceRegisterTest);
-};
+ GCMClient::CheckinInfo expected_checkin_info =
+ GCMClientMock::GetCheckinInfoFromUsername(kTestingUsername2);
+ EXPECT_EQ(expected_checkin_info.android_id,
+ consumer()->checkin_info().android_id);
+ EXPECT_EQ(expected_checkin_info.secret, consumer()->checkin_info().secret);
+}
-TEST_F(GCMProfileServiceRegisterTest, Register) {
+TEST_F(GCMProfileServiceSingleProfileTest, Register) {
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
- Register(kTestingAppId, sender_ids);
+ consumer()->Register(kTestingAppId, sender_ids);
std::string expected_registration_id =
GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids);
- WaitForCompleted();
- EXPECT_FALSE(registration_id_.empty());
- EXPECT_EQ(expected_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ WaitUntilCompleted();
+ EXPECT_EQ(expected_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest, DoubleRegister) {
+TEST_F(GCMProfileServiceSingleProfileTest, DoubleRegister) {
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
- Register(kTestingAppId, sender_ids);
+ consumer()->Register(kTestingAppId, sender_ids);
std::string expected_registration_id =
GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids);
// Calling regsiter 2nd time without waiting 1st one to finish will fail
// immediately.
sender_ids.push_back("sender2");
- Register(kTestingAppId, sender_ids);
- EXPECT_TRUE(registration_id_.empty());
- EXPECT_NE(GCMClient::SUCCESS, result_);
+ consumer()->Register(kTestingAppId, sender_ids);
+ EXPECT_TRUE(consumer()->registration_id().empty());
+ EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING,
+ consumer()->registration_result());
// The 1st register is still doing fine.
- WaitForCompleted();
- EXPECT_FALSE(registration_id_.empty());
- EXPECT_EQ(expected_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ WaitUntilCompleted();
+ EXPECT_EQ(expected_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest, RegisterError) {
+TEST_F(GCMProfileServiceSingleProfileTest, RegisterError) {
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1@error");
- Register(kTestingAppId, sender_ids);
+ consumer()->Register(kTestingAppId, sender_ids);
- WaitForCompleted();
- EXPECT_TRUE(registration_id_.empty());
- EXPECT_NE(GCMClient::SUCCESS, result_);
+ WaitUntilCompleted();
+ EXPECT_TRUE(consumer()->registration_id().empty());
+ EXPECT_NE(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest, RegisterAgainWithSameSenderIDs) {
+TEST_F(GCMProfileServiceSingleProfileTest, RegisterAgainWithSameSenderIDs) {
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
sender_ids.push_back("sender2");
- Register(kTestingAppId, sender_ids);
+ consumer()->Register(kTestingAppId, sender_ids);
std::string expected_registration_id =
GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids);
- WaitForCompleted();
- EXPECT_EQ(expected_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ WaitUntilCompleted();
+ EXPECT_EQ(expected_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
// Clears the results the would be set by the Register callback in preparation
// to call register 2nd time.
- registration_id_.clear();
- result_ = GCMClient::UNKNOWN_ERROR;
+ consumer()->clear_registration_result();
// Calling register 2nd time with the same set of sender IDs but different
// ordering will get back the same registration ID. There is no need to wait
@@ -469,21 +733,22 @@ TEST_F(GCMProfileServiceRegisterTest, RegisterAgainWithSameSenderIDs) {
std::vector<std::string> another_sender_ids;
another_sender_ids.push_back("sender2");
another_sender_ids.push_back("sender1");
- Register(kTestingAppId, another_sender_ids);
- EXPECT_EQ(expected_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ consumer()->Register(kTestingAppId, another_sender_ids);
+ EXPECT_EQ(expected_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest, RegisterAgainWithDifferentSenderIDs) {
+TEST_F(GCMProfileServiceSingleProfileTest,
+ RegisterAgainWithDifferentSenderIDs) {
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
- Register(kTestingAppId, sender_ids);
+ consumer()->Register(kTestingAppId, sender_ids);
std::string expected_registration_id =
GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids);
- WaitForCompleted();
- EXPECT_EQ(expected_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ WaitUntilCompleted();
+ EXPECT_EQ(expected_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
// Make sender IDs different.
sender_ids.push_back("sender2");
@@ -492,36 +757,33 @@ TEST_F(GCMProfileServiceRegisterTest, RegisterAgainWithDifferentSenderIDs) {
// Calling register 2nd time with the different sender IDs will get back a new
// registration ID.
- Register(kTestingAppId, sender_ids);
- WaitForCompleted();
- EXPECT_EQ(expected_registration_id2, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ consumer()->Register(kTestingAppId, sender_ids);
+ WaitUntilCompleted();
+ EXPECT_EQ(expected_registration_id2, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest, ReadRegistrationFromStateStore) {
- scoped_refptr<Extension> extension(CreateExtension());
+TEST_F(GCMProfileServiceSingleProfileTest, ReadRegistrationFromStateStore) {
+ scoped_refptr<Extension> extension(consumer()->CreateExtension());
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
- Register(extension->id(), sender_ids);
+ consumer()->Register(extension->id(), sender_ids);
- WaitForCompleted();
- EXPECT_FALSE(registration_id_.empty());
- EXPECT_EQ(GCMClient::SUCCESS, result_);
- std::string old_registration_id = registration_id_;
+ 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.
- registration_id_.clear();
- result_ = GCMClient::UNKNOWN_ERROR;
+ consumer()->clear_registration_result();
// Simulate start-up by recreating GCMProfileService.
- CreateGCMProfileServiceInstance();
+ consumer()->CreateGCMProfileServiceInstance();
// Simulate start-up by reloading extension.
- extension_service_->UnloadExtension(extension->id(),
- UnloadedExtensionInfo::REASON_TERMINATE);
- extension_service_->AddExtension(extension.get());
+ consumer()->ReloadExtension(extension);
// Register should not reach the server. Forcing GCMClient server error should
// help catch this.
@@ -530,175 +792,564 @@ TEST_F(GCMProfileServiceRegisterTest, ReadRegistrationFromStateStore) {
// This should read the registration info from the extension's state store.
// We still need to wait since the reading from state store might happen at
// the same time.
- Register(extension->id(), sender_ids);
- WaitForCompleted();
- EXPECT_EQ(old_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ consumer()->Register(extension->id(), sender_ids);
+ WaitUntilCompleted();
+ EXPECT_EQ(old_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest,
+TEST_F(GCMProfileServiceSingleProfileTest,
GCMClientLoadingCompletedAfterReadingRegistration) {
- scoped_refptr<Extension> extension(CreateExtension());
+ scoped_refptr<Extension> extension(consumer()->CreateExtension());
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
- Register(extension->id(), sender_ids);
+ consumer()->Register(extension->id(), sender_ids);
- WaitForCompleted();
- EXPECT_FALSE(registration_id_.empty());
- EXPECT_EQ(GCMClient::SUCCESS, result_);
- std::string old_registration_id = registration_id_;
+ 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.
- registration_id_.clear();
- result_ = GCMClient::UNKNOWN_ERROR;
+ consumer()->clear_registration_result();
// Mark that GCMClient is in loading state.
GetGCMClientMock()->SetIsLoading(true);
// Simulate start-up by recreating GCMProfileService.
- CreateGCMProfileServiceInstance();
+ consumer()->CreateGCMProfileServiceInstance();
// Simulate start-up by reloading extension.
- extension_service_->UnloadExtension(extension->id(),
- UnloadedExtensionInfo::REASON_TERMINATE);
- extension_service_->AddExtension(extension.get());
+ consumer()->ReloadExtension(extension);
// Read the registration info from the extension's state store.
// This would hold up because GCMClient is in loading state.
- Register(extension->id(), sender_ids);
+ consumer()->Register(extension->id(), sender_ids);
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(registration_id_.empty());
- EXPECT_EQ(GCMClient::UNKNOWN_ERROR, result_);
+ EXPECT_TRUE(consumer()->registration_id().empty());
+ EXPECT_EQ(GCMClient::UNKNOWN_ERROR, consumer()->registration_result());
// Register operation will be invoked after GCMClient finishes the loading.
GetGCMClientMock()->SetIsLoading(false);
- WaitForCompleted();
- EXPECT_EQ(old_registration_id, registration_id_);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ WaitUntilCompleted();
+ EXPECT_EQ(old_registration_id, consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
}
-TEST_F(GCMProfileServiceRegisterTest, Unregister) {
- scoped_refptr<Extension> extension(CreateExtension());
+TEST_F(GCMProfileServiceSingleProfileTest, RegisterAfterSignOut) {
+ // This will trigger check-out.
+ consumer()->signin_manager()->SignOut();
std::vector<std::string> sender_ids;
sender_ids.push_back("sender1");
- Register(extension->id(), sender_ids);
+ consumer()->Register(kTestingAppId, sender_ids);
+
+ EXPECT_TRUE(consumer()->registration_id().empty());
+ EXPECT_EQ(GCMClient::NOT_SIGNED_IN, consumer()->registration_result());
+}
- WaitForCompleted();
- EXPECT_FALSE(registration_id_.empty());
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+TEST_F(GCMProfileServiceSingleProfileTest, Unregister) {
+ 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());
// The registration info should be cached.
- EXPECT_FALSE(GetGCMProfileService()->registration_info_map_.empty());
+ EXPECT_TRUE(consumer()->ExistsCachedRegistrationInfo());
// The registration info should be persisted.
- EXPECT_TRUE(HasPersistedRegistrationInfo(extension->id()));
+ EXPECT_TRUE(consumer()->HasPersistedRegistrationInfo(extension->id()));
// Uninstall the extension.
- extension_service_->UninstallExtension(extension->id(), false, NULL);
+ consumer()->UninstallExtension(extension);
base::MessageLoop::current()->RunUntilIdle();
// The cached registration info should be removed.
- EXPECT_TRUE(GetGCMProfileService()->registration_info_map_.empty());
+ EXPECT_FALSE(consumer()->ExistsCachedRegistrationInfo());
// The persisted registration info should be removed.
- EXPECT_FALSE(HasPersistedRegistrationInfo(extension->id()));
+ EXPECT_FALSE(consumer()->HasPersistedRegistrationInfo(extension->id()));
+}
+
+TEST_F(GCMProfileServiceSingleProfileTest, Send) {
+ GCMClient::OutgoingMessage message;
+ message.id = "1";
+ message.data["key1"] = "value1";
+ message.data["key2"] = "value2";
+ consumer()->Send(kTestingAppId, kUserId, message);
+
+ // Wait for the send callback is called.
+ WaitUntilCompleted();
+ 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()->signin_manager()->SignOut();
+
+ GCMClient::OutgoingMessage message;
+ message.id = "1";
+ message.data["key1"] = "value1";
+ message.data["key2"] = "value2";
+ consumer()->Send(kTestingAppId, kUserId, message);
+
+ EXPECT_TRUE(consumer()->send_message_id().empty());
+ EXPECT_EQ(GCMClient::NOT_SIGNED_IN, consumer()->send_result());
+}
+
+TEST_F(GCMProfileServiceSingleProfileTest, SendError) {
+ GCMClient::OutgoingMessage message;
+ // Embedding error in id will tell the mock to simulate the send error.
+ message.id = "1@error";
+ message.data["key1"] = "value1";
+ message.data["key2"] = "value2";
+ consumer()->Send(kTestingAppId, kUserId, message);
+
+ // Wait for the send callback is called.
+ WaitUntilCompleted();
+ EXPECT_EQ(consumer()->send_message_id(), message.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->send_result());
+
+ // Wait for the send error.
+ WaitUntilCompleted();
+ EXPECT_EQ(FakeGCMEventRouter::SEND_ERROR_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer()->gcm_event_router()->app_id());
+ EXPECT_EQ(consumer()->send_message_id(),
+ consumer()->gcm_event_router()->send_message_id());
+ EXPECT_NE(GCMClient::SUCCESS,
+ consumer()->gcm_event_router()->send_result());
+}
+
+TEST_F(GCMProfileServiceSingleProfileTest, MessageReceived) {
+ GCMClient::IncomingMessage message;
+ message.data["key1"] = "value1";
+ message.data["key2"] = "value2";
+ GetGCMClientMock()->ReceiveMessage(kTestingUsername, kTestingAppId, message);
+ WaitUntilCompleted();
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer()->gcm_event_router()->app_id());
+ EXPECT_TRUE(message.data == consumer()->gcm_event_router()->message().data);
+}
+
+TEST_F(GCMProfileServiceSingleProfileTest, MessageReceivedAfterSignOut) {
+ // This will trigger check-out.
+ consumer()->signin_manager()->SignOut();
+
+ GCMClient::IncomingMessage message;
+ message.data["key1"] = "value1";
+ message.data["key2"] = "value2";
+ GetGCMClientMock()->ReceiveMessage(kTestingUsername, kTestingAppId, message);
+ PumpIOLoop();
+
+ EXPECT_EQ(FakeGCMEventRouter::NO_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_TRUE(consumer()->gcm_event_router()->app_id().empty());
}
-class GCMProfileServiceSendTest : public GCMProfileServiceTest {
+TEST_F(GCMProfileServiceSingleProfileTest, MessagesDeleted) {
+ GetGCMClientMock()->DeleteMessages(kTestingUsername, kTestingAppId);
+ WaitUntilCompleted();
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGES_DELETED_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer()->gcm_event_router()->app_id());
+}
+
+TEST_F(GCMProfileServiceSingleProfileTest, MessagesDeletedAfterSignOut) {
+ // This will trigger check-out.
+ consumer()->signin_manager()->SignOut();
+
+ GetGCMClientMock()->DeleteMessages(kTestingUsername, kTestingAppId);
+ PumpIOLoop();
+
+ EXPECT_EQ(FakeGCMEventRouter::NO_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_TRUE(consumer()->gcm_event_router()->app_id().empty());
+}
+
+class GCMProfileServiceMultiProfileTest : public GCMProfileServiceTest {
public:
- GCMProfileServiceSendTest() : result_(GCMClient::SUCCESS) {
+ GCMProfileServiceMultiProfileTest() {
}
- virtual ~GCMProfileServiceSendTest() {
+ virtual ~GCMProfileServiceMultiProfileTest() {
}
- void Send(const std::string& receiver_id,
- const GCMClient::OutgoingMessage& message) {
- GetGCMProfileService()->Send(
- kTestingAppId,
- receiver_id,
- message,
- base::Bind(&GCMProfileServiceSendTest::SendCompleted,
- base::Unretained(this)));
+ virtual void SetUp() OVERRIDE {
+ GCMProfileServiceTest::SetUp();
+
+ // Create a 2nd profile consumer.
+ consumer2_.reset(new GCMProfileServiceTestConsumer(&waiter_));
+
+ // This will cause GetGCMProfileService to be created for each profile.
+ consumer()->GetGCMProfileService();
+ consumer2()->GetGCMProfileService();
+
+ // Initiate check-in for each profile.
+ consumer2()->signin_manager()->SignIn(kTestingUsername2);
+ consumer()->signin_manager()->SignIn(kTestingUsername);
+
+ // Wait till all the asynchronous check-ins are done.
+ WaitUntilCompleted();
+ WaitUntilCompleted();
}
- void SendCompleted(const std::string& message_id, GCMClient::Result result) {
- message_id_ = message_id;
- result_ = result;
- SignalCompleted();
+ virtual void TearDown() OVERRIDE {
+ consumer2_.reset();
+
+ GCMProfileServiceTest::TearDown();
}
- protected:
- std::string message_id_;
- GCMClient::Result result_;
+ Profile* profile2() const { return consumer2_->profile(); }
+ GCMProfileServiceTestConsumer* consumer2() const { return consumer2_.get(); }
- private:
- DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceSendTest);
+ protected:
+ scoped_ptr<GCMProfileServiceTestConsumer> consumer2_;
};
-TEST_F(GCMProfileServiceSendTest, Send) {
- GCMClient::OutgoingMessage message;
- message.id = "1";
- message.data["key1"] = "value1";
- message.data["key2"] = "value2";
- Send(kUserId, message);
+TEST_F(GCMProfileServiceMultiProfileTest, CheckIn) {
+ GCMClient::CheckinInfo expected_checkin_info =
+ GCMClientMock::GetCheckinInfoFromUsername(kTestingUsername);
+ EXPECT_EQ(expected_checkin_info.android_id,
+ consumer()->checkin_info().android_id);
+ EXPECT_EQ(expected_checkin_info.secret, consumer()->checkin_info().secret);
+
+ expected_checkin_info =
+ GCMClientMock::GetCheckinInfoFromUsername(kTestingUsername2);
+ EXPECT_EQ(expected_checkin_info.android_id,
+ consumer2()->checkin_info().android_id);
+ EXPECT_EQ(expected_checkin_info.secret, consumer2()->checkin_info().secret);
+}
- // Wait for the send callback is called.
- WaitForCompleted();
- EXPECT_EQ(message_id_, message.id);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+TEST_F(GCMProfileServiceMultiProfileTest, Register) {
+ // Register an app.
+ std::vector<std::string> sender_ids;
+ sender_ids.push_back("sender1");
+ consumer()->Register(kTestingAppId, sender_ids);
+
+ // Register the same app in a different profile.
+ std::vector<std::string> sender_ids2;
+ sender_ids2.push_back("foo");
+ sender_ids2.push_back("bar");
+ consumer2()->Register(kTestingAppId, sender_ids2);
+
+ WaitUntilCompleted();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids),
+ consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
+
+ EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids2),
+ consumer2()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
+
+ // Register a different app in a different profile.
+ std::vector<std::string> sender_ids3;
+ sender_ids3.push_back("sender1");
+ sender_ids3.push_back("sender2");
+ sender_ids3.push_back("sender3");
+ consumer2()->Register(kTestingAppId2, sender_ids3);
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids3),
+ consumer2()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer2()->registration_result());
}
-TEST_F(GCMProfileServiceSendTest, SendError) {
+TEST_F(GCMProfileServiceMultiProfileTest, Send) {
+ // Send a message from one app in one profile.
GCMClient::OutgoingMessage message;
- // Embedding error in id will tell the mock to simulate the send error.
- message.id = "1@error";
+ message.id = "1";
message.data["key1"] = "value1";
message.data["key2"] = "value2";
- Send(kUserId, message);
+ consumer()->Send(kTestingAppId, kUserId, message);
- // Wait for the send callback is called.
- WaitForCompleted();
- EXPECT_EQ(message_id_, message.id);
- EXPECT_EQ(GCMClient::SUCCESS, result_);
+ // Send a message from same app in another profile.
+ GCMClient::OutgoingMessage message2;
+ message2.id = "2";
+ message2.data["foo"] = "bar";
+ consumer2()->Send(kTestingAppId, kUserId2, message2);
- // Wait for the send error.
- WaitForCompleted();
- EXPECT_EQ(GCMEventRouterMock::SEND_ERROR_EVENT,
- gcm_event_router_mock_->received_event());
- EXPECT_EQ(kTestingAppId, gcm_event_router_mock_->app_id());
- EXPECT_EQ(message_id_, gcm_event_router_mock_->send_message_id());
- EXPECT_NE(GCMClient::SUCCESS, gcm_event_router_mock_->send_result());
+ WaitUntilCompleted();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(consumer()->send_message_id(), message.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->send_result());
+
+ EXPECT_EQ(consumer2()->send_message_id(), message2.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer2()->send_result());
+
+ // Send another message from different app in another profile.
+ GCMClient::OutgoingMessage message3;
+ message3.id = "3";
+ message3.data["hello"] = "world";
+ consumer2()->Send(kTestingAppId2, kUserId, message3);
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(consumer2()->send_message_id(), message3.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->send_result());
}
-TEST_F(GCMProfileServiceTest, MessageReceived) {
+TEST_F(GCMProfileServiceMultiProfileTest, MessageReceived) {
+ // Trigger an incoming message for an app in one profile.
GCMClient::IncomingMessage message;
message.data["key1"] = "value1";
message.data["key2"] = "value2";
GetGCMClientMock()->ReceiveMessage(kTestingUsername, kTestingAppId, message);
- WaitForCompleted();
- EXPECT_EQ(GCMEventRouterMock::MESSAGE_EVENT,
- gcm_event_router_mock_->received_event());
- EXPECT_EQ(kTestingAppId, gcm_event_router_mock_->app_id());
- ASSERT_EQ(message.data.size(),
- gcm_event_router_mock_->incoming_message().data.size());
- EXPECT_EQ(
- message.data.find("key1")->second,
- gcm_event_router_mock_->incoming_message().data.find("key1")->second);
- EXPECT_EQ(
- message.data.find("key2")->second,
- gcm_event_router_mock_->incoming_message().data.find("key2")->second);
+
+ // Trigger an incoming message for the same app in another profile.
+ GCMClient::IncomingMessage message2;
+ message2.data["foo"] = "bar";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername2, kTestingAppId, message2);
+
+ WaitUntilCompleted();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer()->gcm_event_router()->app_id());
+ EXPECT_TRUE(message.data == consumer()->gcm_event_router()->message().data);
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer2()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer2()->gcm_event_router()->app_id());
+ EXPECT_TRUE(message2.data == consumer2()->gcm_event_router()->message().data);
+
+ // Trigger another incoming message for a different app in another profile.
+ GCMClient::IncomingMessage message3;
+ message3.data["bar1"] = "foo1";
+ message3.data["bar2"] = "foo2";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername2, kTestingAppId2, message3);
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer2()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId2, consumer2()->gcm_event_router()->app_id());
+ EXPECT_TRUE(message3.data == consumer2()->gcm_event_router()->message().data);
}
-TEST_F(GCMProfileServiceTest, MessagesDeleted) {
+// Test a set of GCM operations on multiple profiles.
+// 1) Register 1 app in profile1 and register 2 apps in profile2;
+// 2) Send a message from profile1;
+// 3) Receive a message to an app in profile1 and receive a message for each of
+// two apps in profile2;
+// 4) Send a message foe ach of two apps in profile2;
+// 5) Sign out of profile1.
+// 6) The app in profile1 should not receive message and deleted_messages
+// events;
+// 7) The app in profile2 could still receive these events;
+// 8) Sign into profile1 with a different user.
+// 9) The message to the signed-out user will be ingored.
+// 10) The message to the new signed-in user will be routed.
+TEST_F(GCMProfileServiceMultiProfileTest, Combined) {
+ // Register an app.
+ std::vector<std::string> sender_ids;
+ sender_ids.push_back("sender1");
+ consumer()->Register(kTestingAppId, sender_ids);
+
+ // Register the same app in a different profile.
+ std::vector<std::string> sender_ids2;
+ sender_ids2.push_back("foo");
+ sender_ids2.push_back("bar");
+ consumer2()->Register(kTestingAppId, sender_ids2);
+
+ // Register a different app in a different profile.
+ std::vector<std::string> sender_ids3;
+ sender_ids3.push_back("sender1");
+ sender_ids3.push_back("sender2");
+ sender_ids3.push_back("sender3");
+ consumer2()->Register(kTestingAppId2, sender_ids3);
+
+ WaitUntilCompleted();
+ WaitUntilCompleted();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids),
+ consumer()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
+
+ EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids3),
+ consumer2()->registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->registration_result());
+
+ // Send a message from one profile.
+ GCMClient::OutgoingMessage out_message;
+ out_message.id = "1";
+ out_message.data["out1"] = "out_data1";
+ out_message.data["out1_2"] = "out_data1_2";
+ consumer()->Send(kTestingAppId, kUserId, out_message);
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(consumer()->send_message_id(), out_message.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer()->send_result());
+
+ // Trigger an incoming message for an app in one profile.
+ GCMClient::IncomingMessage in_message;
+ in_message.data["in1"] = "in_data1";
+ in_message.data["in1_2"] = "in_data1_2";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername, kTestingAppId, in_message);
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer()->gcm_event_router()->app_id());
+ EXPECT_TRUE(
+ in_message.data == consumer()->gcm_event_router()->message().data);
+
+ // Trigger 2 incoming messages, one for each app respectively, in another
+ // profile.
+ GCMClient::IncomingMessage in_message2;
+ in_message2.data["in2"] = "in_data2";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername2, kTestingAppId2, in_message2);
+
+ GCMClient::IncomingMessage in_message3;
+ in_message3.data["in3"] = "in_data3";
+ in_message3.data["in3_2"] = "in_data3_2";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername2, kTestingAppId, in_message3);
+
+ consumer2()->gcm_event_router()->clear_results();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer2()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId2, consumer2()->gcm_event_router()->app_id());
+ EXPECT_TRUE(
+ in_message2.data == consumer2()->gcm_event_router()->message().data);
+
+ consumer2()->gcm_event_router()->clear_results();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer2()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer2()->gcm_event_router()->app_id());
+ EXPECT_TRUE(
+ in_message3.data == consumer2()->gcm_event_router()->message().data);
+
+ // Send two messages, one for each app respectively, from another profile.
+ GCMClient::OutgoingMessage out_message2;
+ out_message2.id = "2";
+ out_message2.data["out2"] = "out_data2";
+ consumer2()->Send(kTestingAppId, kUserId2, out_message2);
+
+ GCMClient::OutgoingMessage out_message3;
+ out_message3.id = "2";
+ out_message3.data["out3"] = "out_data3";
+ consumer2()->Send(kTestingAppId2, kUserId2, out_message3);
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(consumer2()->send_message_id(), out_message2.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer2()->send_result());
+
+ WaitUntilCompleted();
+
+ EXPECT_EQ(consumer2()->send_message_id(), out_message3.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer2()->send_result());
+
+ // Sign out of one profile.
+ consumer()->signin_manager()->SignOut();
+ PumpIOLoop();
+
+ // Incoming message will be ingored for the signed-out profile.
+ GCMClient::IncomingMessage in_message4;
+ in_message4.data["in4"] = "in_data4";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername, kTestingAppId, in_message4);
+
+ consumer()->gcm_event_router()->clear_results();
+ PumpIOLoop();
+
+ EXPECT_EQ(FakeGCMEventRouter::NO_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_TRUE(consumer()->gcm_event_router()->app_id().empty());
+
+ // Deleted messages event will be ingored for the signed-out profile.
GetGCMClientMock()->DeleteMessages(kTestingUsername, kTestingAppId);
- WaitForCompleted();
- EXPECT_EQ(GCMEventRouterMock::MESSAGES_DELETED_EVENT,
- gcm_event_router_mock_->received_event());
- EXPECT_EQ(kTestingAppId, gcm_event_router_mock_->app_id());
+
+ PumpIOLoop();
+
+ EXPECT_EQ(FakeGCMEventRouter::NO_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_TRUE(consumer()->gcm_event_router()->app_id().empty());
+
+ // Deleted messages event will go through for another signed-in profile.
+ GetGCMClientMock()->DeleteMessages(kTestingUsername2, kTestingAppId2);
+
+ consumer2()->gcm_event_router()->clear_results();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGES_DELETED_EVENT,
+ consumer2()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId2, consumer2()->gcm_event_router()->app_id());
+
+ // Send error event will go through for another signed-in profile.
+ GCMClient::OutgoingMessage out_message4;
+ out_message4.id = "1@error";
+ out_message4.data["out4"] = "out_data4";
+ consumer2()->Send(kTestingAppId, kUserId, out_message4);
+
+ WaitUntilCompleted();
+ EXPECT_EQ(consumer2()->send_message_id(), out_message4.id);
+ EXPECT_EQ(GCMClient::SUCCESS, consumer2()->send_result());
+
+ consumer2()->gcm_event_router()->clear_results();
+ WaitUntilCompleted();
+ EXPECT_EQ(FakeGCMEventRouter::SEND_ERROR_EVENT,
+ consumer2()->gcm_event_router()->received_event());
+ EXPECT_EQ(kTestingAppId, consumer2()->gcm_event_router()->app_id());
+ EXPECT_EQ(consumer2()->send_message_id(),
+ consumer2()->gcm_event_router()->send_message_id());
+ EXPECT_NE(GCMClient::SUCCESS,
+ consumer2()->gcm_event_router()->send_result());
+
+ // Sign in with a different user.
+ consumer()->signin_manager()->SignIn(kTestingUsername3);
+ WaitUntilCompleted();
+
+ // Incoming message will still be ingored for the signed-out user.
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername, kTestingAppId, in_message4);
+
+ consumer()->gcm_event_router()->clear_results();
+ PumpIOLoop();
+
+ EXPECT_EQ(FakeGCMEventRouter::NO_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_TRUE(consumer()->gcm_event_router()->app_id().empty());
+
+ // Incoming message will go through for the new signed-in user.
+ GCMClient::IncomingMessage in_message5;
+ in_message5.data["in5"] = "in_data5";
+ GetGCMClientMock()->ReceiveMessage(
+ kTestingUsername3, kTestingAppId, in_message5);
+
+ consumer()->gcm_event_router()->clear_results();
+ WaitUntilCompleted();
+
+ EXPECT_EQ(FakeGCMEventRouter::MESSAGE_EVENT,
+ consumer()->gcm_event_router()->received_event());
+ EXPECT_TRUE(
+ in_message5.data == consumer()->gcm_event_router()->message().data);
}
} // namespace gcm
diff --git a/google_apis/gcm/gcm_client.h b/google_apis/gcm/gcm_client.h
index 914bb83..0759a49 100644
--- a/google_apis/gcm/gcm_client.h
+++ b/google_apis/gcm/gcm_client.h
@@ -23,6 +23,8 @@ class GCM_EXPORT GCMClient {
SUCCESS,
// Invalid parameter.
INVALID_PARAMETER,
+ // Profile not signed in.
+ NOT_SIGNED_IN,
// Previous asynchronous operation is still pending to finish. Certain
// operation, like register, is only allowed one at a time.
ASYNC_OPERATION_PENDING,