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 "google_apis/drive/request_sender.h" 6 7 #include "base/strings/string_number_conversions.h" 8 #include "google_apis/drive/base_requests.h" 9 #include "google_apis/drive/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 251