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
CreateErrorDetails(const std::string & message_id,const gcm::GCMClient::Result result,const std::string & total_messages)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:
GcmApiTest()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
SetUpCommandLine(CommandLine * command_line)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
SetUpOnMainThread()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
StartCollecting()97 void GcmApiTest::StartCollecting() {
98 service()->set_collect(true);
99 }
100
service() const101 gcm::FakeGCMProfileService* GcmApiTest::service() const {
102 return fake_gcm_profile_service_;
103 }
104
LoadTestExtension(const std::string & extension_path,const std::string & page_name)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,RegisterValidation)117 IN_PROC_BROWSER_TEST_F(GcmApiTest, RegisterValidation) {
118 ASSERT_TRUE(RunExtensionTest("gcm/functions/register_validation"));
119 }
120
IN_PROC_BROWSER_TEST_F(GcmApiTest,Register)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,Unregister)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,SendValidation)140 IN_PROC_BROWSER_TEST_F(GcmApiTest, SendValidation) {
141 ASSERT_TRUE(RunExtensionTest("gcm/functions/send"));
142 }
143
IN_PROC_BROWSER_TEST_F(GcmApiTest,SendMessageData)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,SendMessageDefaultTTL)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,OnMessagesDeleted)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,OnMessage)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,OnSendError)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
IN_PROC_BROWSER_TEST_F(GcmApiTest,Incognito)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