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/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