1 // Copyright 2014 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 <stdint.h>
6 #include <map>
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_tokenizer.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "google_apis/gcm/engine/gcm_request_test_base.h"
16 #include "google_apis/gcm/engine/gcm_unregistration_request_handler.h"
17 #include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
18 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
19 #include "net/base/load_flags.h"
20 #include "services/network/public/cpp/shared_url_loader_factory.h"
21
22 namespace gcm {
23
24 namespace {
25 const int kMaxRetries = 2;
26 const uint64_t kAndroidId = 42UL;
27 const char kLoginHeader[] = "AidLogin";
28 const char kAppId[] = "TestAppId";
29 const char kDeletedAppId[] = "deleted=TestAppId";
30 const char kDeletedToken[] = "token=SomeToken";
31 const char kProductCategoryForSubtypes[] = "com.chrome.macosx";
32 const char kRegistrationURL[] = "http://foo.bar/register";
33 const uint64_t kSecurityToken = 77UL;
34 const int kGCMVersion = 40;
35 const char kInstanceId[] = "IID1";
36 const char kDeveloperId[] = "Project1";
37 const char kScope[] = "GCM";
38
39 } // namespace
40
41 class UnregistrationRequestTest : public GCMRequestTestBase {
42 public:
43 UnregistrationRequestTest();
44 ~UnregistrationRequestTest() override;
45
46 void UnregistrationCallback(UnregistrationRequest::Status status);
47
48 void OnAboutToCompleteFetch() override;
49
max_retry_count() const50 int max_retry_count() const { return max_retry_count_; }
set_max_retry_count(int max_retry_count)51 void set_max_retry_count(int max_retry_count) {
52 max_retry_count_ = max_retry_count;
53 }
54
55 protected:
56 int max_retry_count_;
57 bool callback_called_;
58 UnregistrationRequest::Status status_;
59 std::unique_ptr<UnregistrationRequest> request_;
60 FakeGCMStatsRecorder recorder_;
61 };
62
UnregistrationRequestTest()63 UnregistrationRequestTest::UnregistrationRequestTest()
64 : max_retry_count_(kMaxRetries),
65 callback_called_(false),
66 status_(UnregistrationRequest::UNREGISTRATION_STATUS_COUNT) {}
67
~UnregistrationRequestTest()68 UnregistrationRequestTest::~UnregistrationRequestTest() {}
69
UnregistrationCallback(UnregistrationRequest::Status status)70 void UnregistrationRequestTest::UnregistrationCallback(
71 UnregistrationRequest::Status status) {
72 callback_called_ = true;
73 status_ = status;
74 }
75
OnAboutToCompleteFetch()76 void UnregistrationRequestTest::OnAboutToCompleteFetch() {
77 status_ = UnregistrationRequest::UNREGISTRATION_STATUS_COUNT;
78 callback_called_ = false;
79 }
80
81 class GCMUnregistrationRequestTest : public UnregistrationRequestTest {
82 public:
83 GCMUnregistrationRequestTest();
84 ~GCMUnregistrationRequestTest() override;
85
86 void CreateRequest();
87 };
88
GCMUnregistrationRequestTest()89 GCMUnregistrationRequestTest::GCMUnregistrationRequestTest() {
90 }
91
~GCMUnregistrationRequestTest()92 GCMUnregistrationRequestTest::~GCMUnregistrationRequestTest() {
93 }
94
CreateRequest()95 void GCMUnregistrationRequestTest::CreateRequest() {
96 UnregistrationRequest::RequestInfo request_info(kAndroidId, kSecurityToken,
97 kAppId /* category */,
98 std::string() /* subtype */);
99 std::unique_ptr<GCMUnregistrationRequestHandler> request_handler(
100 new GCMUnregistrationRequestHandler(kAppId));
101 request_.reset(new UnregistrationRequest(
102 GURL(kRegistrationURL), request_info, std::move(request_handler),
103 GetBackoffPolicy(),
104 base::BindOnce(&UnregistrationRequestTest::UnregistrationCallback,
105 base::Unretained(this)),
106 max_retry_count_, url_loader_factory(),
107 base::ThreadTaskRunnerHandle::Get(), &recorder_, std::string()));
108 }
109
TEST_F(GCMUnregistrationRequestTest,RequestDataPassedToFetcher)110 TEST_F(GCMUnregistrationRequestTest, RequestDataPassedToFetcher) {
111 CreateRequest();
112 request_->Start();
113
114 // Verify that the no-cookie flag is set.
115 const network::ResourceRequest* pending_request;
116 ASSERT_TRUE(
117 test_url_loader_factory()->IsPending(kRegistrationURL, &pending_request));
118 EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
119 pending_request->credentials_mode);
120
121 // Verify that authorization header was put together properly.
122 const net::HttpRequestHeaders* headers =
123 GetExtraHeadersForURL(kRegistrationURL);
124 ASSERT_TRUE(headers);
125 std::string auth_header;
126 headers->GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
127 base::StringTokenizer auth_tokenizer(auth_header, " :");
128 ASSERT_TRUE(auth_tokenizer.GetNext());
129 EXPECT_EQ(kLoginHeader, auth_tokenizer.token());
130 ASSERT_TRUE(auth_tokenizer.GetNext());
131 EXPECT_EQ(base::NumberToString(kAndroidId), auth_tokenizer.token());
132 ASSERT_TRUE(auth_tokenizer.GetNext());
133 EXPECT_EQ(base::NumberToString(kSecurityToken), auth_tokenizer.token());
134
135 std::map<std::string, std::string> expected_pairs;
136 expected_pairs["app"] = kAppId;
137 expected_pairs["device"] = base::NumberToString(kAndroidId);
138 expected_pairs["delete"] = "true";
139 expected_pairs["gcm_unreg_caller"] = "false";
140
141 ASSERT_NO_FATAL_FAILURE(
142 VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs));
143 }
144
TEST_F(GCMUnregistrationRequestTest,SuccessfulUnregistration)145 TEST_F(GCMUnregistrationRequestTest, SuccessfulUnregistration) {
146 set_max_retry_count(0);
147 CreateRequest();
148 request_->Start();
149
150 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
151 EXPECT_TRUE(callback_called_);
152 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
153 }
154
TEST_F(GCMUnregistrationRequestTest,ResponseHttpStatusNotOK)155 TEST_F(GCMUnregistrationRequestTest, ResponseHttpStatusNotOK) {
156 CreateRequest();
157 request_->Start();
158
159 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, "");
160 EXPECT_FALSE(callback_called_);
161
162 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
163 EXPECT_TRUE(callback_called_);
164 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
165 }
166
TEST_F(GCMUnregistrationRequestTest,ResponseEmpty)167 TEST_F(GCMUnregistrationRequestTest, ResponseEmpty) {
168 CreateRequest();
169 request_->Start();
170
171 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "");
172 EXPECT_FALSE(callback_called_);
173
174 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
175 EXPECT_TRUE(callback_called_);
176 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
177 }
178
TEST_F(GCMUnregistrationRequestTest,InvalidParametersError)179 TEST_F(GCMUnregistrationRequestTest, InvalidParametersError) {
180 CreateRequest();
181 request_->Start();
182
183 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
184 "Error=INVALID_PARAMETERS");
185 EXPECT_TRUE(callback_called_);
186 EXPECT_EQ(UnregistrationRequest::INVALID_PARAMETERS, status_);
187 }
188
TEST_F(GCMUnregistrationRequestTest,DeviceRegistrationError)189 TEST_F(GCMUnregistrationRequestTest, DeviceRegistrationError) {
190 CreateRequest();
191 request_->Start();
192
193 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
194 "Error=PHONE_REGISTRATION_ERROR");
195 EXPECT_TRUE(callback_called_);
196 EXPECT_EQ(UnregistrationRequest::DEVICE_REGISTRATION_ERROR, status_);
197 }
198
TEST_F(GCMUnregistrationRequestTest,UnkwnownError)199 TEST_F(GCMUnregistrationRequestTest, UnkwnownError) {
200 CreateRequest();
201 request_->Start();
202
203 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "Error=XXX");
204 EXPECT_TRUE(callback_called_);
205 EXPECT_EQ(UnregistrationRequest::UNKNOWN_ERROR, status_);
206 }
207
TEST_F(GCMUnregistrationRequestTest,ServiceUnavailable)208 TEST_F(GCMUnregistrationRequestTest, ServiceUnavailable) {
209 CreateRequest();
210 request_->Start();
211
212 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_SERVICE_UNAVAILABLE,
213 "");
214 EXPECT_FALSE(callback_called_);
215
216 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
217 EXPECT_TRUE(callback_called_);
218 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
219 }
220
TEST_F(GCMUnregistrationRequestTest,InternalServerError)221 TEST_F(GCMUnregistrationRequestTest, InternalServerError) {
222 CreateRequest();
223 request_->Start();
224
225 SetResponseForURLAndComplete(kRegistrationURL,
226 net::HTTP_INTERNAL_SERVER_ERROR, "");
227 EXPECT_FALSE(callback_called_);
228
229 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
230 EXPECT_TRUE(callback_called_);
231 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
232 }
233
TEST_F(GCMUnregistrationRequestTest,IncorrectAppId)234 TEST_F(GCMUnregistrationRequestTest, IncorrectAppId) {
235 CreateRequest();
236 request_->Start();
237
238 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
239 "deleted=OtherTestAppId");
240 EXPECT_FALSE(callback_called_);
241
242 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
243 EXPECT_TRUE(callback_called_);
244 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
245 }
246
TEST_F(GCMUnregistrationRequestTest,ResponseParsingFailed)247 TEST_F(GCMUnregistrationRequestTest, ResponseParsingFailed) {
248 CreateRequest();
249 request_->Start();
250
251 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
252 "some malformed response");
253 EXPECT_FALSE(callback_called_);
254
255 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
256 EXPECT_TRUE(callback_called_);
257 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
258 }
259
TEST_F(GCMUnregistrationRequestTest,MaximumAttemptsReachedWithZeroRetries)260 TEST_F(GCMUnregistrationRequestTest, MaximumAttemptsReachedWithZeroRetries) {
261 set_max_retry_count(0);
262 CreateRequest();
263 request_->Start();
264
265 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
266 "bad response");
267 EXPECT_TRUE(callback_called_);
268 EXPECT_EQ(UnregistrationRequest::REACHED_MAX_RETRIES, status_);
269 }
270
TEST_F(GCMUnregistrationRequestTest,MaximumAttemptsReached)271 TEST_F(GCMUnregistrationRequestTest, MaximumAttemptsReached) {
272 CreateRequest();
273 request_->Start();
274
275 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
276 "bad response");
277 EXPECT_FALSE(callback_called_);
278
279 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
280 "bad response");
281 EXPECT_FALSE(callback_called_);
282
283 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
284 "bad response");
285 EXPECT_TRUE(callback_called_);
286 EXPECT_EQ(UnregistrationRequest::REACHED_MAX_RETRIES, status_);
287 }
288
289 class InstaceIDDeleteTokenRequestTest : public UnregistrationRequestTest {
290 public:
291 InstaceIDDeleteTokenRequestTest();
292 ~InstaceIDDeleteTokenRequestTest() override;
293
294 void CreateRequest(bool use_subtype,
295 const std::string& instance_id,
296 const std::string& authorized_entity,
297 const std::string& scope);
298 };
299
InstaceIDDeleteTokenRequestTest()300 InstaceIDDeleteTokenRequestTest::InstaceIDDeleteTokenRequestTest() {
301 }
302
~InstaceIDDeleteTokenRequestTest()303 InstaceIDDeleteTokenRequestTest::~InstaceIDDeleteTokenRequestTest() {
304 }
305
CreateRequest(bool use_subtype,const std::string & instance_id,const std::string & authorized_entity,const std::string & scope)306 void InstaceIDDeleteTokenRequestTest::CreateRequest(
307 bool use_subtype,
308 const std::string& instance_id,
309 const std::string& authorized_entity,
310 const std::string& scope) {
311 std::string category = use_subtype ? kProductCategoryForSubtypes : kAppId;
312 std::string subtype = use_subtype ? kAppId : std::string();
313 UnregistrationRequest::RequestInfo request_info(kAndroidId, kSecurityToken,
314 category, subtype);
315 std::unique_ptr<InstanceIDDeleteTokenRequestHandler> request_handler(
316 new InstanceIDDeleteTokenRequestHandler(instance_id, authorized_entity,
317 scope, kGCMVersion));
318 request_.reset(new UnregistrationRequest(
319 GURL(kRegistrationURL), request_info, std::move(request_handler),
320 GetBackoffPolicy(),
321 base::BindOnce(&UnregistrationRequestTest::UnregistrationCallback,
322 base::Unretained(this)),
323 max_retry_count(), url_loader_factory(),
324 base::ThreadTaskRunnerHandle::Get(), &recorder_, std::string()));
325 }
326
TEST_F(InstaceIDDeleteTokenRequestTest,RequestDataPassedToFetcher)327 TEST_F(InstaceIDDeleteTokenRequestTest, RequestDataPassedToFetcher) {
328 CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
329 request_->Start();
330
331 // Verify that authorization header was put together properly.
332 const net::HttpRequestHeaders* headers =
333 GetExtraHeadersForURL(kRegistrationURL);
334 ASSERT_TRUE(headers);
335 std::string auth_header;
336 headers->GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
337 base::StringTokenizer auth_tokenizer(auth_header, " :");
338 ASSERT_TRUE(auth_tokenizer.GetNext());
339 EXPECT_EQ(kLoginHeader, auth_tokenizer.token());
340 ASSERT_TRUE(auth_tokenizer.GetNext());
341 EXPECT_EQ(base::NumberToString(kAndroidId), auth_tokenizer.token());
342 ASSERT_TRUE(auth_tokenizer.GetNext());
343 EXPECT_EQ(base::NumberToString(kSecurityToken), auth_tokenizer.token());
344
345 std::map<std::string, std::string> expected_pairs;
346 expected_pairs["gmsv"] = base::NumberToString(kGCMVersion);
347 expected_pairs["app"] = kAppId;
348 expected_pairs["device"] = base::NumberToString(kAndroidId);
349 expected_pairs["delete"] = "true";
350 expected_pairs["appid"] = kInstanceId;
351 expected_pairs["sender"] = kDeveloperId;
352 expected_pairs["scope"] = kScope;
353 expected_pairs["X-scope"] = kScope;
354
355 ASSERT_NO_FATAL_FAILURE(
356 VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs));
357 }
358
TEST_F(InstaceIDDeleteTokenRequestTest,RequestDataWithSubtype)359 TEST_F(InstaceIDDeleteTokenRequestTest, RequestDataWithSubtype) {
360 CreateRequest(true /* use_subtype */, kInstanceId, kDeveloperId, kScope);
361 request_->Start();
362
363 // Same as RequestDataPassedToFetcher except "app" and "X-subtype".
364 std::map<std::string, std::string> expected_pairs;
365 expected_pairs["gmsv"] = base::NumberToString(kGCMVersion);
366 expected_pairs["app"] = kProductCategoryForSubtypes;
367 expected_pairs["X-subtype"] = kAppId;
368 expected_pairs["device"] = base::NumberToString(kAndroidId);
369 expected_pairs["delete"] = "true";
370 expected_pairs["appid"] = kInstanceId;
371 expected_pairs["sender"] = kDeveloperId;
372 expected_pairs["scope"] = kScope;
373 expected_pairs["X-scope"] = kScope;
374
375 ASSERT_NO_FATAL_FAILURE(
376 VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs));
377 }
378
TEST_F(InstaceIDDeleteTokenRequestTest,SuccessfulUnregistration)379 TEST_F(InstaceIDDeleteTokenRequestTest, SuccessfulUnregistration) {
380 CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
381 request_->Start();
382
383 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedToken);
384 EXPECT_TRUE(callback_called_);
385 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
386 }
387
TEST_F(InstaceIDDeleteTokenRequestTest,ResponseHttpStatusNotOK)388 TEST_F(InstaceIDDeleteTokenRequestTest, ResponseHttpStatusNotOK) {
389 CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
390 request_->Start();
391
392 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, "");
393 EXPECT_FALSE(callback_called_);
394
395 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedToken);
396 EXPECT_TRUE(callback_called_);
397 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
398 }
399
TEST_F(InstaceIDDeleteTokenRequestTest,InvalidParametersError)400 TEST_F(InstaceIDDeleteTokenRequestTest, InvalidParametersError) {
401 CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
402 request_->Start();
403
404 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
405 "Error=INVALID_PARAMETERS");
406 EXPECT_TRUE(callback_called_);
407 EXPECT_EQ(UnregistrationRequest::INVALID_PARAMETERS, status_);
408 }
409
TEST_F(InstaceIDDeleteTokenRequestTest,UnkwnownError)410 TEST_F(InstaceIDDeleteTokenRequestTest, UnkwnownError) {
411 CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
412 request_->Start();
413
414 SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "Error=XXX");
415 EXPECT_TRUE(callback_called_);
416 EXPECT_EQ(UnregistrationRequest::UNKNOWN_ERROR, status_);
417 }
418
419 } // namespace gcm
420