| OLD | NEW |
| (Empty) |
| 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 "chrome/browser/google_apis/request_sender.h" | |
| 6 | |
| 7 #include "base/strings/string_number_conversions.h" | |
| 8 #include "chrome/browser/google_apis/base_requests.h" | |
| 9 #include "chrome/browser/google_apis/dummy_auth_service.h" | |
| 10 #include "testing/gtest/include/gtest/gtest.h" | |
| 11 | |
| 12 namespace google_apis { | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 const char kTestRefreshToken[] = "valid-refresh-token"; | |
| 17 const char kTestAccessToken[] = "valid-access-token"; | |
| 18 | |
| 19 // Enum for indicating the reason why a request is finished. | |
| 20 enum FinishReason { | |
| 21 NONE, | |
| 22 SUCCESS, | |
| 23 CANCEL, | |
| 24 AUTH_FAILURE, | |
| 25 }; | |
| 26 | |
| 27 // AuthService for testing purpose. It accepts kTestRefreshToken and returns | |
| 28 // kTestAccessToken + {"1", "2", "3", ...}. | |
| 29 class TestAuthService : public DummyAuthService { | |
| 30 public: | |
| 31 TestAuthService() : auth_try_count_(0) {} | |
| 32 | |
| 33 virtual void StartAuthentication( | |
| 34 const AuthStatusCallback& callback) OVERRIDE { | |
| 35 // RequestSender should clear the rejected access token before starting | |
| 36 // to request another one. | |
| 37 EXPECT_FALSE(HasAccessToken()); | |
| 38 | |
| 39 ++auth_try_count_; | |
| 40 | |
| 41 if (refresh_token() == kTestRefreshToken) { | |
| 42 const std::string token = | |
| 43 kTestAccessToken + base::IntToString(auth_try_count_); | |
| 44 set_access_token(token); | |
| 45 callback.Run(HTTP_SUCCESS, token); | |
| 46 } else { | |
| 47 set_access_token(""); | |
| 48 callback.Run(HTTP_UNAUTHORIZED, ""); | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 private: | |
| 53 int auth_try_count_; | |
| 54 }; | |
| 55 | |
| 56 // The main test fixture class. | |
| 57 class RequestSenderTest : public testing::Test { | |
| 58 protected: | |
| 59 RequestSenderTest() | |
| 60 : auth_service_(new TestAuthService), | |
| 61 request_sender_(auth_service_, NULL, NULL, "dummy-user-agent") { | |
| 62 auth_service_->set_refresh_token(kTestRefreshToken); | |
| 63 auth_service_->set_access_token(kTestAccessToken); | |
| 64 } | |
| 65 | |
| 66 TestAuthService* auth_service_; // Owned by |request_sender_|. | |
| 67 RequestSender request_sender_; | |
| 68 }; | |
| 69 | |
| 70 // Minimal implementation for AuthenticatedRequestInterface that can interact | |
| 71 // with RequestSender correctly. | |
| 72 class TestRequest : public AuthenticatedRequestInterface { | |
| 73 public: | |
| 74 TestRequest(RequestSender* sender, | |
| 75 bool* start_called, | |
| 76 FinishReason* finish_reason) | |
| 77 : sender_(sender), | |
| 78 start_called_(start_called), | |
| 79 finish_reason_(finish_reason), | |
| 80 weak_ptr_factory_(this) { | |
| 81 } | |
| 82 | |
| 83 // Test the situation that the request has finished. | |
| 84 void FinishRequestWithSuccess() { | |
| 85 *finish_reason_ = SUCCESS; | |
| 86 sender_->RequestFinished(this); | |
| 87 } | |
| 88 | |
| 89 const std::string& passed_access_token() const { | |
| 90 return passed_access_token_; | |
| 91 } | |
| 92 | |
| 93 const ReAuthenticateCallback& passed_reauth_callback() const { | |
| 94 return passed_reauth_callback_; | |
| 95 } | |
| 96 | |
| 97 virtual void Start(const std::string& access_token, | |
| 98 const std::string& custom_user_agent, | |
| 99 const ReAuthenticateCallback& callback) OVERRIDE { | |
| 100 *start_called_ = true; | |
| 101 passed_access_token_ = access_token; | |
| 102 passed_reauth_callback_ = callback; | |
| 103 | |
| 104 // This request class itself does not return any response at this point. | |
| 105 // Each test case should respond properly by using the above methods. | |
| 106 } | |
| 107 | |
| 108 virtual void Cancel() OVERRIDE { | |
| 109 EXPECT_TRUE(*start_called_); | |
| 110 *finish_reason_ = CANCEL; | |
| 111 sender_->RequestFinished(this); | |
| 112 } | |
| 113 | |
| 114 virtual void OnAuthFailed(GDataErrorCode code) OVERRIDE { | |
| 115 *finish_reason_ = AUTH_FAILURE; | |
| 116 sender_->RequestFinished(this); | |
| 117 } | |
| 118 | |
| 119 virtual base::WeakPtr<AuthenticatedRequestInterface> GetWeakPtr() OVERRIDE { | |
| 120 return weak_ptr_factory_.GetWeakPtr(); | |
| 121 } | |
| 122 | |
| 123 private: | |
| 124 RequestSender* sender_; | |
| 125 bool* start_called_; | |
| 126 FinishReason* finish_reason_; | |
| 127 std::string passed_access_token_; | |
| 128 ReAuthenticateCallback passed_reauth_callback_; | |
| 129 base::WeakPtrFactory<TestRequest> weak_ptr_factory_; | |
| 130 }; | |
| 131 | |
| 132 } // namespace | |
| 133 | |
| 134 TEST_F(RequestSenderTest, StartAndFinishRequest) { | |
| 135 bool start_called = false; | |
| 136 FinishReason finish_reason = NONE; | |
| 137 TestRequest* request = new TestRequest(&request_sender_, | |
| 138 &start_called, | |
| 139 &finish_reason); | |
| 140 base::WeakPtr<AuthenticatedRequestInterface> weak_ptr = request->GetWeakPtr(); | |
| 141 | |
| 142 base::Closure cancel_closure = request_sender_.StartRequestWithRetry(request); | |
| 143 EXPECT_TRUE(!cancel_closure.is_null()); | |
| 144 | |
| 145 // Start is called with the specified access token. Let it succeed. | |
| 146 EXPECT_TRUE(start_called); | |
| 147 EXPECT_EQ(kTestAccessToken, request->passed_access_token()); | |
| 148 request->FinishRequestWithSuccess(); | |
| 149 EXPECT_FALSE(weak_ptr); // The request object is deleted. | |
| 150 | |
| 151 // It is safe to run the cancel closure even after the request is finished. | |
| 152 // It is just no-op. The TestRequest::Cancel method is not called. | |
| 153 cancel_closure.Run(); | |
| 154 EXPECT_EQ(SUCCESS, finish_reason); | |
| 155 } | |
| 156 | |
| 157 TEST_F(RequestSenderTest, StartAndCancelRequest) { | |
| 158 bool start_called = false; | |
| 159 FinishReason finish_reason = NONE; | |
| 160 TestRequest* request = new TestRequest(&request_sender_, | |
| 161 &start_called, | |
| 162 &finish_reason); | |
| 163 base::WeakPtr<AuthenticatedRequestInterface> weak_ptr = request->GetWeakPtr(); | |
| 164 | |
| 165 base::Closure cancel_closure = request_sender_.StartRequestWithRetry(request); | |
| 166 EXPECT_TRUE(!cancel_closure.is_null()); | |
| 167 EXPECT_TRUE(start_called); | |
| 168 | |
| 169 cancel_closure.Run(); | |
| 170 EXPECT_EQ(CANCEL, finish_reason); | |
| 171 EXPECT_FALSE(weak_ptr); // The request object is deleted. | |
| 172 } | |
| 173 | |
| 174 TEST_F(RequestSenderTest, NoRefreshToken) { | |
| 175 auth_service_->ClearRefreshToken(); | |
| 176 auth_service_->ClearAccessToken(); | |
| 177 | |
| 178 bool start_called = false; | |
| 179 FinishReason finish_reason = NONE; | |
| 180 TestRequest* request = new TestRequest(&request_sender_, | |
| 181 &start_called, | |
| 182 &finish_reason); | |
| 183 base::WeakPtr<AuthenticatedRequestInterface> weak_ptr = request->GetWeakPtr(); | |
| 184 | |
| 185 base::Closure cancel_closure = request_sender_.StartRequestWithRetry(request); | |
| 186 EXPECT_TRUE(!cancel_closure.is_null()); | |
| 187 | |
| 188 // The request is not started at all because no access token is obtained. | |
| 189 EXPECT_FALSE(start_called); | |
| 190 EXPECT_EQ(AUTH_FAILURE, finish_reason); | |
| 191 EXPECT_FALSE(weak_ptr); // The request object is deleted. | |
| 192 } | |
| 193 | |
| 194 TEST_F(RequestSenderTest, ValidRefreshTokenAndNoAccessToken) { | |
| 195 auth_service_->ClearAccessToken(); | |
| 196 | |
| 197 bool start_called = false; | |
| 198 FinishReason finish_reason = NONE; | |
| 199 TestRequest* request = new TestRequest(&request_sender_, | |
| 200 &start_called, | |
| 201 &finish_reason); | |
| 202 base::WeakPtr<AuthenticatedRequestInterface> weak_ptr = request->GetWeakPtr(); | |
| 203 | |
| 204 base::Closure cancel_closure = request_sender_.StartRequestWithRetry(request); | |
| 205 EXPECT_TRUE(!cancel_closure.is_null()); | |
| 206 | |
| 207 // Access token should indicate that this is the first retry. | |
| 208 EXPECT_TRUE(start_called); | |
| 209 EXPECT_EQ(kTestAccessToken + std::string("1"), | |
| 210 request->passed_access_token()); | |
| 211 request->FinishRequestWithSuccess(); | |
| 212 EXPECT_EQ(SUCCESS, finish_reason); | |
| 213 EXPECT_FALSE(weak_ptr); // The request object is deleted. | |
| 214 } | |
| 215 | |
| 216 TEST_F(RequestSenderTest, AccessTokenRejectedSeveralTimes) { | |
| 217 bool start_called = false; | |
| 218 FinishReason finish_reason = NONE; | |
| 219 TestRequest* request = new TestRequest(&request_sender_, | |
| 220 &start_called, | |
| 221 &finish_reason); | |
| 222 base::WeakPtr<AuthenticatedRequestInterface> weak_ptr = request->GetWeakPtr(); | |
| 223 | |
| 224 base::Closure cancel_closure = request_sender_.StartRequestWithRetry(request); | |
| 225 EXPECT_TRUE(!cancel_closure.is_null()); | |
| 226 | |
| 227 EXPECT_TRUE(start_called); | |
| 228 EXPECT_EQ(kTestAccessToken, request->passed_access_token()); | |
| 229 // Emulate the case that the access token was rejected by the remote service. | |
| 230 request->passed_reauth_callback().Run(request); | |
| 231 // New access token is fetched. Let it fail once again. | |
| 232 EXPECT_EQ(kTestAccessToken + std::string("1"), | |
| 233 request->passed_access_token()); | |
| 234 request->passed_reauth_callback().Run(request); | |
| 235 // Once more. | |
| 236 EXPECT_EQ(kTestAccessToken + std::string("2"), | |
| 237 request->passed_access_token()); | |
| 238 request->passed_reauth_callback().Run(request); | |
| 239 | |
| 240 // Currently, limit for the retry is controlled in each request object, not | |
| 241 // by the RequestSender. So with this TestRequest, RequestSender retries | |
| 242 // infinitely. Let it succeed/ | |
| 243 EXPECT_EQ(kTestAccessToken + std::string("3"), | |
| 244 request->passed_access_token()); | |
| 245 request->FinishRequestWithSuccess(); | |
| 246 EXPECT_EQ(SUCCESS, finish_reason); | |
| 247 EXPECT_FALSE(weak_ptr); | |
| 248 } | |
| 249 | |
| 250 } // namespace google_apis | |
| OLD | NEW |