diff options
Diffstat (limited to 'chrome/browser/services/gcm/gcm_service_unittest.cc')
-rw-r--r-- | chrome/browser/services/gcm/gcm_service_unittest.cc | 1318 |
1 files changed, 1318 insertions, 0 deletions
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 0000000..b54e8ca --- /dev/null +++ b/chrome/browser/services/gcm/gcm_service_unittest.cc @@ -0,0 +1,1318 @@ +// 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/fake_gcm_client_factory.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/fake_identity_provider.h" +#include "google_apis/gaia/fake_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 PumpCurrentLoop() { + base::RunLoop().RunUntilIdle(); +} + +void PumpUILoop() { + PumpCurrentLoop(); +} + +void PumpIOLoop() { + base::RunLoop run_loop; + content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO, + FROM_HERE, + base::Bind(&PumpCurrentLoop), + 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 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 start_automatically, + scoped_ptr<IdentityProvider> identity_provider, + const scoped_refptr<net::URLRequestContextGetter>& request_context); + virtual ~TestGCMService(); + + protected: + // GCMService: + virtual bool ShouldStartAutomatically() const OVERRIDE; + virtual base::FilePath GetStorePath() const OVERRIDE; + virtual scoped_refptr<net::URLRequestContextGetter> + GetURLRequestContextGetter() const OVERRIDE; + + private: + base::ScopedTempDir temp_dir_; + scoped_refptr<net::URLRequestContextGetter> request_context_; + const bool start_automatically_; + + DISALLOW_COPY_AND_ASSIGN(TestGCMService); +}; + +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 start_automatically, + scoped_ptr<IdentityProvider> identity_provider, + const scoped_refptr<net::URLRequestContextGetter>& request_context) + : GCMService(identity_provider.Pass()), + request_context_(request_context), + start_automatically_(start_automatically) { + if (!temp_dir_.CreateUniqueTempDir()) + ADD_FAILURE(); +} + +TestGCMService::~TestGCMService() { +} + +bool TestGCMService::ShouldStartAutomatically() const { + return start_automatically_; +} + +base::FilePath TestGCMService::GetStorePath() const { + return temp_dir_.path(); +} + +scoped_refptr<net::URLRequestContextGetter> +TestGCMService::GetURLRequestContextGetter() const { + return request_context_; +} + +} // namespace + +class TestGCMServiceWrapper { + public: + enum WaitToFinish { + DO_NOT_WAIT, + WAIT + }; + + 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 start_automatically, + 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, + WaitToFinish wait_to_finish); + void Send(const std::string& app_id, + const std::string& receiver_id, + const GCMClient::OutgoingMessage& message, + WaitToFinish wait_to_finish); + void Unregister(const std::string& app_id, WaitToFinish wait_to_finish); + + void WaitForAsyncOperation(); + + private: + void RegisterCompleted(const std::string& registration_id, + GCMClient::Result result); + void SendCompleted(const std::string& message_id, GCMClient::Result result); + void UnregisterCompleted(GCMClient::Result result); + + scoped_refptr<net::URLRequestContextGetter> request_context_; + FakeOAuth2TokenService token_service_; + scoped_ptr<FakeIdentityProvider> identity_provider_owner_; + FakeIdentityProvider* identity_provider_; + scoped_ptr<TestGCMService> service_; + scoped_ptr<FakeGCMAppHandler> gcm_app_handler_; + + base::Closure async_operation_completed_callback_; + + std::string registration_id_; + GCMClient::Result registration_result_; + std::string send_message_id_; + GCMClient::Result send_result_; + GCMClient::Result unregistration_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(&token_service_)); + identity_provider_ = identity_provider_owner_.get(); +} + +TestGCMServiceWrapper::~TestGCMServiceWrapper() { + if (!service_) + return; + + service_->ShutdownService(); + 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 start_automatically, + GCMClientMock::LoadingDelay gcm_client_loading_delay) { + service_.reset(new TestGCMService( + start_automatically, + 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) { + token_service_.AddAccount(account_id); + identity_provider_->LogIn(account_id); + PumpIOLoop(); + PumpUILoop(); +} + +void TestGCMServiceWrapper::SignOut() { + identity_provider_->LogOut(); + PumpIOLoop(); + PumpUILoop(); +} + +void TestGCMServiceWrapper::Register(const std::string& app_id, + const std::vector<std::string>& sender_ids, + WaitToFinish wait_to_finish) { + base::RunLoop run_loop; + async_operation_completed_callback_ = run_loop.QuitClosure(); + service_->Register(app_id, + sender_ids, + base::Bind(&TestGCMServiceWrapper::RegisterCompleted, + base::Unretained(this))); + if (wait_to_finish == WAIT) + run_loop.Run(); +} + +void TestGCMServiceWrapper::Send(const std::string& app_id, + const std::string& receiver_id, + const GCMClient::OutgoingMessage& message, + WaitToFinish wait_to_finish) { + base::RunLoop run_loop; + async_operation_completed_callback_ = run_loop.QuitClosure(); + service_->Send(app_id, + receiver_id, + message, + base::Bind(&TestGCMServiceWrapper::SendCompleted, + base::Unretained(this))); + if (wait_to_finish == WAIT) + run_loop.Run(); +} + +void TestGCMServiceWrapper::Unregister(const std::string& app_id, + WaitToFinish wait_to_finish) { + base::RunLoop run_loop; + async_operation_completed_callback_ = run_loop.QuitClosure(); + service_->Unregister(app_id, + base::Bind(&TestGCMServiceWrapper::UnregisterCompleted, + base::Unretained(this))); + if (wait_to_finish == WAIT) + run_loop.Run(); +} + +void TestGCMServiceWrapper::WaitForAsyncOperation() { + base::RunLoop run_loop; + async_operation_completed_callback_ = run_loop.QuitClosure(); + run_loop.Run(); +} + +void TestGCMServiceWrapper::RegisterCompleted( + const std::string& registration_id, + GCMClient::Result result) { + registration_id_ = registration_id; + registration_result_ = result; + if (!async_operation_completed_callback_.is_null()) + async_operation_completed_callback_.Run(); +} + +void TestGCMServiceWrapper::SendCompleted(const std::string& message_id, + GCMClient::Result result) { + send_message_id_ = message_id; + send_result_ = result; + if (!async_operation_completed_callback_.is_null()) + async_operation_completed_callback_.Run(); +} + +void TestGCMServiceWrapper::UnregisterCompleted(GCMClient::Result result) { + unregistration_result_ = result; + if (!async_operation_completed_callback_.is_null()) + async_operation_completed_callback_.Run(); +} + +class GCMServiceTest : public testing::Test { + protected: + GCMServiceTest(); + virtual ~GCMServiceTest(); + + // testing::Test: + virtual void SetUp() OVERRIDE; + virtual 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()->ShutdownService(); + 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, TestGCMServiceWrapper::WAIT); + + 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, TestGCMServiceWrapper::WAIT); + + // 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, TestGCMServiceWrapper::WAIT); + + 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, TestGCMServiceWrapper::WAIT); + + // 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, TestGCMServiceWrapper::WAIT); + 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, TestGCMServiceWrapper::WAIT); + + 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, TestGCMServiceWrapper::WAIT); + 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, + TestGCMServiceWrapper::WAIT); + + 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, TestGCMServiceWrapper::WAIT); + 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_id2 = + 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, TestGCMServiceWrapper::WAIT); + EXPECT_EQ(expected_registration_id2, 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, + TestGCMServiceWrapper::DO_NOT_WAIT); + 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(); + wrapper_->WaitForAsyncOperation(); + 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, TestGCMServiceWrapper::WAIT); + + 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, TestGCMServiceWrapper::WAIT); + + EXPECT_FALSE(wrapper_->registration_id().empty()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); + + wrapper_->Unregister(kTestAppID1, TestGCMServiceWrapper::WAIT); + + 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, + TestGCMServiceWrapper::DO_NOT_WAIT); + + // Test that unregistration fails with async operation pending when there is a + // registration already in progress. + wrapper_->Unregister(kTestAppID1, TestGCMServiceWrapper::WAIT); + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, + wrapper_->unregistration_result()); + + // Complete the unregistration. + wrapper_->WaitForAsyncOperation(); + 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, TestGCMServiceWrapper::DO_NOT_WAIT); + + // Test that unregistration fails with async operation pending when there is + // an unregistration already in progress. + wrapper_->Unregister(kTestAppID1, TestGCMServiceWrapper::WAIT); + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, + wrapper_->unregistration_result()); + wrapper_->ClearUnregistrationResult(); + + // Complete unregistration. + wrapper_->WaitForAsyncOperation(); + 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, + TestGCMServiceWrapper::DO_NOT_WAIT); + + // Test that registration fails with async operation pending when there is a + // registration already in progress. + wrapper_->Register(kTestAppID1, sender_ids, TestGCMServiceWrapper::WAIT); + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, + wrapper_->registration_result()); + wrapper_->ClearRegistrationResult(); + + // Complete the registration. + wrapper_->WaitForAsyncOperation(); + 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, TestGCMServiceWrapper::DO_NOT_WAIT); + + // Test that registration fails with async operation pending when there is an + // unregistration already in progress. + wrapper_->Register(kTestAppID1, sender_ids, TestGCMServiceWrapper::WAIT); + EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING, + wrapper_->registration_result()); + + // Complete the first unregistration expecting success. + wrapper_->WaitForAsyncOperation(); + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->unregistration_result()); + + // Test that it is ok to register again after unregistration. + wrapper_->Register(kTestAppID1, sender_ids, TestGCMServiceWrapper::WAIT); + 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, TestGCMServiceWrapper::WAIT); + + 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, + TestGCMServiceWrapper::DO_NOT_WAIT); + 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(); + wrapper_->WaitForAsyncOperation(); + 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, TestGCMServiceWrapper::WAIT); + + 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, TestGCMServiceWrapper::WAIT); + + 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"), + TestGCMServiceWrapper::WAIT); + 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"), + TestGCMServiceWrapper::WAIT); + 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> wrapper2_; + + private: + DISALLOW_COPY_AND_ASSIGN(GCMServiceMultipleInstanceTest); +}; + +GCMServiceMultipleInstanceTest::GCMServiceMultipleInstanceTest() { +} + +GCMServiceMultipleInstanceTest::~GCMServiceMultipleInstanceTest() { +} + +void GCMServiceMultipleInstanceTest::SetUp() { + GCMServiceTest::SetUp(); + + wrapper2_.reset(new TestGCMServiceWrapper(request_context_)); + + wrapper_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); + wrapper2_->CreateService(true, GCMClientMock::NO_DELAY_LOADING); + + // Initiate check-in for each instance. + wrapper_->SignIn(kTestAccountID1); + wrapper2_->SignIn(kTestAccountID2); +} + +void GCMServiceMultipleInstanceTest::TearDown() { + wrapper2_.reset(); +} + +TEST_F(GCMServiceMultipleInstanceTest, Register) { + // Register an app. + std::vector<std::string> sender_ids; + sender_ids.push_back("sender1"); + wrapper_->Register(kTestAppID1, sender_ids, TestGCMServiceWrapper::WAIT); + + // Register the same app in a different instance. + std::vector<std::string> sender_ids2; + sender_ids2.push_back("foo"); + sender_ids2.push_back("bar"); + wrapper2_->Register(kTestAppID1, sender_ids2, TestGCMServiceWrapper::WAIT); + + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids), + wrapper_->registration_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); + + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids2), + wrapper2_->registration_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->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"); + wrapper2_->Register(kTestAppID2, sender_ids3, TestGCMServiceWrapper::WAIT); + + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids3), + wrapper2_->registration_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->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, TestGCMServiceWrapper::WAIT); + + // Send a message from same app in another instance. + GCMClient::OutgoingMessage message2; + message2.id = "2"; + message2.data["foo"] = "bar"; + wrapper2_->Send(kTestAppID1, kUserID2, message2, TestGCMServiceWrapper::WAIT); + + EXPECT_EQ(message.id, wrapper_->send_message_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->send_result()); + + EXPECT_EQ(message2.id, wrapper2_->send_message_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->send_result()); + + // Send another message from different app in another instance. + GCMClient::OutgoingMessage message3; + message3.id = "3"; + message3.data["hello"] = "world"; + wrapper2_->Send(kTestAppID2, kUserID1, message3, TestGCMServiceWrapper::WAIT); + + EXPECT_EQ(message3.id, wrapper2_->send_message_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->send_result()); +} + +TEST_F(GCMServiceMultipleInstanceTest, MessageReceived) { + wrapper_->Register(kTestAppID1, + ToSenderList("sender"), + TestGCMServiceWrapper::WAIT); + wrapper2_->Register(kTestAppID1, + ToSenderList("sender"), + TestGCMServiceWrapper::WAIT); + wrapper2_->Register(kTestAppID2, + ToSenderList("sender2"), + TestGCMServiceWrapper::WAIT); + + // 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"; + wrapper2_->GetGCMClient()->ReceiveMessage(kTestAppID1, message2); + wrapper2_->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, + wrapper2_->gcm_app_handler()->received_event()); + EXPECT_EQ(kTestAppID1, wrapper2_->gcm_app_handler()->app_id()); + EXPECT_EQ(message2.data, wrapper2_->gcm_app_handler()->message().data); + EXPECT_EQ("sender", wrapper2_->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"; + wrapper2_->GetGCMClient()->ReceiveMessage(kTestAppID2, message3); + wrapper2_->gcm_app_handler()->WaitForNotification(); + + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, + wrapper2_->gcm_app_handler()->received_event()); + EXPECT_EQ(kTestAppID2, wrapper2_->gcm_app_handler()->app_id()); + EXPECT_EQ(message3.data, wrapper2_->gcm_app_handler()->message().data); + EXPECT_EQ("sender2", wrapper2_->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, TestGCMServiceWrapper::WAIT); + + // Register the same app in a different instance. + std::vector<std::string> sender_ids2; + sender_ids2.push_back("foo"); + sender_ids2.push_back("bar"); + wrapper2_->Register(kTestAppID1, sender_ids2, TestGCMServiceWrapper::WAIT); + + // 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"); + wrapper2_->Register(kTestAppID2, sender_ids3, TestGCMServiceWrapper::WAIT); + + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids), + wrapper_->registration_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper_->registration_result()); + + EXPECT_EQ(GCMClientMock::GetRegistrationIdFromSenderIds(sender_ids3), + wrapper2_->registration_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->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, + TestGCMServiceWrapper::WAIT); + + 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"; + wrapper2_->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"; + wrapper2_->GetGCMClient()->ReceiveMessage(kTestAppID1, in_message3); + + wrapper2_->gcm_app_handler()->WaitForNotification(); + + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, + wrapper2_->gcm_app_handler()->received_event()); + EXPECT_EQ(kTestAppID2, wrapper2_->gcm_app_handler()->app_id()); + EXPECT_EQ(in_message2.data, wrapper2_->gcm_app_handler()->message().data); + + wrapper2_->gcm_app_handler()->WaitForNotification(); + + EXPECT_EQ(FakeGCMAppHandler::MESSAGE_EVENT, + wrapper2_->gcm_app_handler()->received_event()); + EXPECT_EQ(kTestAppID1, wrapper2_->gcm_app_handler()->app_id()); + EXPECT_EQ(in_message3.data, wrapper2_->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"; + wrapper2_->Send(kTestAppID1, + kUserID2, + out_message2, + TestGCMServiceWrapper::WAIT); + + GCMClient::OutgoingMessage out_message3; + out_message3.id = "3"; + out_message3.data["out3"] = "out_data3"; + wrapper2_->Send(kTestAppID2, + kUserID2, + out_message3, + TestGCMServiceWrapper::DO_NOT_WAIT); + + EXPECT_EQ(out_message2.id, wrapper2_->send_message_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->send_result()); + + wrapper2_->WaitForAsyncOperation(); + + EXPECT_EQ(out_message3.id, wrapper2_->send_message_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->send_result()); + + // Sign out of one instance. + wrapper_->SignOut(); + + // Register/send stops working for signed-out instance. + wrapper_->Register(kTestAppID1, sender_ids, TestGCMServiceWrapper::WAIT); + EXPECT_TRUE(wrapper_->registration_id().empty()); + EXPECT_EQ(GCMClient::NOT_SIGNED_IN, wrapper_->registration_result()); + + wrapper_->Send(kTestAppID2, + kUserID2, + out_message3, + TestGCMServiceWrapper::WAIT); + 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. + wrapper2_->GetGCMClient()->DeleteMessages(kTestAppID2); + wrapper2_->gcm_app_handler()->WaitForNotification(); + + EXPECT_EQ(FakeGCMAppHandler::MESSAGES_DELETED_EVENT, + wrapper2_->gcm_app_handler()->received_event()); + EXPECT_EQ(kTestAppID2, wrapper2_->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"; + wrapper2_->Send(kTestAppID1, + kUserID1, + out_message4, + TestGCMServiceWrapper::WAIT); + + EXPECT_EQ(out_message4.id, wrapper2_->send_message_id()); + EXPECT_EQ(GCMClient::SUCCESS, wrapper2_->send_result()); + + wrapper2_->gcm_app_handler()->WaitForNotification(); + EXPECT_EQ(FakeGCMAppHandler::SEND_ERROR_EVENT, + wrapper2_->gcm_app_handler()->received_event()); + EXPECT_EQ(kTestAppID1, wrapper2_->gcm_app_handler()->app_id()); + EXPECT_EQ(out_message4.id, + wrapper2_->gcm_app_handler()->send_error_details().message_id); + EXPECT_NE(GCMClient::SUCCESS, + wrapper2_->gcm_app_handler()->send_error_details().result); + EXPECT_EQ(out_message4.data, + wrapper2_->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"), + TestGCMServiceWrapper::WAIT); + + // 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 |