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 <map> 6 #include <string> 7 #include <vector> 8 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_tokenizer.h" 11 #include "google_apis/gcm/engine/unregistration_request.h" 12 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h" 13 #include "net/url_request/test_url_fetcher_factory.h" 14 #include "net/url_request/url_request_test_util.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace gcm { 18 19 namespace { 20 const uint64 kAndroidId = 42UL; 21 const char kLoginHeader[] = "AidLogin"; 22 const char kAppId[] = "TestAppId"; 23 const char kDeletedAppId[] = "deleted=TestAppId"; 24 const char kRegistrationURL[] = "http://foo.bar/register"; 25 const uint64 kSecurityToken = 77UL; 26 27 // Backoff policy for testing registration request. 28 const net::BackoffEntry::Policy kDefaultBackoffPolicy = { 29 // Number of initial errors (in sequence) to ignore before applying 30 // exponential back-off rules. 31 // Explicitly set to 2 to skip the delay on the first retry, as we are not 32 // trying to test the backoff itself, but rather the fact that retry happens. 33 1, 34 35 // Initial delay for exponential back-off in ms. 36 15000, // 15 seconds. 37 38 // Factor by which the waiting time will be multiplied. 39 2, 40 41 // Fuzzing percentage. ex: 10% will spread requests randomly 42 // between 90%-100% of the calculated time. 43 0.5, // 50%. 44 45 // Maximum amount of time we are willing to delay our request in ms. 46 1000 * 60 * 5, // 5 minutes. 47 48 // Time to keep an entry from being discarded even when it 49 // has no significant state, -1 to never discard. 50 -1, 51 52 // Don't use initial delay unless the last request was an error. 53 false, 54 }; 55 } // namespace 56 57 class UnregistrationRequestTest : public testing::Test { 58 public: 59 UnregistrationRequestTest(); 60 virtual ~UnregistrationRequestTest(); 61 62 void UnregistrationCallback(UnregistrationRequest::Status status); 63 64 void CreateRequest(); 65 void SetResponseStatusAndString(net::HttpStatusCode status_code, 66 const std::string& response_body); 67 void CompleteFetch(); 68 69 protected: 70 bool callback_called_; 71 UnregistrationRequest::Status status_; 72 scoped_ptr<UnregistrationRequest> request_; 73 base::MessageLoop message_loop_; 74 net::TestURLFetcherFactory url_fetcher_factory_; 75 scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_; 76 FakeGCMStatsRecorder recorder_; 77 }; 78 79 UnregistrationRequestTest::UnregistrationRequestTest() 80 : callback_called_(false), 81 status_(UnregistrationRequest::UNREGISTRATION_STATUS_COUNT), 82 url_request_context_getter_(new net::TestURLRequestContextGetter( 83 message_loop_.message_loop_proxy())) {} 84 85 UnregistrationRequestTest::~UnregistrationRequestTest() {} 86 87 void UnregistrationRequestTest::UnregistrationCallback( 88 UnregistrationRequest::Status status) { 89 callback_called_ = true; 90 status_ = status; 91 } 92 93 void UnregistrationRequestTest::CreateRequest() { 94 request_.reset(new UnregistrationRequest( 95 GURL(kRegistrationURL), 96 UnregistrationRequest::RequestInfo(kAndroidId, 97 kSecurityToken, 98 kAppId), 99 kDefaultBackoffPolicy, 100 base::Bind(&UnregistrationRequestTest::UnregistrationCallback, 101 base::Unretained(this)), 102 url_request_context_getter_.get(), 103 &recorder_)); 104 } 105 106 void UnregistrationRequestTest::SetResponseStatusAndString( 107 net::HttpStatusCode status_code, 108 const std::string& response_body) { 109 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); 110 ASSERT_TRUE(fetcher); 111 fetcher->set_response_code(status_code); 112 fetcher->SetResponseString(response_body); 113 } 114 115 void UnregistrationRequestTest::CompleteFetch() { 116 status_ = UnregistrationRequest::UNREGISTRATION_STATUS_COUNT; 117 callback_called_ = false; 118 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); 119 ASSERT_TRUE(fetcher); 120 fetcher->delegate()->OnURLFetchComplete(fetcher); 121 } 122 123 TEST_F(UnregistrationRequestTest, RequestDataPassedToFetcher) { 124 CreateRequest(); 125 request_->Start(); 126 127 // Get data sent by request. 128 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); 129 ASSERT_TRUE(fetcher); 130 131 EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL()); 132 133 // Verify that authorization header was put together properly. 134 net::HttpRequestHeaders headers; 135 fetcher->GetExtraRequestHeaders(&headers); 136 std::string auth_header; 137 headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header); 138 base::StringTokenizer auth_tokenizer(auth_header, " :"); 139 ASSERT_TRUE(auth_tokenizer.GetNext()); 140 EXPECT_EQ(kLoginHeader, auth_tokenizer.token()); 141 ASSERT_TRUE(auth_tokenizer.GetNext()); 142 EXPECT_EQ(base::Uint64ToString(kAndroidId), auth_tokenizer.token()); 143 ASSERT_TRUE(auth_tokenizer.GetNext()); 144 EXPECT_EQ(base::Uint64ToString(kSecurityToken), auth_tokenizer.token()); 145 std::string app_id_header; 146 headers.GetHeader("app", &app_id_header); 147 EXPECT_EQ(kAppId, app_id_header); 148 149 std::map<std::string, std::string> expected_pairs; 150 expected_pairs["app"] = kAppId; 151 expected_pairs["device"] = base::Uint64ToString(kAndroidId); 152 expected_pairs["delete"] = "true"; 153 expected_pairs["gcm_unreg_caller"] = "false"; 154 155 // Verify data was formatted properly. 156 std::string upload_data = fetcher->upload_data(); 157 base::StringTokenizer data_tokenizer(upload_data, "&="); 158 while (data_tokenizer.GetNext()) { 159 std::map<std::string, std::string>::iterator iter = 160 expected_pairs.find(data_tokenizer.token()); 161 ASSERT_TRUE(iter != expected_pairs.end()) << data_tokenizer.token(); 162 ASSERT_TRUE(data_tokenizer.GetNext()) << data_tokenizer.token(); 163 EXPECT_EQ(iter->second, data_tokenizer.token()); 164 // Ensure that none of the keys appears twice. 165 expected_pairs.erase(iter); 166 } 167 168 EXPECT_EQ(0UL, expected_pairs.size()); 169 } 170 171 TEST_F(UnregistrationRequestTest, SuccessfulUnregistration) { 172 CreateRequest(); 173 request_->Start(); 174 175 SetResponseStatusAndString(net::HTTP_OK, kDeletedAppId); 176 CompleteFetch(); 177 178 EXPECT_TRUE(callback_called_); 179 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_); 180 } 181 182 TEST_F(UnregistrationRequestTest, ResponseHttpStatusNotOK) { 183 CreateRequest(); 184 request_->Start(); 185 186 SetResponseStatusAndString(net::HTTP_UNAUTHORIZED, ""); 187 CompleteFetch(); 188 189 EXPECT_TRUE(callback_called_); 190 EXPECT_EQ(UnregistrationRequest::HTTP_NOT_OK, status_); 191 } 192 193 TEST_F(UnregistrationRequestTest, ResponseEmpty) { 194 CreateRequest(); 195 request_->Start(); 196 197 SetResponseStatusAndString(net::HTTP_OK, ""); 198 CompleteFetch(); 199 200 EXPECT_FALSE(callback_called_); 201 202 SetResponseStatusAndString(net::HTTP_OK, kDeletedAppId); 203 CompleteFetch(); 204 205 EXPECT_TRUE(callback_called_); 206 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_); 207 } 208 209 TEST_F(UnregistrationRequestTest, InvalidParametersError) { 210 CreateRequest(); 211 request_->Start(); 212 213 SetResponseStatusAndString(net::HTTP_OK, "Error=INVALID_PARAMETERS"); 214 CompleteFetch(); 215 216 EXPECT_TRUE(callback_called_); 217 EXPECT_EQ(UnregistrationRequest::INVALID_PARAMETERS, status_); 218 } 219 220 TEST_F(UnregistrationRequestTest, UnkwnownError) { 221 CreateRequest(); 222 request_->Start(); 223 224 SetResponseStatusAndString(net::HTTP_OK, "Error=XXX"); 225 CompleteFetch(); 226 227 EXPECT_TRUE(callback_called_); 228 EXPECT_EQ(UnregistrationRequest::UNKNOWN_ERROR, status_); 229 } 230 231 TEST_F(UnregistrationRequestTest, ServiceUnavailable) { 232 CreateRequest(); 233 request_->Start(); 234 235 SetResponseStatusAndString(net::HTTP_SERVICE_UNAVAILABLE, ""); 236 CompleteFetch(); 237 238 EXPECT_FALSE(callback_called_); 239 240 SetResponseStatusAndString(net::HTTP_OK, kDeletedAppId); 241 CompleteFetch(); 242 243 EXPECT_TRUE(callback_called_); 244 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_); 245 } 246 247 TEST_F(UnregistrationRequestTest, InternalServerError) { 248 CreateRequest(); 249 request_->Start(); 250 251 SetResponseStatusAndString(net::HTTP_INTERNAL_SERVER_ERROR, ""); 252 CompleteFetch(); 253 254 EXPECT_FALSE(callback_called_); 255 256 SetResponseStatusAndString(net::HTTP_OK, kDeletedAppId); 257 CompleteFetch(); 258 259 EXPECT_TRUE(callback_called_); 260 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_); 261 } 262 263 TEST_F(UnregistrationRequestTest, IncorrectAppId) { 264 CreateRequest(); 265 request_->Start(); 266 267 SetResponseStatusAndString(net::HTTP_OK, "deleted=OtherTestAppId"); 268 CompleteFetch(); 269 270 EXPECT_FALSE(callback_called_); 271 272 SetResponseStatusAndString(net::HTTP_OK, kDeletedAppId); 273 CompleteFetch(); 274 275 EXPECT_TRUE(callback_called_); 276 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_); 277 } 278 279 TEST_F(UnregistrationRequestTest, ResponseParsingFailed) { 280 CreateRequest(); 281 request_->Start(); 282 283 SetResponseStatusAndString(net::HTTP_OK, "some malformed response"); 284 CompleteFetch(); 285 286 EXPECT_FALSE(callback_called_); 287 288 SetResponseStatusAndString(net::HTTP_OK, kDeletedAppId); 289 CompleteFetch(); 290 291 EXPECT_TRUE(callback_called_); 292 EXPECT_EQ(UnregistrationRequest::SUCCESS, status_); 293 } 294 295 } // namespace gcm 296