Chromium Code Reviews| Index: chrome/browser/services/gcm/gcm_service_unittest.cc |
| diff --git a/chrome/browser/services/gcm/gcm_service_unittest.cc b/chrome/browser/services/gcm/gcm_service_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0ed77a5a45b4ff1185a337b6e55ad6c0ea7fea4f |
| --- /dev/null |
| +++ b/chrome/browser/services/gcm/gcm_service_unittest.cc |
| @@ -0,0 +1,1422 @@ |
| +// 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_service.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| +#include "base/files/scoped_temp_dir.h" |
| +#include "base/location.h" |
| +#include "base/run_loop.h" |
| +#include "base/strings/string_util.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 "content/public/browser/browser_thread.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "google_apis/gaia/oauth2_access_token_consumer.h" |
| +#include "google_apis/gaia/oauth2_access_token_fetcher.h" |
| +#include "google_apis/gaia/oauth2_token_service.h" |
| +#include "net/url_request/url_request_context_getter.h" |
| +#include "net/url_request/url_request_test_util.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace gcm { |
| + |
| +namespace { |
| + |
| +const char kTestAccountID1[] = "user1@example.com"; |
| +const char kTestAccountID2[] = "user2@example.com"; |
| +const char kTestAccountID3[] = "user3@example.com"; |
| +const char kTestAppID1[] = "TestApp1"; |
| +const char kTestAppID2[] = "TestApp2"; |
| +const char kUserID1[] = "user1"; |
| +const char kUserID2[] = "user2"; |
| + |
| +void PumpUILoop() { |
| + base::RunLoop().RunUntilIdle(); |
| +} |
| + |
| +void PumpIOLoop() { |
| + base::RunLoop run_loop; |
| + content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&base::DoNothing), |
| + run_loop.QuitClosure()); |
| + run_loop.Run(); |
| +} |
| + |
| +std::vector<std::string> ToSenderList(const std::string& sender_ids) { |
| + std::vector<std::string> senders; |
| + Tokenize(sender_ids, ",", &senders); |
| + return senders; |
| +} |
| + |
| +class FakeOAuth2TokenService : public OAuth2TokenService { |
|
jianli
2014/04/17 00:33:19
Should we move this and FakeIdentityProvider to
gc
bartfab (slow)
2014/04/17 14:20:01
Done. While at it, I took a closer look at gcm_pro
|
| + public: |
| + explicit FakeOAuth2TokenService( |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context); |
| + virtual ~FakeOAuth2TokenService(); |
| + |
| + // OAuth2TokenService: |
| + virtual bool RefreshTokenIsAvailable( |
| + const std::string& account_id) const OVERRIDE; |
| + |
| + protected: |
| + virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher( |
| + const std::string& account_id, |
| + net::URLRequestContextGetter* getter, |
| + OAuth2AccessTokenConsumer* consumer) OVERRIDE; |
| + virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE; |
| + |
| + private: |
| + scoped_refptr<net::URLRequestContextGetter> request_context_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FakeOAuth2TokenService); |
| +}; |
| + |
| +class FakeIdentityProvider : public IdentityProvider { |
| + public: |
| + explicit FakeIdentityProvider( |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context); |
| + virtual ~FakeIdentityProvider(); |
| + |
| + // IdentityProvider: |
| + virtual OAuth2TokenService* GetTokenService() OVERRIDE; |
| + virtual std::string GetUsername() OVERRIDE; |
| + virtual std::string GetAccountId() OVERRIDE; |
| + virtual std::vector<std::string> GetAllAccountIds() OVERRIDE; |
| + virtual bool RequestLogin() OVERRIDE; |
| + |
| + void SignIn(const std::string& account_id); |
| + void SignOut(); |
| + |
| + private: |
| + std::string account_id_; |
| + FakeOAuth2TokenService token_service_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FakeIdentityProvider); |
| +}; |
| + |
| +class FakeGCMClientFactory : public GCMClientFactory { |
| + public: |
| + explicit FakeGCMClientFactory( |
| + GCMClientMock::LoadingDelay gcm_client_loading_delay); |
| + virtual ~FakeGCMClientFactory(); |
| + |
| + // GCMClientFactory: |
| + virtual scoped_ptr<GCMClient> BuildInstance() OVERRIDE; |
| + |
| + private: |
| + GCMClientMock::LoadingDelay gcm_client_loading_delay_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FakeGCMClientFactory); |
| +}; |
| + |
| +class FakeGCMAppHandler : public GCMAppHandler { |
| + public: |
| + enum Event { |
| + NO_EVENT, |
| + MESSAGE_EVENT, |
| + MESSAGES_DELETED_EVENT, |
| + SEND_ERROR_EVENT |
| + }; |
| + |
| + FakeGCMAppHandler(); |
| + virtual ~FakeGCMAppHandler(); |
| + |
| + const Event& received_event() const { return received_event_; } |
| + const std::string& app_id() const { return app_id_; } |
| + const GCMClient::IncomingMessage& message() const { return message_; } |
| + const GCMClient::SendErrorDetails& send_error_details() const { |
| + return send_error_details_; |
| + } |
| + |
| + void WaitForNotification(); |
| + |
| + // GCMAppHandler: |
| + virtual void ShutdownHandler() OVERRIDE; |
| + virtual void OnMessage(const std::string& app_id, |
| + const GCMClient::IncomingMessage& message) OVERRIDE; |
| + virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE; |
| + virtual void OnSendError( |
| + const std::string& app_id, |
| + const GCMClient::SendErrorDetails& send_error_details) OVERRIDE; |
| + |
| + private: |
| + void ClearResults(); |
| + |
| + scoped_ptr<base::RunLoop> run_loop_; |
| + |
| + Event received_event_; |
| + std::string app_id_; |
| + GCMClient::IncomingMessage message_; |
| + GCMClient::SendErrorDetails send_error_details_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FakeGCMAppHandler); |
| +}; |
| + |
| +class TestGCMService : public GCMService { |
| + public: |
| + TestGCMService( |
| + bool is_always_enabled, |
| + scoped_ptr<IdentityProvider> identity_provider, |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context); |
| + virtual ~TestGCMService(); |
| + |
| + // GCMService: |
| + virtual void Initialize( |
| + scoped_ptr<GCMClientFactory> gcm_client_factory) OVERRIDE; |
| + |
| + protected: |
| + // GCMService: |
| + virtual bool IsAlwaysEnabled() OVERRIDE; |
| + virtual base::FilePath GetStorePath() OVERRIDE; |
| + virtual scoped_refptr<net::URLRequestContextGetter> |
| + GetURLRequestContextGetter() OVERRIDE; |
| + |
| + private: |
| + base::ScopedTempDir temp_dir_; |
| + scoped_refptr<net::URLRequestContextGetter> request_context_; |
| + const bool is_always_enabled_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TestGCMService); |
| +}; |
| + |
| +FakeOAuth2TokenService::FakeOAuth2TokenService( |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context) |
| + : request_context_(request_context) { |
| +} |
| + |
| +FakeOAuth2TokenService::~FakeOAuth2TokenService() { |
| +} |
| + |
| +bool FakeOAuth2TokenService::RefreshTokenIsAvailable( |
| + const std::string& account_id) const { |
| + return false; |
| +} |
| + |
| +OAuth2AccessTokenFetcher* FakeOAuth2TokenService::CreateAccessTokenFetcher( |
| + const std::string& account_id, |
| + net::URLRequestContextGetter* getter, |
| + OAuth2AccessTokenConsumer* consumer) { |
| + return NULL; |
| +} |
| + |
| +net::URLRequestContextGetter* FakeOAuth2TokenService::GetRequestContext() { |
| + return request_context_; |
| +} |
| + |
| +FakeIdentityProvider::FakeIdentityProvider( |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context) |
| + : token_service_(request_context) { |
| +} |
| + |
| +FakeIdentityProvider::~FakeIdentityProvider() { |
| +} |
| + |
| +OAuth2TokenService* FakeIdentityProvider::GetTokenService() { |
| + return &token_service_; |
| +} |
| + |
| +std::string FakeIdentityProvider::GetUsername() { |
| + return account_id_; |
| +} |
| + |
| +std::string FakeIdentityProvider::GetAccountId() { |
| + return account_id_; |
| +} |
| + |
| +std::vector<std::string> FakeIdentityProvider::GetAllAccountIds() { |
| + std::vector<std::string> all_accounts; |
| + all_accounts.push_back(account_id_); |
| + return all_accounts; |
| +} |
| + |
| +bool FakeIdentityProvider::RequestLogin() { |
| + return true; |
| +} |
| + |
| +void FakeIdentityProvider::SignIn(const std::string& account_id) { |
| + account_id_ = account_id; |
| + FireOnLogin(); |
| +} |
| + |
| +void FakeIdentityProvider::SignOut() { |
| + account_id_.clear(); |
| + FireOnLogout(); |
| +} |
| + |
| +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_)); |
| +} |
| + |
| +FakeGCMAppHandler::FakeGCMAppHandler() : received_event_(NO_EVENT) { |
| +} |
| + |
| +FakeGCMAppHandler::~FakeGCMAppHandler() { |
| +} |
| + |
| +void FakeGCMAppHandler::WaitForNotification() { |
| + run_loop_.reset(new base::RunLoop); |
| + run_loop_->Run(); |
| + run_loop_.reset(); |
| +} |
| + |
| +void FakeGCMAppHandler::ShutdownHandler() { |
| +} |
| + |
| +void FakeGCMAppHandler::OnMessage(const std::string& app_id, |
| + const GCMClient::IncomingMessage& message) { |
| + ClearResults(); |
| + received_event_ = MESSAGE_EVENT; |
| + app_id_ = app_id; |
| + message_ = message; |
| + if (run_loop_) |
| + run_loop_->Quit(); |
| +} |
| + |
| +void FakeGCMAppHandler::OnMessagesDeleted(const std::string& app_id) { |
| + ClearResults(); |
| + received_event_ = MESSAGES_DELETED_EVENT; |
| + app_id_ = app_id; |
| + if (run_loop_) |
| + run_loop_->Quit(); |
| +} |
| + |
| +void FakeGCMAppHandler::OnSendError( |
| + const std::string& app_id, |
| + const GCMClient::SendErrorDetails& send_error_details) { |
| + ClearResults(); |
| + received_event_ = SEND_ERROR_EVENT; |
| + app_id_ = app_id; |
| + send_error_details_ = send_error_details; |
| + if (run_loop_) |
| + run_loop_->Quit(); |
| +} |
| + |
| +void FakeGCMAppHandler::ClearResults() { |
| + received_event_ = NO_EVENT; |
| + app_id_.clear(); |
| + message_ = GCMClient::IncomingMessage(); |
| + send_error_details_ = GCMClient::SendErrorDetails(); |
| +} |
| + |
| +TestGCMService::TestGCMService( |
| + bool is_always_enabled, |
| + scoped_ptr<IdentityProvider> identity_provider, |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context) |
| + : GCMService(identity_provider.Pass()), |
| + request_context_(request_context), |
| + is_always_enabled_(is_always_enabled) { |
| +} |
| + |
| +TestGCMService::~TestGCMService() { |
| +} |
| + |
| +void TestGCMService::Initialize( |
| + scoped_ptr<GCMClientFactory> gcm_client_factory) { |
| + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| + GCMService::Initialize(gcm_client_factory.Pass()); |
| +} |
| + |
| +bool TestGCMService::IsAlwaysEnabled() { |
| + return is_always_enabled_; |
| +} |
| + |
| +base::FilePath TestGCMService::GetStorePath() { |
| + return temp_dir_.path(); |
| +} |
| + |
| +scoped_refptr<net::URLRequestContextGetter> |
| +TestGCMService::GetURLRequestContextGetter() { |
| + return request_context_; |
| +} |
| + |
| +} // namespace |
| + |
| +class TestGCMServiceWrapper { |
| + public: |
| + explicit TestGCMServiceWrapper( |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context); |
| + ~TestGCMServiceWrapper(); |
| + |
| + TestGCMService* service() { return service_.get(); } |
| + FakeGCMAppHandler* gcm_app_handler() { return gcm_app_handler_.get(); } |
| + 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_; } |
| + GCMClient::Result unregistration_result() const { |
| + return unregistration_result_; |
| + } |
| + |
| + void ClearRegistrationResult(); |
| + void ClearUnregistrationResult(); |
| + |
| + bool ServiceHasAppHandlers() const; |
| + GCMClientMock* GetGCMClient(); |
| + |
| + void CreateService(bool service_is_always_enabled, |
| + GCMClientMock::LoadingDelay gcm_client_loading_delay); |
| + |
| + void SignIn(const std::string& account_id); |
| + void SignOut(); |
| + |
| + void Register(const std::string& app_id, |
| + const std::vector<std::string>& sender_ids, |
| + bool wait); |
| + void Send(const std::string& app_id, |
| + const std::string& receiver_id, |
| + const GCMClient::OutgoingMessage& message, |
| + bool wait); |
| + void Unregister(const std::string& app_id, bool wait); |
| + |
| + private: |
| + scoped_refptr<net::URLRequestContextGetter> request_context_; |
| + scoped_ptr<FakeIdentityProvider> identity_provider_owner_; |
| + FakeIdentityProvider* identity_provider_; |
| + scoped_ptr<TestGCMService> service_; |
| + scoped_ptr<FakeGCMAppHandler> gcm_app_handler_; |
| + |
| + std::string registration_id_; |
| + GCMClient::Result registration_result_; |
| + std::string send_message_id_; |
| + GCMClient::Result send_result_; |
| + GCMClient::Result unregistration_result_; |
| + |
| + void RegisterCompleted(const base::Closure& callback, |
| + const std::string& registration_id, |
| + GCMClient::Result result); |
| + void SendCompleted(const base::Closure& callback, |
| + const std::string& message_id, |
| + GCMClient::Result result); |
| + void UnregisterCompleted(const base::Closure& callback, |
| + GCMClient::Result result); |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TestGCMServiceWrapper); |
| +}; |
| + |
| +TestGCMServiceWrapper::TestGCMServiceWrapper( |
| + const scoped_refptr<net::URLRequestContextGetter>& request_context) |
| + : request_context_(request_context), |
| + identity_provider_(NULL), |
| + registration_result_(GCMClient::UNKNOWN_ERROR), |
| + send_result_(GCMClient::UNKNOWN_ERROR), |
| + unregistration_result_(GCMClient::UNKNOWN_ERROR) { |
| + identity_provider_owner_.reset(new FakeIdentityProvider(request_context_)); |
| + identity_provider_ = identity_provider_owner_.get(); |
| +} |
| + |
| +TestGCMServiceWrapper::~TestGCMServiceWrapper() { |
| + if (!service_) |
| + return; |
| + |
| + service_->Shutdown(); |
| + service_.reset(); |
| + PumpIOLoop(); |
| +} |
| + |
| +void TestGCMServiceWrapper::ClearRegistrationResult() { |
| + registration_id_.clear(); |
| + registration_result_ = GCMClient::UNKNOWN_ERROR; |
| +} |
| + |
| +void TestGCMServiceWrapper::ClearUnregistrationResult() { |
| + unregistration_result_ = GCMClient::UNKNOWN_ERROR; |
| +} |
| + |
| +bool TestGCMServiceWrapper::ServiceHasAppHandlers() const { |
| + return !service_->app_handlers_.empty(); |
| +} |
| + |
| +GCMClientMock* TestGCMServiceWrapper::GetGCMClient() { |
| + return static_cast<GCMClientMock*>(service_->GetGCMClientForTesting()); |
| +} |
| + |
| +void TestGCMServiceWrapper::CreateService( |
| + bool service_is_always_enabled, |
| + GCMClientMock::LoadingDelay gcm_client_loading_delay) { |
| + service_.reset(new TestGCMService( |
| + service_is_always_enabled, |
| + identity_provider_owner_.PassAs<IdentityProvider>(), |
| + request_context_)); |
| + service_->Initialize(scoped_ptr<GCMClientFactory>( |
| + new FakeGCMClientFactory(gcm_client_loading_delay))); |
| + |
| + gcm_app_handler_.reset(new FakeGCMAppHandler); |
| + service_->AddAppHandler(kTestAppID1, gcm_app_handler_.get()); |
| + service_->AddAppHandler(kTestAppID2, gcm_app_handler_.get()); |
| +} |
| + |
| +void TestGCMServiceWrapper::SignIn(const std::string& account_id) { |
| + identity_provider_->SignIn(account_id); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| +} |
| + |
| +void TestGCMServiceWrapper::SignOut() { |
| + identity_provider_->SignOut(); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| +} |
| + |
| +void TestGCMServiceWrapper::Register(const std::string& app_id, |
| + const std::vector<std::string>& sender_ids, |
| + bool wait) { |
|
jianli
2014/04/17 00:33:19
nit: better use enum to improve readability
bartfab (slow)
2014/04/22 17:51:07
Done.
|
| + base::RunLoop run_loop; |
| + service_->Register( |
| + app_id, |
| + sender_ids, |
| + base::Bind(&TestGCMServiceWrapper::RegisterCompleted, |
| + base::Unretained(this), |
| + wait ? run_loop.QuitClosure() : base::Bind(&base::DoNothing))); |
| + if (wait) |
| + run_loop.Run(); |
| +} |
| + |
| +void TestGCMServiceWrapper::Send(const std::string& app_id, |
| + const std::string& receiver_id, |
| + const GCMClient::OutgoingMessage& message, |
| + bool wait) { |
| + base::RunLoop run_loop; |
| + service_->Send( |
| + app_id, |
| + receiver_id, |
| + message, |
| + base::Bind(&TestGCMServiceWrapper::SendCompleted, |
| + base::Unretained(this), |
| + wait ? run_loop.QuitClosure() : base::Bind(&base::DoNothing))); |
| + if (wait) |
| + run_loop.Run(); |
| +} |
| + |
| +void TestGCMServiceWrapper::Unregister(const std::string& app_id, bool wait) { |
| + base::RunLoop run_loop; |
| + service_->Unregister( |
| + app_id, |
| + base::Bind(&TestGCMServiceWrapper::UnregisterCompleted, |
| + base::Unretained(this), |
| + wait ? run_loop.QuitClosure() : base::Bind(&base::DoNothing))); |
| + if (wait) |
| + run_loop.Run(); |
| +} |
| + |
| +void TestGCMServiceWrapper::RegisterCompleted( |
| + const base::Closure& callback, |
| + const std::string& registration_id, |
| + GCMClient::Result result) { |
| + registration_id_ = registration_id; |
| + registration_result_ = result; |
| + callback.Run(); |
| +} |
| + |
| +void TestGCMServiceWrapper::SendCompleted(const base::Closure& callback, |
| + const std::string& message_id, |
| + GCMClient::Result result) { |
| + send_message_id_ = message_id; |
| + send_result_ = result; |
| + callback.Run(); |
| +} |
| + |
| +void TestGCMServiceWrapper::UnregisterCompleted(const base::Closure& callback, |
| + GCMClient::Result result) { |
| + unregistration_result_ = result; |
| + callback.Run(); |
| +} |
| + |
| +class GCMServiceTest : public testing::Test { |
| + protected: |
| + GCMServiceTest(); |
| + virtual ~GCMServiceTest(); |
| + |
| + // testing::Test: |
| + void SetUp() OVERRIDE; |
| + void TearDown() OVERRIDE; |
| + |
| + scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_; |
| + scoped_refptr<net::URLRequestContextGetter> request_context_; |
| + scoped_ptr<TestGCMServiceWrapper> wrapper_; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(GCMServiceTest); |
| +}; |
| + |
| +GCMServiceTest::GCMServiceTest() { |
| +} |
| + |
| +GCMServiceTest::~GCMServiceTest() { |
| +} |
| + |
| +void GCMServiceTest::SetUp() { |
| + thread_bundle_.reset(new content::TestBrowserThreadBundle( |
| + content::TestBrowserThreadBundle::REAL_IO_THREAD)); |
| + request_context_ = new net::TestURLRequestContextGetter( |
| + content::BrowserThread::GetMessageLoopProxyForThread( |
| + content::BrowserThread::IO)); |
| + wrapper_.reset(new TestGCMServiceWrapper(request_context_)); |
| +} |
| + |
| +void GCMServiceTest::TearDown() { |
| + wrapper_.reset(); |
| +} |
| + |
| +TEST_F(GCMServiceTest, CreateGCMServiceBeforeSignIn) { |
| + // Create CreateGMCService first. |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + EXPECT_FALSE(wrapper_->service()->IsStarted()); |
| + |
| + // Sign in. This will kick off the check-in. |
| + wrapper_->SignIn(kTestAccountID1); |
| + EXPECT_TRUE(wrapper_->service()->IsStarted()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, CreateGCMServiceAfterSignIn) { |
| + // Sign in. This will not initiate the check-in. |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // Create GCMeService after sign-in. |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + EXPECT_TRUE(wrapper_->service()->IsStarted()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, Shutdown) { |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + EXPECT_TRUE(wrapper_->ServiceHasAppHandlers()); |
| + |
| + wrapper_->service()->Shutdown(); |
| + EXPECT_FALSE(wrapper_->ServiceHasAppHandlers()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, SignInAndSignOutUnderPositiveChannelSignal) { |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // GCMClient should be loaded. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| + |
| + wrapper_->SignOut(); |
| + |
| + // GCMClient should be checked out. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::CHECKED_OUT, wrapper_->GetGCMClient()->status()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, SignInAndSignOutUnderNonPositiveChannelSignal) { |
| + // Non-positive channel signal will prevent GCMClient from checking in during |
| + // sign-in. |
| + wrapper_->CreateService(false, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // GCMClient should not be loaded. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::UNINITIALIZED, wrapper_->GetGCMClient()->status()); |
| + |
| + wrapper_->SignOut(); |
| + |
| + // Check-out should still be performed. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::CHECKED_OUT, wrapper_->GetGCMClient()->status()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, SignOutAndThenSignIn) { |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // GCMClient should be loaded. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| + |
| + wrapper_->SignOut(); |
| + |
| + // GCMClient should be checked out. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::CHECKED_OUT, wrapper_->GetGCMClient()->status()); |
| + |
| + // Sign-in with a different account. |
| + wrapper_->SignIn(kTestAccountID2); |
| + |
| + // GCMClient should be loaded again. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, StopAndRestartGCM) { |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // GCMClient should be loaded. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Stops the GCM. |
| + wrapper_->service()->Stop(); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + |
| + // GCMClient should be stopped. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::STOPPED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Restarts the GCM. |
| + wrapper_->service()->Start(); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + |
| + // GCMClient should be loaded. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Stops the GCM. |
| + wrapper_->service()->Stop(); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + |
| + // GCMClient should be stopped. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::STOPPED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Sign out. |
| + wrapper_->SignOut(); |
| + |
| + // GCMClient should be checked out. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::CHECKED_OUT, wrapper_->GetGCMClient()->status()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, RegisterWhenNotSignedIn) { |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + EXPECT_TRUE(wrapper_->registration_id().empty()); |
| + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, RegisterUnderNonPositiveChannelSignal) { |
| + // Non-positive channel signal will prevent GCMClient from checking in during |
| + // sign-in. |
| + wrapper_->CreateService(false, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // GCMClient should not be checked in. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::UNINITIALIZED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Invoking register will make GCMClient checked in. |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + // GCMClient should be checked in. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Registration should succeed. |
| + const std::string expected_registration_id = |
| + GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids); |
| + EXPECT_EQ(expected_registration_id, wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, SendWhenNotSignedIn) { |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + |
| + GCMClient::OutgoingMessage message; |
| + message.id = "1"; |
| + message.data["key1"] = "value1"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, true); |
| + |
| + EXPECT_TRUE(wrapper_->send_message_id().empty()); |
| + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->send_result()); |
| +} |
| + |
| +TEST_F(GCMServiceTest, SendUnderNonPositiveChannelSignal) { |
| + // Non-positive channel signal will prevent GCMClient from checking in during |
| + // sign-in. |
| + wrapper_->CreateService(false, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // GCMClient should not be checked in. |
| + EXPECT_FALSE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::UNINITIALIZED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Invoking send will make GCMClient checked in. |
| + GCMClient::OutgoingMessage message; |
| + message.id = "1"; |
| + message.data["key1"] = "value1"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, true); |
| + |
| + // GCMClient should be checked in. |
| + EXPECT_TRUE(wrapper_->service()->IsGCMClientReady()); |
| + EXPECT_EQ(GCMClientMock::LOADED, wrapper_->GetGCMClient()->status()); |
| + |
| + // Sending should succeed. |
| + EXPECT_EQ(message.id, wrapper_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); |
| +} |
| + |
| +// Tests a single instance of GCMService. |
| +class GCMServiceSingleInstanceTest : public GCMServiceTest { |
| + public: |
| + GCMServiceSingleInstanceTest(); |
| + virtual ~GCMServiceSingleInstanceTest(); |
| + |
| + // GCMServiceTest: |
| + virtual void SetUp() OVERRIDE; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(GCMServiceSingleInstanceTest); |
| +}; |
| + |
| +GCMServiceSingleInstanceTest::GCMServiceSingleInstanceTest() { |
| +} |
| + |
| +GCMServiceSingleInstanceTest::~GCMServiceSingleInstanceTest() { |
| +} |
| + |
| +void GCMServiceSingleInstanceTest::SetUp() { |
| + GCMServiceTest::SetUp(); |
| + |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, Register) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + const std::string expected_registration_id = |
| + GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids); |
| + |
| + EXPECT_EQ(expected_registration_id, wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, RegisterError) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1@error"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + EXPECT_TRUE(wrapper_->registration_id().empty()); |
| + EXPECT_NE(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, RegisterAgainWithSameSenderIDs) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + sender_ids.push_back("sender2"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + const std::string expected_registration_id = |
| + GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids); |
| + |
| + EXPECT_EQ(expected_registration_id, wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + // Clears the results the would be set by the Register callback in preparation |
| + // to call register 2nd time. |
| + wrapper_->ClearRegistrationResult(); |
| + |
| + // Calling register 2nd time with the same set of sender IDs but different |
| + // ordering will get back the same registration ID. |
| + std::vector<std::string> another_sender_ids; |
| + another_sender_ids.push_back("sender2"); |
| + another_sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, another_sender_ids, true); |
| + |
| + EXPECT_EQ(expected_registration_id, wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, RegisterAgainWithDifferentSenderIDs) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + const std::string expected_registration_id = |
| + GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids); |
| + |
| + EXPECT_EQ(expected_registration_id, wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + // Make sender IDs different. |
| + sender_ids.push_back("sender2"); |
| + const std::string expected_registration_id_2 = |
| + GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids); |
| + |
| + // Calling register 2nd time with the different sender IDs will get back a new |
| + // registration ID. |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + EXPECT_EQ(expected_registration_id_2, wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, GCMClientNotReadyBeforeRegistration) { |
| + // Make GCMClient not ready initially. |
| + wrapper_.reset(new TestGCMServiceWrapper(request_context_)); |
| + wrapper_->CreateService(true, GCMClientMock::DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // The registration is on hold until GCMClient is ready. |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, false); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_TRUE(wrapper_->registration_id().empty()); |
| + EXPECT_EQ(GCMClient::UNKNOWN_ERROR, wrapper_->registration_result()); |
| + |
| + // Register operation will be invoked after GCMClient becomes ready. |
| + wrapper_->GetGCMClient()->PerformDelayedLoading(); |
| + PumpIOLoop(); |
|
jianli
2014/04/17 00:33:19
Why so many PumpIOLoop? Please explain like in ori
bartfab (slow)
2014/04/22 17:51:07
I replaced this with a proper wait until a notific
|
| + PumpIOLoop(); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_FALSE(wrapper_->registration_id().empty()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, RegisterAfterSignOut) { |
| + // This will trigger check-out. |
| + wrapper_->SignOut(); |
| + |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + EXPECT_TRUE(wrapper_->registration_id().empty()); |
| + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, UnregisterExplicitly) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + EXPECT_FALSE(wrapper_->registration_id().empty()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + wrapper_->Unregister(kTestAppID1, true); |
| + |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->unregistration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, UnregisterWhenAsyncOperationPending) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + // First start registration without waiting for it to complete. |
| + wrapper_->Register(kTestAppID1, sender_ids, false); |
| + |
| + // Test that unregistration fails with async operation pending when there is a |
| + // registration already in progress. |
| + wrapper_->Unregister(kTestAppID1, true); |
| + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, |
| + wrapper_->unregistration_result()); |
| + |
| + // Complete the unregistration. |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + // Start unregistration without waiting for it to complete. This time no async |
| + // operation is pending. |
| + wrapper_->Unregister(kTestAppID1, false); |
| + |
| + // Test that unregistration fails with async operation pending when there is |
| + // an unregistration already in progress. |
| + wrapper_->Unregister(kTestAppID1, true); |
| + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, |
| + wrapper_->unregistration_result()); |
| + wrapper_->ClearUnregistrationResult(); |
| + |
| + // Complete unregistration. |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->unregistration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, RegisterWhenAsyncOperationPending) { |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + // First start registration without waiting for it to complete. |
| + wrapper_->Register(kTestAppID1, sender_ids, false); |
| + |
| + // Test that registration fails with async operation pending when there is a |
| + // registration already in progress. |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, |
| + wrapper_->registration_result()); |
| + wrapper_->ClearRegistrationResult(); |
| + |
| + // Complete the registration. |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + // Start unregistration without waiting for it to complete. This time no async |
| + // operation is pending. |
| + wrapper_->Unregister(kTestAppID1, false); |
| + |
| + // Test that registration fails with async operation pending when there is an |
| + // unregistration already in progress. |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, |
| + wrapper_->registration_result()); |
| + |
| + // Complete the first unregistration expecting success. |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->unregistration_result()); |
| + |
| + // Test that it is ok to register again after unregistration. |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, Send) { |
| + GCMClient::OutgoingMessage message; |
| + message.id = "1"; |
| + message.data["key1"] = "value1"; |
| + message.data["key2"] = "value2"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, true); |
| + |
| + EXPECT_EQ(message.id, wrapper_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, GCMClientNotReadyBeforeSending) { |
| + // Make GCMClient not ready initially. |
| + wrapper_.reset(new TestGCMServiceWrapper(request_context_)); |
| + wrapper_->CreateService(true, GCMClientMock::DELAY_LOADING); |
| + wrapper_->SignIn(kTestAccountID1); |
| + |
| + // The sending is on hold until GCMClient is ready. |
| + GCMClient::OutgoingMessage message; |
| + message.id = "1"; |
| + message.data["key1"] = "value1"; |
| + message.data["key2"] = "value2"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, false); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + |
| + EXPECT_TRUE(wrapper_->send_message_id().empty()); |
| + EXPECT_EQ(GCMClient::UNKNOWN_ERROR, wrapper_->send_result()); |
| + |
| + // Send operation will be invoked after GCMClient becomes ready. |
| + wrapper_->GetGCMClient()->PerformDelayedLoading(); |
| + PumpIOLoop(); |
|
jianli
2014/04/17 00:33:19
ditto
bartfab (slow)
2014/04/22 17:51:07
I replaced this with a proper wait until a notific
|
| + PumpIOLoop(); |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + EXPECT_EQ(message.id, wrapper_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, SendAfterSignOut) { |
| + // This will trigger check-out. |
| + wrapper_->SignOut(); |
| + |
| + GCMClient::OutgoingMessage message; |
| + message.id = "1"; |
| + message.data["key1"] = "value1"; |
| + message.data["key2"] = "value2"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, true); |
| + |
| + EXPECT_TRUE(wrapper_->send_message_id().empty()); |
| + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->send_result()); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, 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"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, true); |
| + |
| + EXPECT_EQ(message.id, wrapper_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); |
| + |
| + // Wait for the send error. |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + EXPECT_EQ(FakeGCMAppHandler::SEND_ERROR_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(message.id, |
| + wrapper_->gcm_app_handler()->send_error_details().message_id); |
| + EXPECT_NE(GCMClient::SUCCESS, |
| + wrapper_->gcm_app_handler()->send_error_details().result); |
| + EXPECT_EQ(message.data, |
| + wrapper_->gcm_app_handler()->send_error_details().additional_data); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, MessageReceived) { |
| + wrapper_->Register(kTestAppID1, ToSenderList("sender"), true); |
| + GCMClient::IncomingMessage message; |
| + message.data["key1"] = "value1"; |
| + message.data["key2"] = "value2"; |
| + message.sender_id = "sender"; |
| + wrapper_->GetGCMClient()->ReceiveMessage(kTestAppID1, message); |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(message.data, wrapper_->gcm_app_handler()->message().data); |
| + EXPECT_TRUE(wrapper_->gcm_app_handler()->message().collapse_key.empty()); |
| + EXPECT_EQ(message.sender_id, |
| + wrapper_->gcm_app_handler()->message().sender_id); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, MessageWithCollapseKeyReceived) { |
| + wrapper_->Register(kTestAppID1, ToSenderList("sender"), true); |
| + GCMClient::IncomingMessage message; |
| + message.data["key1"] = "value1"; |
| + message.collapse_key = "collapse_key_value"; |
| + message.sender_id = "sender"; |
| + wrapper_->GetGCMClient()->ReceiveMessage(kTestAppID1, message); |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(message.data, wrapper_->gcm_app_handler()->message().data); |
| + EXPECT_EQ(message.collapse_key, |
| + wrapper_->gcm_app_handler()->message().collapse_key); |
| +} |
| + |
| +TEST_F(GCMServiceSingleInstanceTest, MessagesDeleted) { |
| + wrapper_->GetGCMClient()->DeleteMessages(kTestAppID1); |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGES_DELETED_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_->gcm_app_handler()->app_id()); |
| +} |
| + |
| +// Tests to make sure that concurrent GCMService instances work correctly |
| +// regardless how GCMClient is created. |
| +class GCMServiceMultipleInstanceTest : public GCMServiceTest { |
| + protected: |
| + GCMServiceMultipleInstanceTest(); |
| + virtual ~GCMServiceMultipleInstanceTest(); |
| + |
| + // GCMServiceTest: |
| + virtual void SetUp() OVERRIDE; |
| + virtual void TearDown() OVERRIDE; |
| + |
| + scoped_ptr<TestGCMServiceWrapper> wrapper_2_; |
|
jianli
2014/04/17 00:33:19
wrapper2_
bartfab (slow)
2014/04/17 14:20:01
Done.
|
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(GCMServiceMultipleInstanceTest); |
| +}; |
| + |
| +GCMServiceMultipleInstanceTest::GCMServiceMultipleInstanceTest() { |
| +} |
| + |
| +GCMServiceMultipleInstanceTest::~GCMServiceMultipleInstanceTest() { |
| +} |
| + |
| +void GCMServiceMultipleInstanceTest::SetUp() { |
| + GCMServiceTest::SetUp(); |
| + |
| + wrapper_2_.reset(new TestGCMServiceWrapper(request_context_)); |
| + |
| + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + wrapper_2_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); |
| + |
| + // Initiate check-in for each instance. |
| + wrapper_->SignIn(kTestAccountID1); |
| + wrapper_2_->SignIn(kTestAccountID2); |
| +} |
| + |
| +void GCMServiceMultipleInstanceTest::TearDown() { |
| + wrapper_2_.reset(); |
| +} |
| + |
| +TEST_F(GCMServiceMultipleInstanceTest, Register) { |
| + // Register an app. |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + // Register the same app in a different instance. |
| + std::vector<std::string> sender_ids2; |
| + sender_ids2.push_back("foo"); |
| + sender_ids2.push_back("bar"); |
| + wrapper_2_->Register(kTestAppID1, sender_ids2, true); |
| + |
| + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids), |
| + wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids2), |
| + wrapper_2_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->registration_result()); |
| + |
| + // Register a different app in a different instance. |
| + std::vector<std::string> sender_ids3; |
| + sender_ids3.push_back("sender1"); |
| + sender_ids3.push_back("sender2"); |
| + sender_ids3.push_back("sender3"); |
| + wrapper_2_->Register(kTestAppID2, sender_ids3, true); |
| + |
| + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids3), |
| + wrapper_2_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->registration_result()); |
| +} |
| + |
| +TEST_F(GCMServiceMultipleInstanceTest, Send) { |
| + // Send a message from one app in one instance. |
| + GCMClient::OutgoingMessage message; |
| + message.id = "1"; |
| + message.data["key1"] = "value1"; |
| + message.data["key2"] = "value2"; |
| + wrapper_->Send(kTestAppID1, kUserID1, message, true); |
| + |
| + // Send a message from same app in another instance. |
| + GCMClient::OutgoingMessage message2; |
| + message2.id = "2"; |
| + message2.data["foo"] = "bar"; |
| + wrapper_2_->Send(kTestAppID1, kUserID2, message2, true); |
| + |
| + EXPECT_EQ(message.id, wrapper_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); |
| + |
| + EXPECT_EQ(message2.id, wrapper_2_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->send_result()); |
| + |
| + // Send another message from different app in another instance. |
| + GCMClient::OutgoingMessage message3; |
| + message3.id = "3"; |
| + message3.data["hello"] = "world"; |
| + wrapper_2_->Send(kTestAppID2, kUserID1, message3, true); |
| + |
| + EXPECT_EQ(message3.id, wrapper_2_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->send_result()); |
| +} |
| + |
| +TEST_F(GCMServiceMultipleInstanceTest, MessageReceived) { |
| + wrapper_->Register(kTestAppID1, ToSenderList("sender"), true); |
| + wrapper_2_->Register(kTestAppID1, ToSenderList("sender"), true); |
| + wrapper_2_->Register(kTestAppID2, ToSenderList("sender2"), true); |
| + |
| + // Trigger an incoming message for an app in one instance. |
| + GCMClient::IncomingMessage message; |
| + message.data["key1"] = "value1"; |
| + message.data["key2"] = "value2"; |
| + message.sender_id = "sender"; |
| + wrapper_->GetGCMClient()->ReceiveMessage(kTestAppID1, message); |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + |
| + // Trigger an incoming message for the same app in another instance. |
| + GCMClient::IncomingMessage message2; |
| + message2.data["foo"] = "bar"; |
| + message2.sender_id = "sender"; |
| + wrapper_2_->GetGCMClient()->ReceiveMessage(kTestAppID1, message2); |
| + wrapper_2_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(message.data, wrapper_->gcm_app_handler()->message().data); |
| + EXPECT_EQ("sender", wrapper_->gcm_app_handler()->message().sender_id); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_2_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_2_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(message2.data, wrapper_2_->gcm_app_handler()->message().data); |
| + EXPECT_EQ("sender", wrapper_2_->gcm_app_handler()->message().sender_id); |
| + |
| + // Trigger another incoming message for a different app in another instance. |
| + GCMClient::IncomingMessage message3; |
| + message3.data["bar1"] = "foo1"; |
| + message3.data["bar2"] = "foo2"; |
| + message3.sender_id = "sender2"; |
| + wrapper_2_->GetGCMClient()->ReceiveMessage(kTestAppID2, message3); |
| + wrapper_2_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_2_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID2, wrapper_2_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(message3.data, wrapper_2_->gcm_app_handler()->message().data); |
| + EXPECT_EQ("sender2", wrapper_2_->gcm_app_handler()->message().sender_id); |
| +} |
| + |
| +// Test a set of GCM operations on multiple instances. |
| +// 1) Register 1 app in instance 1 and register 2 apps in instance 2; |
| +// 2) Send a message from instance 1; |
| +// 3) Receive a message to an app in instance 1 and receive a message for each |
| +// of the two apps in instance 2; |
| +// 4) Send a message for each of the two apps in instance 2; |
| +// 5) Sign out of instance 1. |
| +// 6) Register/send stops working for instance 1; |
| +// 7) The app in instance 2 can still receive these events; |
| +// 8) Sign into instance 1 with a different account. |
| +// 9) The message to the newly signed-in account will be routed. |
| +TEST_F(GCMServiceMultipleInstanceTest, Combined) { |
| + // Register an app. |
| + std::vector<std::string> sender_ids; |
| + sender_ids.push_back("sender1"); |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + |
| + // Register the same app in a different instance. |
| + std::vector<std::string> sender_ids2; |
| + sender_ids2.push_back("foo"); |
| + sender_ids2.push_back("bar"); |
| + wrapper_2_->Register(kTestAppID1, sender_ids2, true); |
| + |
| + // Register a different app in a different instance. |
| + std::vector<std::string> sender_ids3; |
| + sender_ids3.push_back("sender1"); |
| + sender_ids3.push_back("sender2"); |
| + sender_ids3.push_back("sender3"); |
| + wrapper_2_->Register(kTestAppID2, sender_ids3, true); |
| + |
| + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids), |
| + wrapper_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); |
| + |
| + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids3), |
| + wrapper_2_->registration_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->registration_result()); |
| + |
| + // Send a message from one instance. |
| + GCMClient::OutgoingMessage out_message; |
| + out_message.id = "1"; |
| + out_message.data["out1"] = "out_data1"; |
| + out_message.data["out1_2"] = "out_data1_2"; |
| + wrapper_->Send(kTestAppID1, kUserID1, out_message, true); |
| + |
| + EXPECT_EQ(out_message.id, wrapper_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); |
| + |
| + // Trigger an incoming message for an app in one instance. |
| + GCMClient::IncomingMessage in_message; |
| + in_message.data["in1"] = "in_data1"; |
| + in_message.data["in1_2"] = "in_data1_2"; |
| + in_message.sender_id = "sender1"; |
| + wrapper_->GetGCMClient()->ReceiveMessage(kTestAppID1, in_message); |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(in_message.data, wrapper_->gcm_app_handler()->message().data); |
| + |
| + // Trigger 2 incoming messages, one for each app respectively, in another |
| + // instance. |
| + GCMClient::IncomingMessage in_message2; |
| + in_message2.data["in2"] = "in_data2"; |
| + in_message2.sender_id = "sender3"; |
| + wrapper_2_->GetGCMClient()->ReceiveMessage(kTestAppID2, in_message2); |
| + |
| + GCMClient::IncomingMessage in_message3; |
| + in_message3.data["in3"] = "in_data3"; |
| + in_message3.data["in3_2"] = "in_data3_2"; |
| + in_message3.sender_id = "foo"; |
| + wrapper_2_->GetGCMClient()->ReceiveMessage(kTestAppID1, in_message3); |
| + |
| + wrapper_2_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_2_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID2, wrapper_2_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(in_message2.data, wrapper_2_->gcm_app_handler()->message().data); |
| + |
| + wrapper_2_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_2_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_2_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(in_message3.data, wrapper_2_->gcm_app_handler()->message().data); |
| + |
| + // Send two messages, one for each app respectively, from another instance. |
| + GCMClient::OutgoingMessage out_message2; |
| + out_message2.id = "2"; |
| + out_message2.data["out2"] = "out_data2"; |
| + wrapper_2_->Send(kTestAppID1, kUserID2, out_message2, true); |
| + |
| + GCMClient::OutgoingMessage out_message3; |
| + out_message3.id = "3"; |
| + out_message3.data["out3"] = "out_data3"; |
| + wrapper_2_->Send(kTestAppID2, kUserID2, out_message3, false); |
| + |
| + EXPECT_EQ(out_message2.id, wrapper_2_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->send_result()); |
| + |
| + PumpIOLoop(); |
| + PumpUILoop(); |
| + |
| + EXPECT_EQ(out_message3.id, wrapper_2_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->send_result()); |
| + |
| + // Sign out of one instance. |
| + wrapper_->SignOut(); |
| + |
| + // Register/send stops working for signed-out instance. |
| + wrapper_->Register(kTestAppID1, sender_ids, true); |
| + EXPECT_TRUE(wrapper_->registration_id().empty()); |
| + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->registration_result()); |
| + |
| + wrapper_->Send(kTestAppID2, kUserID2, out_message3, true); |
| + EXPECT_TRUE(wrapper_->send_message_id().empty()); |
| + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->send_result()); |
| + |
| + // Deleted messages event will go through for another signed-in instance. |
| + wrapper_2_->GetGCMClient()->DeleteMessages(kTestAppID2); |
| + wrapper_2_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGES_DELETED_EVENT, |
| + wrapper_2_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID2, wrapper_2_->gcm_app_handler()->app_id()); |
| + |
| + // Send error event will go through for another signed-in instance. |
| + GCMClient::OutgoingMessage out_message4; |
| + out_message4.id = "1@error"; |
| + out_message4.data["out4"] = "out_data4"; |
| + wrapper_2_->Send(kTestAppID1, kUserID1, out_message4, true); |
| + |
| + EXPECT_EQ(out_message4.id, wrapper_2_->send_message_id()); |
| + EXPECT_EQ(GCMClient::SUCCESS, wrapper_2_->send_result()); |
| + |
| + wrapper_2_->gcm_app_handler()->WaitForNotification(); |
| + EXPECT_EQ(FakeGCMAppHandler::SEND_ERROR_EVENT, |
| + wrapper_2_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(kTestAppID1, wrapper_2_->gcm_app_handler()->app_id()); |
| + EXPECT_EQ(out_message4.id, |
| + wrapper_2_->gcm_app_handler()->send_error_details().message_id); |
| + EXPECT_NE(GCMClient::SUCCESS, |
| + wrapper_2_->gcm_app_handler()->send_error_details().result); |
| + EXPECT_EQ( |
| + out_message4.data, |
| + wrapper_2_->gcm_app_handler()->send_error_details().additional_data); |
| + |
| + // Sign in with a different account. |
| + wrapper_->SignIn(kTestAccountID3); |
| + |
| + // Signing out cleared all registrations, so we need to register again. |
| + wrapper_->Register(kTestAppID1, ToSenderList("sender1"), true); |
| + |
| + // Incoming message will go through for the new signed-in account. |
| + GCMClient::IncomingMessage in_message5; |
| + in_message5.data["in5"] = "in_data5"; |
| + in_message5.sender_id = "sender1"; |
| + wrapper_->GetGCMClient()->ReceiveMessage(kTestAppID1, in_message5); |
| + |
| + wrapper_->gcm_app_handler()->WaitForNotification(); |
| + |
| + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, |
| + wrapper_->gcm_app_handler()->received_event()); |
| + EXPECT_EQ(in_message5.data, wrapper_->gcm_app_handler()->message().data); |
| +} |
| + |
| +} // namespace gcm |