Home | History | Annotate | Download | only in drive
      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