| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/containers/contains.h" |
| #include "base/functional/bind.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/gcm/gcm_profile_service_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "components/gcm_driver/fake_gcm_profile_service.h" |
| #include "components/sync/base/command_line_switches.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "extensions/buildflags/buildflags.h" |
| #include "extensions/test/result_catcher.h" |
| |
| static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); |
| |
| 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 { |
| protected: |
| // BrowserTestBase overrides. |
| void SetUpCommandLine(base::CommandLine* command_line) override; |
| void SetUpBrowserContextKeyedServices( |
| content::BrowserContext* context) override; |
| |
| void StartCollecting(); |
| |
| const Extension* LoadTestExtension(const std::string& extension_path, |
| const std::string& page_name); |
| gcm::FakeGCMProfileService* service(); |
| }; |
| |
| void GcmApiTest::SetUpCommandLine(base::CommandLine* command_line) { |
| // We now always create the GCMProfileService instance in |
| // SyncServiceFactory 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(syncer::kDisableSync); |
| |
| ExtensionApiTest::SetUpCommandLine(command_line); |
| } |
| |
| void GcmApiTest::SetUpBrowserContextKeyedServices( |
| content::BrowserContext* context) { |
| ExtensionApiTest::SetUpBrowserContextKeyedServices(context); |
| gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactory( |
| context, base::BindRepeating(&gcm::FakeGCMProfileService::Build)); |
| } |
| |
| void GcmApiTest::StartCollecting() { |
| service()->set_collect(true); |
| } |
| |
| gcm::FakeGCMProfileService* GcmApiTest::service() { |
| return static_cast<gcm::FakeGCMProfileService*>( |
| gcm::GCMProfileServiceFactory::GetInstance()->GetForProfile(profile())); |
| } |
| |
| 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) { |
| const GURL extension_url = extension->GetResourceURL(page_name); |
| EXPECT_TRUE(extension_url.is_valid()); |
| auto* web_contents = GetActiveWebContents(); |
| EXPECT_TRUE(NavigateToURL(web_contents, extension_url)); |
| } |
| return extension; |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| // Register and unregister are deprecated on the server. Don't test them. |
| // TODO(crbug.com/421235963): Consider deprecating on other platforms. |
| 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<std::string>& sender_ids = |
| service()->last_registered_sender_ids(); |
| EXPECT_TRUE(base::Contains(sender_ids, "Sender1")); |
| EXPECT_TRUE(base::Contains(sender_ids, "Sender2")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(GcmApiTest, Unregister) { |
| service()->AddExpectedUnregisterResponse(gcm::GCMClient::SUCCESS); |
| service()->AddExpectedUnregisterResponse(gcm::GCMClient::SERVER_ERROR); |
| |
| ASSERT_TRUE(RunExtensionTest("gcm/functions/unregister")); |
| } |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| 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::OutgoingMessage& message = service()->last_sent_message(); |
| gcm::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::OutgoingMessage& message = service()->last_sent_message(); |
| gcm::MessageData::const_iterator iter; |
| |
| EXPECT_EQ(gcm::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::IncomingMessage message; |
| message.data["property1"] = "value1"; |
| message.data["property2"] = "value2"; |
| // First message is sent without from and collapse key. |
| app_handler.OnMessage(extension->id(), message); |
| |
| // Second message is send with from. |
| message.sender_id = "12345678"; |
| app_handler.OnMessage(extension->id(), message); |
| |
| // Third message is send with a collapse key. |
| message.sender_id.clear(); |
| message.collapse_key = "collapseKeyValue"; |
| app_handler.OnMessage(extension->id(), message); |
| |
| // Fourth message carries the same data, from and collapse key. |
| message.sender_id = "12345678"; |
| 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(); |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| // Register and unregister are deprecated on the server. Don't test them. |
| // TODO(crbug.com/421235963): Consider deprecating on other platforms. |
| IN_PROC_BROWSER_TEST_F(GcmApiTest, Incognito) { |
| ResultCatcher catcher; |
| catcher.RestrictToBrowserContext(profile()); |
| ResultCatcher incognito_catcher; |
| incognito_catcher.RestrictToBrowserContext( |
| profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)); |
| |
| ASSERT_TRUE(RunExtensionTest("gcm/functions/incognito", {}, |
| {.allow_in_incognito = true})); |
| |
| EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); |
| EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message(); |
| } |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| } // namespace extensions |