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