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 <string> 6 7 #include "google_apis/gcm/engine/checkin_request.h" 8 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h" 9 #include "google_apis/gcm/protocol/checkin.pb.h" 10 #include "net/base/backoff_entry.h" 11 #include "net/url_request/test_url_fetcher_factory.h" 12 #include "net/url_request/url_request_test_util.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace gcm { 16 17 namespace { 18 19 const net::BackoffEntry::Policy kDefaultBackoffPolicy = { 20 // Number of initial errors (in sequence) to ignore before applying 21 // exponential back-off rules. 22 // Explicitly set to 1 to skip the delay of the first Retry, as we are not 23 // trying to test the backoff itself, but rather the fact that retry happens. 24 1, 25 26 // Initial delay for exponential back-off in ms. 27 15000, // 15 seconds. 28 29 // Factor by which the waiting time will be multiplied. 30 2, 31 32 // Fuzzing percentage. ex: 10% will spread requests randomly 33 // between 90%-100% of the calculated time. 34 0.5, // 50%. 35 36 // Maximum amount of time we are willing to delay our request in ms. 37 1000 * 60 * 5, // 5 minutes. 38 39 // Time to keep an entry from being discarded even when it 40 // has no significant state, -1 to never discard. 41 -1, 42 43 // Don't use initial delay unless the last request was an error. 44 false, 45 }; 46 47 } 48 49 const uint64 kAndroidId = 42UL; 50 const uint64 kBlankAndroidId = 999999UL; 51 const uint64 kBlankSecurityToken = 999999UL; 52 const char kCheckinURL[] = "http://foo.bar/checkin"; 53 const char kChromeVersion[] = "Version String"; 54 const uint64 kSecurityToken = 77; 55 const char kSettingsDigest[] = "settings_digest"; 56 const char kEmailAddress[] = "test_user (at) gmail.com"; 57 const char kTokenValue[] = "token_value"; 58 59 class CheckinRequestTest : public testing::Test { 60 public: 61 enum ResponseScenario { 62 VALID_RESPONSE, // Both android_id and security_token set in response. 63 MISSING_ANDROID_ID, // android_id is missing. 64 MISSING_SECURITY_TOKEN, // security_token is missing. 65 ANDROID_ID_IS_ZER0, // android_id is 0. 66 SECURITY_TOKEN_IS_ZERO // security_token is 0. 67 }; 68 69 CheckinRequestTest(); 70 virtual ~CheckinRequestTest(); 71 72 void FetcherCallback( 73 const checkin_proto::AndroidCheckinResponse& response); 74 75 void CreateRequest(uint64 android_id, uint64 security_token); 76 77 void SetResponseStatusAndString( 78 net::HttpStatusCode status_code, 79 const std::string& response_data); 80 81 void CompleteFetch(); 82 83 void SetResponse(ResponseScenario response_scenario); 84 85 protected: 86 bool callback_called_; 87 uint64 android_id_; 88 uint64 security_token_; 89 int checkin_device_type_; 90 base::MessageLoop message_loop_; 91 net::TestURLFetcherFactory url_fetcher_factory_; 92 scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_; 93 checkin_proto::ChromeBuildProto chrome_build_proto_; 94 scoped_ptr<CheckinRequest> request_; 95 FakeGCMStatsRecorder recorder_; 96 }; 97 98 CheckinRequestTest::CheckinRequestTest() 99 : callback_called_(false), 100 android_id_(kBlankAndroidId), 101 security_token_(kBlankSecurityToken), 102 checkin_device_type_(0), 103 url_request_context_getter_(new net::TestURLRequestContextGetter( 104 message_loop_.message_loop_proxy())) { 105 } 106 107 CheckinRequestTest::~CheckinRequestTest() {} 108 109 void CheckinRequestTest::FetcherCallback( 110 const checkin_proto::AndroidCheckinResponse& checkin_response) { 111 callback_called_ = true; 112 if (checkin_response.has_android_id()) 113 android_id_ = checkin_response.android_id(); 114 if (checkin_response.has_security_token()) 115 security_token_ = checkin_response.security_token(); 116 } 117 118 void CheckinRequestTest::CreateRequest(uint64 android_id, 119 uint64 security_token) { 120 // First setup a chrome_build protobuf. 121 chrome_build_proto_.set_platform( 122 checkin_proto::ChromeBuildProto::PLATFORM_LINUX); 123 chrome_build_proto_.set_channel( 124 checkin_proto::ChromeBuildProto::CHANNEL_CANARY); 125 chrome_build_proto_.set_chrome_version(kChromeVersion); 126 127 std::map<std::string, std::string> account_tokens; 128 account_tokens[kEmailAddress] = kTokenValue; 129 130 CheckinRequest::RequestInfo request_info(android_id, 131 security_token, 132 account_tokens, 133 kSettingsDigest, 134 chrome_build_proto_); 135 // Then create a request with that protobuf and specified android_id, 136 // security_token. 137 request_.reset(new CheckinRequest( 138 GURL(kCheckinURL), 139 request_info, 140 kDefaultBackoffPolicy, 141 base::Bind(&CheckinRequestTest::FetcherCallback, base::Unretained(this)), 142 url_request_context_getter_.get(), 143 &recorder_)); 144 145 // Setting android_id_ and security_token_ to blank value, not used elsewhere 146 // in the tests. 147 callback_called_ = false; 148 android_id_ = kBlankAndroidId; 149 security_token_ = kBlankSecurityToken; 150 } 151 152 void CheckinRequestTest::SetResponseStatusAndString( 153 net::HttpStatusCode status_code, 154 const std::string& response_data) { 155 net::TestURLFetcher* fetcher = 156 url_fetcher_factory_.GetFetcherByID(0); 157 ASSERT_TRUE(fetcher); 158 fetcher->set_response_code(status_code); 159 fetcher->SetResponseString(response_data); 160 } 161 162 void CheckinRequestTest::CompleteFetch() { 163 net::TestURLFetcher* fetcher = 164 url_fetcher_factory_.GetFetcherByID(0); 165 ASSERT_TRUE(fetcher); 166 fetcher->delegate()->OnURLFetchComplete(fetcher); 167 } 168 169 void CheckinRequestTest::SetResponse(ResponseScenario response_scenario) { 170 checkin_proto::AndroidCheckinResponse response; 171 response.set_stats_ok(true); 172 173 uint64 android_id = response_scenario == ANDROID_ID_IS_ZER0 ? 0 : kAndroidId; 174 uint64 security_token = 175 response_scenario == SECURITY_TOKEN_IS_ZERO ? 0 : kSecurityToken; 176 177 if (response_scenario != MISSING_ANDROID_ID) 178 response.set_android_id(android_id); 179 180 if (response_scenario != MISSING_SECURITY_TOKEN) 181 response.set_security_token(security_token); 182 183 std::string response_string; 184 response.SerializeToString(&response_string); 185 SetResponseStatusAndString(net::HTTP_OK, response_string); 186 } 187 188 TEST_F(CheckinRequestTest, FetcherDataAndURL) { 189 CreateRequest(kAndroidId, kSecurityToken); 190 request_->Start(); 191 192 // Get data sent by request. 193 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); 194 ASSERT_TRUE(fetcher); 195 EXPECT_EQ(GURL(kCheckinURL), fetcher->GetOriginalURL()); 196 197 checkin_proto::AndroidCheckinRequest request_proto; 198 request_proto.ParseFromString(fetcher->upload_data()); 199 EXPECT_EQ(kAndroidId, static_cast<uint64>(request_proto.id())); 200 EXPECT_EQ(kSecurityToken, request_proto.security_token()); 201 EXPECT_EQ(chrome_build_proto_.platform(), 202 request_proto.checkin().chrome_build().platform()); 203 EXPECT_EQ(chrome_build_proto_.chrome_version(), 204 request_proto.checkin().chrome_build().chrome_version()); 205 EXPECT_EQ(chrome_build_proto_.channel(), 206 request_proto.checkin().chrome_build().channel()); 207 EXPECT_EQ(2, request_proto.account_cookie_size()); 208 EXPECT_EQ(kEmailAddress, request_proto.account_cookie(0)); 209 EXPECT_EQ(kTokenValue, request_proto.account_cookie(1)); 210 211 #if defined(CHROME_OS) 212 EXPECT_EQ(checkin_proto::DEVICE_CHROME_OS, request_proto.checkin().type()); 213 #else 214 EXPECT_EQ(checkin_proto::DEVICE_CHROME_BROWSER, 215 request_proto.checkin().type()); 216 #endif 217 218 EXPECT_EQ(kSettingsDigest, request_proto.digest()); 219 } 220 221 TEST_F(CheckinRequestTest, ResponseBodyEmpty) { 222 CreateRequest(0u, 0u); 223 request_->Start(); 224 225 SetResponseStatusAndString(net::HTTP_OK, std::string()); 226 CompleteFetch(); 227 228 EXPECT_FALSE(callback_called_); 229 230 SetResponse(VALID_RESPONSE); 231 CompleteFetch(); 232 233 EXPECT_TRUE(callback_called_); 234 EXPECT_EQ(kAndroidId, android_id_); 235 EXPECT_EQ(kSecurityToken, security_token_); 236 } 237 238 TEST_F(CheckinRequestTest, ResponseBodyCorrupted) { 239 CreateRequest(0u, 0u); 240 request_->Start(); 241 242 SetResponseStatusAndString(net::HTTP_OK, "Corrupted response body"); 243 CompleteFetch(); 244 245 EXPECT_FALSE(callback_called_); 246 247 SetResponse(VALID_RESPONSE); 248 CompleteFetch(); 249 250 EXPECT_TRUE(callback_called_); 251 EXPECT_EQ(kAndroidId, android_id_); 252 EXPECT_EQ(kSecurityToken, security_token_); 253 } 254 255 TEST_F(CheckinRequestTest, ResponseHttpStatusUnauthorized) { 256 CreateRequest(0u, 0u); 257 request_->Start(); 258 259 SetResponseStatusAndString(net::HTTP_UNAUTHORIZED, std::string()); 260 CompleteFetch(); 261 262 EXPECT_TRUE(callback_called_); 263 EXPECT_EQ(kBlankAndroidId, android_id_); 264 EXPECT_EQ(kBlankSecurityToken, security_token_); 265 } 266 267 TEST_F(CheckinRequestTest, ResponseHttpStatusBadRequest) { 268 CreateRequest(0u, 0u); 269 request_->Start(); 270 271 SetResponseStatusAndString(net::HTTP_BAD_REQUEST, std::string()); 272 CompleteFetch(); 273 274 EXPECT_TRUE(callback_called_); 275 EXPECT_EQ(kBlankAndroidId, android_id_); 276 EXPECT_EQ(kBlankSecurityToken, security_token_); 277 } 278 279 TEST_F(CheckinRequestTest, ResponseHttpStatusNotOK) { 280 CreateRequest(0u, 0u); 281 request_->Start(); 282 283 SetResponseStatusAndString(net::HTTP_INTERNAL_SERVER_ERROR, std::string()); 284 CompleteFetch(); 285 286 EXPECT_FALSE(callback_called_); 287 288 SetResponse(VALID_RESPONSE); 289 CompleteFetch(); 290 291 EXPECT_TRUE(callback_called_); 292 EXPECT_EQ(kAndroidId, android_id_); 293 EXPECT_EQ(kSecurityToken, security_token_); 294 } 295 296 TEST_F(CheckinRequestTest, ResponseMissingAndroidId) { 297 CreateRequest(0u, 0u); 298 request_->Start(); 299 300 SetResponse(MISSING_ANDROID_ID); 301 CompleteFetch(); 302 303 EXPECT_FALSE(callback_called_); 304 305 SetResponse(VALID_RESPONSE); 306 CompleteFetch(); 307 308 EXPECT_TRUE(callback_called_); 309 EXPECT_EQ(kAndroidId, android_id_); 310 EXPECT_EQ(kSecurityToken, security_token_); 311 } 312 313 TEST_F(CheckinRequestTest, ResponseMissingSecurityToken) { 314 CreateRequest(0u, 0u); 315 request_->Start(); 316 317 SetResponse(MISSING_SECURITY_TOKEN); 318 CompleteFetch(); 319 320 EXPECT_FALSE(callback_called_); 321 322 SetResponse(VALID_RESPONSE); 323 CompleteFetch(); 324 325 EXPECT_TRUE(callback_called_); 326 EXPECT_EQ(kAndroidId, android_id_); 327 EXPECT_EQ(kSecurityToken, security_token_); 328 } 329 330 TEST_F(CheckinRequestTest, AndroidIdEqualsZeroInResponse) { 331 CreateRequest(0u, 0u); 332 request_->Start(); 333 334 SetResponse(ANDROID_ID_IS_ZER0); 335 CompleteFetch(); 336 337 EXPECT_FALSE(callback_called_); 338 339 SetResponse(VALID_RESPONSE); 340 CompleteFetch(); 341 342 EXPECT_TRUE(callback_called_); 343 EXPECT_EQ(kAndroidId, android_id_); 344 EXPECT_EQ(kSecurityToken, security_token_); 345 } 346 347 TEST_F(CheckinRequestTest, SecurityTokenEqualsZeroInResponse) { 348 CreateRequest(0u, 0u); 349 request_->Start(); 350 351 SetResponse(SECURITY_TOKEN_IS_ZERO); 352 CompleteFetch(); 353 354 EXPECT_FALSE(callback_called_); 355 356 SetResponse(VALID_RESPONSE); 357 CompleteFetch(); 358 359 EXPECT_TRUE(callback_called_); 360 EXPECT_EQ(kAndroidId, android_id_); 361 EXPECT_EQ(kSecurityToken, security_token_); 362 } 363 364 TEST_F(CheckinRequestTest, SuccessfulFirstTimeCheckin) { 365 CreateRequest(0u, 0u); 366 request_->Start(); 367 368 SetResponse(VALID_RESPONSE); 369 CompleteFetch(); 370 371 EXPECT_TRUE(callback_called_); 372 EXPECT_EQ(kAndroidId, android_id_); 373 EXPECT_EQ(kSecurityToken, security_token_); 374 } 375 376 TEST_F(CheckinRequestTest, SuccessfulSubsequentCheckin) { 377 CreateRequest(kAndroidId, kSecurityToken); 378 request_->Start(); 379 380 SetResponse(VALID_RESPONSE); 381 CompleteFetch(); 382 383 EXPECT_TRUE(callback_called_); 384 EXPECT_EQ(kAndroidId, android_id_); 385 EXPECT_EQ(kSecurityToken, security_token_); 386 } 387 388 } // namespace gcm 389