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