// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/prefs/pref_service.h" #include "base/run_loop.h" #include "chrome/browser/extensions/api/gcm/gcm_api.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_gcm_app_handler.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/services/gcm/fake_gcm_profile_service.h" #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/ui_test_utils.h" #include "extensions/test/result_catcher.h" using extensions::ResultCatcher; namespace { const char kEventsExtension[] = "gcm/events"; gcm::GCMClient::SendErrorDetails CreateErrorDetails( const std::string& message_id, const gcm::GCMClient::Result result, const std::string& total_messages) { gcm::GCMClient::SendErrorDetails error; error.message_id = message_id; error.result = result; error.additional_data["expectedMessageId"] = message_id; switch (result) { case gcm::GCMClient::ASYNC_OPERATION_PENDING: error.additional_data["expectedErrorMessage"] = "Asynchronous operation is pending."; break; case gcm::GCMClient::SERVER_ERROR: error.additional_data["expectedErrorMessage"] = "Server error occurred."; break; case gcm::GCMClient::NETWORK_ERROR: error.additional_data["expectedErrorMessage"] = "Network error occurred."; break; case gcm::GCMClient::TTL_EXCEEDED: error.additional_data["expectedErrorMessage"] = "Time-to-live exceeded."; break; case gcm::GCMClient::UNKNOWN_ERROR: default: // Default case is the same as UNKNOWN_ERROR error.additional_data["expectedErrorMessage"] = "Unknown error occurred."; break; } error.additional_data["totalMessages"] = total_messages; return error; } } // namespace namespace extensions { class GcmApiTest : public ExtensionApiTest { public: GcmApiTest() : fake_gcm_profile_service_(NULL) {} protected: virtual void SetUpCommandLine(CommandLine* command_line) override; virtual void SetUpOnMainThread() override; void StartCollecting(); const Extension* LoadTestExtension(const std::string& extension_path, const std::string& page_name); gcm::FakeGCMProfileService* service() const; private: gcm::FakeGCMProfileService* fake_gcm_profile_service_; }; void GcmApiTest::SetUpCommandLine(CommandLine* command_line) { // We now always create the GCMProfileService instance in // ProfileSyncServiceFactory that is called when a profile is being // initialized. In order to prevent it from being created, we add the switch // to disable the sync logic. command_line->AppendSwitch(switches::kDisableSync); ExtensionApiTest::SetUpCommandLine(command_line); } void GcmApiTest::SetUpOnMainThread() { // Enable GCM such that tests could be run on all channels. browser()->profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true); gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactory( browser()->profile(), &gcm::FakeGCMProfileService::Build); fake_gcm_profile_service_ = static_cast( gcm::GCMProfileServiceFactory::GetInstance()->GetForProfile( browser()->profile())); ExtensionApiTest::SetUpOnMainThread(); } void GcmApiTest::StartCollecting() { service()->set_collect(true); } gcm::FakeGCMProfileService* GcmApiTest::service() const { return fake_gcm_profile_service_; } const Extension* GcmApiTest::LoadTestExtension( const std::string& extension_path, const std::string& page_name) { const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(extension_path)); if (extension) { ui_test_utils::NavigateToURL( browser(), extension->GetResourceURL(page_name)); } return extension; } IN_PROC_BROWSER_TEST_F(GcmApiTest, RegisterValidation) { ASSERT_TRUE(RunExtensionTest("gcm/functions/register_validation")); } IN_PROC_BROWSER_TEST_F(GcmApiTest, Register) { StartCollecting(); ASSERT_TRUE(RunExtensionTest("gcm/functions/register")); const std::vector& sender_ids = service()->last_registered_sender_ids(); EXPECT_TRUE(std::find(sender_ids.begin(), sender_ids.end(), "Sender1") != sender_ids.end()); EXPECT_TRUE(std::find(sender_ids.begin(), sender_ids.end(), "Sender2") != sender_ids.end()); } IN_PROC_BROWSER_TEST_F(GcmApiTest, Unregister) { service()->AddExpectedUnregisterResponse(gcm::GCMClient::SUCCESS); service()->AddExpectedUnregisterResponse(gcm::GCMClient::SERVER_ERROR); ASSERT_TRUE(RunExtensionTest("gcm/functions/unregister")); } IN_PROC_BROWSER_TEST_F(GcmApiTest, SendValidation) { ASSERT_TRUE(RunExtensionTest("gcm/functions/send")); } IN_PROC_BROWSER_TEST_F(GcmApiTest, SendMessageData) { StartCollecting(); ASSERT_TRUE(RunExtensionTest("gcm/functions/send_message_data")); EXPECT_EQ("destination-id", service()->last_receiver_id()); const gcm::GCMClient::OutgoingMessage& message = service()->last_sent_message(); gcm::GCMClient::MessageData::const_iterator iter; EXPECT_EQ(100, message.time_to_live); EXPECT_TRUE((iter = message.data.find("key1")) != message.data.end()); EXPECT_EQ("value1", iter->second); EXPECT_TRUE((iter = message.data.find("key2")) != message.data.end()); EXPECT_EQ("value2", iter->second); } IN_PROC_BROWSER_TEST_F(GcmApiTest, SendMessageDefaultTTL) { StartCollecting(); ASSERT_TRUE(RunExtensionTest("gcm/functions/send_message_default_ttl")); EXPECT_EQ("destination-id", service()->last_receiver_id()); const gcm::GCMClient::OutgoingMessage& message = service()->last_sent_message(); gcm::GCMClient::MessageData::const_iterator iter; EXPECT_EQ(gcm::GCMClient::OutgoingMessage::kMaximumTTL, message.time_to_live); } IN_PROC_BROWSER_TEST_F(GcmApiTest, OnMessagesDeleted) { ResultCatcher catcher; catcher.RestrictToBrowserContext(profile()); const extensions::Extension* extension = LoadTestExtension(kEventsExtension, "on_messages_deleted.html"); ASSERT_TRUE(extension); extensions::ExtensionGCMAppHandler app_handler(profile()); app_handler.OnMessagesDeleted(extension->id()); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } IN_PROC_BROWSER_TEST_F(GcmApiTest, OnMessage) { ResultCatcher catcher; catcher.RestrictToBrowserContext(profile()); const extensions::Extension* extension = LoadTestExtension(kEventsExtension, "on_message.html"); ASSERT_TRUE(extension); extensions::ExtensionGCMAppHandler app_handler(profile()); gcm::GCMClient::IncomingMessage message; message.data["property1"] = "value1"; message.data["property2"] = "value2"; // First message is sent without a collapse key. app_handler.OnMessage(extension->id(), message); // Second message carries the same data and a collapse key. message.collapse_key = "collapseKeyValue"; app_handler.OnMessage(extension->id(), message); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } IN_PROC_BROWSER_TEST_F(GcmApiTest, OnSendError) { ResultCatcher catcher; catcher.RestrictToBrowserContext(profile()); const extensions::Extension* extension = LoadTestExtension(kEventsExtension, "on_send_error.html"); ASSERT_TRUE(extension); std::string total_expected_messages = "5"; extensions::ExtensionGCMAppHandler app_handler(profile()); app_handler.OnSendError( extension->id(), CreateErrorDetails("error_message_1", gcm::GCMClient::ASYNC_OPERATION_PENDING, total_expected_messages)); app_handler.OnSendError( extension->id(), CreateErrorDetails("error_message_2", gcm::GCMClient::SERVER_ERROR, total_expected_messages)); app_handler.OnSendError( extension->id(), CreateErrorDetails("error_message_3", gcm::GCMClient::NETWORK_ERROR, total_expected_messages)); app_handler.OnSendError( extension->id(), CreateErrorDetails("error_message_4", gcm::GCMClient::UNKNOWN_ERROR, total_expected_messages)); app_handler.OnSendError( extension->id(), CreateErrorDetails("error_message_5", gcm::GCMClient::TTL_EXCEEDED, total_expected_messages)); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } IN_PROC_BROWSER_TEST_F(GcmApiTest, Incognito) { ResultCatcher catcher; catcher.RestrictToBrowserContext(profile()); ResultCatcher incognito_catcher; incognito_catcher.RestrictToBrowserContext( profile()->GetOffTheRecordProfile()); ASSERT_TRUE(RunExtensionTestIncognito("gcm/functions/incognito")); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message(); } } // namespace extensions