1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/prefs/pref_service.h" 6#include "base/run_loop.h" 7#include "chrome/browser/extensions/api/gcm/gcm_api.h" 8#include "chrome/browser/extensions/extension_apitest.h" 9#include "chrome/browser/extensions/extension_gcm_app_handler.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/services/gcm/fake_gcm_profile_service.h" 12#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" 13#include "chrome/common/chrome_switches.h" 14#include "chrome/common/pref_names.h" 15#include "chrome/test/base/ui_test_utils.h" 16#include "extensions/test/result_catcher.h" 17 18using extensions::ResultCatcher; 19 20namespace { 21 22const char kEventsExtension[] = "gcm/events"; 23 24gcm::GCMClient::SendErrorDetails CreateErrorDetails( 25 const std::string& message_id, 26 const gcm::GCMClient::Result result, 27 const std::string& total_messages) { 28 gcm::GCMClient::SendErrorDetails error; 29 error.message_id = message_id; 30 error.result = result; 31 error.additional_data["expectedMessageId"] = message_id; 32 switch (result) { 33 case gcm::GCMClient::ASYNC_OPERATION_PENDING: 34 error.additional_data["expectedErrorMessage"] = 35 "Asynchronous operation is pending."; 36 break; 37 case gcm::GCMClient::SERVER_ERROR: 38 error.additional_data["expectedErrorMessage"] = "Server error occurred."; 39 break; 40 case gcm::GCMClient::NETWORK_ERROR: 41 error.additional_data["expectedErrorMessage"] = "Network error occurred."; 42 break; 43 case gcm::GCMClient::TTL_EXCEEDED: 44 error.additional_data["expectedErrorMessage"] = "Time-to-live exceeded."; 45 break; 46 case gcm::GCMClient::UNKNOWN_ERROR: 47 default: // Default case is the same as UNKNOWN_ERROR 48 error.additional_data["expectedErrorMessage"] = "Unknown error occurred."; 49 break; 50 } 51 error.additional_data["totalMessages"] = total_messages; 52 return error; 53} 54 55} // namespace 56 57namespace extensions { 58 59class GcmApiTest : public ExtensionApiTest { 60 public: 61 GcmApiTest() : fake_gcm_profile_service_(NULL) {} 62 63 protected: 64 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE; 65 virtual void SetUpOnMainThread() OVERRIDE; 66 67 void StartCollecting(); 68 69 const Extension* LoadTestExtension(const std::string& extension_path, 70 const std::string& page_name); 71 gcm::FakeGCMProfileService* service() const; 72 73 private: 74 gcm::FakeGCMProfileService* fake_gcm_profile_service_; 75}; 76 77void GcmApiTest::SetUpCommandLine(CommandLine* command_line) { 78 // We now always create the GCMProfileService instance in 79 // ProfileSyncServiceFactory that is called when a profile is being 80 // initialized. In order to prevent it from being created, we add the switch 81 // to disable the sync logic. 82 command_line->AppendSwitch(switches::kDisableSync); 83 84 ExtensionApiTest::SetUpCommandLine(command_line); 85} 86 87void GcmApiTest::SetUpOnMainThread() { 88 // Enable GCM such that tests could be run on all channels. 89 browser()->profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true); 90 91 gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactory( 92 browser()->profile(), &gcm::FakeGCMProfileService::Build); 93 fake_gcm_profile_service_ = static_cast<gcm::FakeGCMProfileService*>( 94 gcm::GCMProfileServiceFactory::GetInstance()->GetForProfile( 95 browser()->profile())); 96 97 ExtensionApiTest::SetUpOnMainThread(); 98} 99 100void GcmApiTest::StartCollecting() { 101 service()->set_collect(true); 102} 103 104gcm::FakeGCMProfileService* GcmApiTest::service() const { 105 return fake_gcm_profile_service_; 106} 107 108const Extension* GcmApiTest::LoadTestExtension( 109 const std::string& extension_path, 110 const std::string& page_name) { 111 const Extension* extension = 112 LoadExtension(test_data_dir_.AppendASCII(extension_path)); 113 if (extension) { 114 ui_test_utils::NavigateToURL( 115 browser(), extension->GetResourceURL(page_name)); 116 } 117 return extension; 118} 119 120IN_PROC_BROWSER_TEST_F(GcmApiTest, RegisterValidation) { 121 ASSERT_TRUE(RunExtensionTest("gcm/functions/register_validation")); 122} 123 124IN_PROC_BROWSER_TEST_F(GcmApiTest, Register) { 125 StartCollecting(); 126 ASSERT_TRUE(RunExtensionTest("gcm/functions/register")); 127 128 const std::vector<std::string>& sender_ids = 129 service()->last_registered_sender_ids(); 130 EXPECT_TRUE(std::find(sender_ids.begin(), sender_ids.end(), "Sender1") != 131 sender_ids.end()); 132 EXPECT_TRUE(std::find(sender_ids.begin(), sender_ids.end(), "Sender2") != 133 sender_ids.end()); 134} 135 136IN_PROC_BROWSER_TEST_F(GcmApiTest, Unregister) { 137 service()->AddExpectedUnregisterResponse(gcm::GCMClient::SUCCESS); 138 service()->AddExpectedUnregisterResponse(gcm::GCMClient::SERVER_ERROR); 139 140 ASSERT_TRUE(RunExtensionTest("gcm/functions/unregister")); 141} 142 143IN_PROC_BROWSER_TEST_F(GcmApiTest, SendValidation) { 144 ASSERT_TRUE(RunExtensionTest("gcm/functions/send")); 145} 146 147IN_PROC_BROWSER_TEST_F(GcmApiTest, SendMessageData) { 148 StartCollecting(); 149 ASSERT_TRUE(RunExtensionTest("gcm/functions/send_message_data")); 150 151 EXPECT_EQ("destination-id", service()->last_receiver_id()); 152 const gcm::GCMClient::OutgoingMessage& message = 153 service()->last_sent_message(); 154 gcm::GCMClient::MessageData::const_iterator iter; 155 156 EXPECT_EQ(100, message.time_to_live); 157 158 EXPECT_TRUE((iter = message.data.find("key1")) != message.data.end()); 159 EXPECT_EQ("value1", iter->second); 160 161 EXPECT_TRUE((iter = message.data.find("key2")) != message.data.end()); 162 EXPECT_EQ("value2", iter->second); 163} 164 165IN_PROC_BROWSER_TEST_F(GcmApiTest, SendMessageDefaultTTL) { 166 StartCollecting(); 167 ASSERT_TRUE(RunExtensionTest("gcm/functions/send_message_default_ttl")); 168 169 EXPECT_EQ("destination-id", service()->last_receiver_id()); 170 const gcm::GCMClient::OutgoingMessage& message = 171 service()->last_sent_message(); 172 gcm::GCMClient::MessageData::const_iterator iter; 173 174 EXPECT_EQ(gcm::GCMClient::OutgoingMessage::kMaximumTTL, message.time_to_live); 175} 176 177IN_PROC_BROWSER_TEST_F(GcmApiTest, OnMessagesDeleted) { 178 ResultCatcher catcher; 179 catcher.RestrictToBrowserContext(profile()); 180 181 const extensions::Extension* extension = 182 LoadTestExtension(kEventsExtension, "on_messages_deleted.html"); 183 ASSERT_TRUE(extension); 184 185 extensions::ExtensionGCMAppHandler app_handler(profile()); 186 app_handler.OnMessagesDeleted(extension->id()); 187 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 188} 189 190IN_PROC_BROWSER_TEST_F(GcmApiTest, OnMessage) { 191 ResultCatcher catcher; 192 catcher.RestrictToBrowserContext(profile()); 193 194 const extensions::Extension* extension = 195 LoadTestExtension(kEventsExtension, "on_message.html"); 196 ASSERT_TRUE(extension); 197 198 extensions::ExtensionGCMAppHandler app_handler(profile()); 199 200 gcm::GCMClient::IncomingMessage message; 201 message.data["property1"] = "value1"; 202 message.data["property2"] = "value2"; 203 // First message is sent without a collapse key. 204 app_handler.OnMessage(extension->id(), message); 205 206 // Second message carries the same data and a collapse key. 207 message.collapse_key = "collapseKeyValue"; 208 app_handler.OnMessage(extension->id(), message); 209 210 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 211} 212 213IN_PROC_BROWSER_TEST_F(GcmApiTest, OnSendError) { 214 ResultCatcher catcher; 215 catcher.RestrictToBrowserContext(profile()); 216 217 const extensions::Extension* extension = 218 LoadTestExtension(kEventsExtension, "on_send_error.html"); 219 ASSERT_TRUE(extension); 220 221 std::string total_expected_messages = "5"; 222 extensions::ExtensionGCMAppHandler app_handler(profile()); 223 app_handler.OnSendError( 224 extension->id(), 225 CreateErrorDetails("error_message_1", 226 gcm::GCMClient::ASYNC_OPERATION_PENDING, 227 total_expected_messages)); 228 app_handler.OnSendError( 229 extension->id(), 230 CreateErrorDetails("error_message_2", 231 gcm::GCMClient::SERVER_ERROR, 232 total_expected_messages)); 233 app_handler.OnSendError( 234 extension->id(), 235 CreateErrorDetails("error_message_3", 236 gcm::GCMClient::NETWORK_ERROR, 237 total_expected_messages)); 238 app_handler.OnSendError( 239 extension->id(), 240 CreateErrorDetails("error_message_4", 241 gcm::GCMClient::UNKNOWN_ERROR, 242 total_expected_messages)); 243 app_handler.OnSendError( 244 extension->id(), 245 CreateErrorDetails("error_message_5", 246 gcm::GCMClient::TTL_EXCEEDED, 247 total_expected_messages)); 248 249 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 250} 251 252IN_PROC_BROWSER_TEST_F(GcmApiTest, Incognito) { 253 ResultCatcher catcher; 254 catcher.RestrictToBrowserContext(profile()); 255 ResultCatcher incognito_catcher; 256 incognito_catcher.RestrictToBrowserContext( 257 profile()->GetOffTheRecordProfile()); 258 259 ASSERT_TRUE(RunExtensionTestIncognito("gcm/functions/incognito")); 260 261 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 262 EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message(); 263} 264 265} // namespace extensions 266