Home | History | Annotate | Download | only in gaia
      1 // Copyright (c) 2012 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 // A complete set of unit tests for GaiaOAuthClient.
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/values.h"
     12 #include "google_apis/gaia/gaia_oauth_client.h"
     13 #include "net/base/net_errors.h"
     14 #include "net/http/http_status_code.h"
     15 #include "net/url_request/test_url_fetcher_factory.h"
     16 #include "net/url_request/url_fetcher_delegate.h"
     17 #include "net/url_request/url_request_status.h"
     18 #include "net/url_request/url_request_test_util.h"
     19 #include "testing/gmock/include/gmock/gmock.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "url/gurl.h"
     22 
     23 using ::testing::_;
     24 using ::testing::Eq;
     25 using ::testing::HasSubstr;
     26 using ::testing::Pointee;
     27 using ::testing::SaveArg;
     28 
     29 namespace {
     30 
     31 // Responds as though OAuth returned from the server.
     32 class MockOAuthFetcher : public net::TestURLFetcher {
     33  public:
     34   MockOAuthFetcher(int response_code,
     35                    int max_failure_count,
     36                    bool complete_immediately,
     37                    const GURL& url,
     38                    const std::string& results,
     39                    net::URLFetcher::RequestType request_type,
     40                    net::URLFetcherDelegate* d)
     41       : net::TestURLFetcher(0, url, d),
     42         max_failure_count_(max_failure_count),
     43         current_failure_count_(0),
     44         complete_immediately_(complete_immediately) {
     45     set_url(url);
     46     set_response_code(response_code);
     47     SetResponseString(results);
     48   }
     49 
     50   virtual ~MockOAuthFetcher() { }
     51 
     52   virtual void Start() OVERRIDE {
     53     if ((GetResponseCode() != net::HTTP_OK) && (max_failure_count_ != -1) &&
     54         (current_failure_count_ == max_failure_count_)) {
     55       set_response_code(net::HTTP_OK);
     56     }
     57 
     58     net::URLRequestStatus::Status code = net::URLRequestStatus::SUCCESS;
     59     if (GetResponseCode() != net::HTTP_OK) {
     60       code = net::URLRequestStatus::FAILED;
     61       current_failure_count_++;
     62     }
     63     set_status(net::URLRequestStatus(code, 0));
     64 
     65     if (complete_immediately_)
     66       delegate()->OnURLFetchComplete(this);
     67   }
     68 
     69   void Finish() {
     70     ASSERT_FALSE(complete_immediately_);
     71     delegate()->OnURLFetchComplete(this);
     72   }
     73 
     74  private:
     75   int max_failure_count_;
     76   int current_failure_count_;
     77   bool complete_immediately_;
     78   DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcher);
     79 };
     80 
     81 class MockOAuthFetcherFactory : public net::URLFetcherFactory,
     82                                 public net::ScopedURLFetcherFactory {
     83  public:
     84   MockOAuthFetcherFactory()
     85       : net::ScopedURLFetcherFactory(this),
     86         response_code_(net::HTTP_OK),
     87         complete_immediately_(true) {
     88   }
     89   virtual ~MockOAuthFetcherFactory() {}
     90   virtual net::URLFetcher* CreateURLFetcher(
     91       int id,
     92       const GURL& url,
     93       net::URLFetcher::RequestType request_type,
     94       net::URLFetcherDelegate* d) OVERRIDE {
     95     url_fetcher_ = new MockOAuthFetcher(
     96         response_code_,
     97         max_failure_count_,
     98         complete_immediately_,
     99         url,
    100         results_,
    101         request_type,
    102         d);
    103     return url_fetcher_;
    104   }
    105   void set_response_code(int response_code) {
    106     response_code_ = response_code;
    107   }
    108   void set_max_failure_count(int count) {
    109     max_failure_count_ = count;
    110   }
    111   void set_results(const std::string& results) {
    112     results_ = results;
    113   }
    114   MockOAuthFetcher* get_url_fetcher() {
    115     return url_fetcher_;
    116   }
    117   void set_complete_immediately(bool complete_immediately) {
    118     complete_immediately_ = complete_immediately;
    119   }
    120  private:
    121   MockOAuthFetcher* url_fetcher_;
    122   int response_code_;
    123   bool complete_immediately_;
    124   int max_failure_count_;
    125   std::string results_;
    126   DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcherFactory);
    127 };
    128 
    129 const std::string kTestAccessToken = "1/fFAGRNJru1FTz70BzhT3Zg";
    130 const std::string kTestRefreshToken =
    131     "1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ";
    132 const std::string kTestUserEmail = "a_user (at) gmail.com";
    133 const std::string kTestUserId = "8675309";
    134 const int kTestExpiresIn = 3920;
    135 
    136 const std::string kDummyGetTokensResult =
    137   "{\"access_token\":\"" + kTestAccessToken + "\","
    138   "\"expires_in\":" + base::IntToString(kTestExpiresIn) + ","
    139   "\"refresh_token\":\"" + kTestRefreshToken + "\"}";
    140 
    141 const std::string kDummyRefreshTokenResult =
    142   "{\"access_token\":\"" + kTestAccessToken + "\","
    143   "\"expires_in\":" + base::IntToString(kTestExpiresIn) + "}";
    144 
    145 const std::string kDummyUserInfoResult =
    146   "{\"email\":\"" + kTestUserEmail + "\"}";
    147 
    148 const std::string kDummyUserIdResult =
    149   "{\"id\":\"" + kTestUserId + "\"}";
    150 
    151 const std::string kDummyTokenInfoResult =
    152   "{\"issued_to\": \"1234567890.apps.googleusercontent.com\","
    153   "\"audience\": \"1234567890.apps.googleusercontent.com\","
    154   "\"scope\": \"https://googleapis.com/oauth2/v2/tokeninfo\","
    155   "\"expires_in\":" + base::IntToString(kTestExpiresIn) + "}";
    156 }
    157 
    158 namespace gaia {
    159 
    160 class GaiaOAuthClientTest : public testing::Test {
    161  protected:
    162   virtual void SetUp() OVERRIDE {
    163     client_info_.client_id = "test_client_id";
    164     client_info_.client_secret = "test_client_secret";
    165     client_info_.redirect_uri = "test_redirect_uri";
    166   };
    167 
    168  protected:
    169   net::TestURLRequestContextGetter* GetRequestContext() {
    170     if (!request_context_getter_) {
    171       request_context_getter_ = new net::TestURLRequestContextGetter(
    172           message_loop_.message_loop_proxy());
    173     }
    174     return request_context_getter_;
    175   }
    176 
    177   base::MessageLoop message_loop_;
    178   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
    179   OAuthClientInfo client_info_;
    180 };
    181 
    182 class MockGaiaOAuthClientDelegate : public gaia::GaiaOAuthClient::Delegate {
    183  public:
    184   MockGaiaOAuthClientDelegate() {}
    185   ~MockGaiaOAuthClientDelegate() {}
    186 
    187   MOCK_METHOD3(OnGetTokensResponse, void(const std::string& refresh_token,
    188                                          const std::string& access_token,
    189                                          int expires_in_seconds));
    190   MOCK_METHOD2(OnRefreshTokenResponse, void(const std::string& access_token,
    191                                             int expires_in_seconds));
    192   MOCK_METHOD1(OnGetUserEmailResponse, void(const std::string& user_email));
    193   MOCK_METHOD1(OnGetUserIdResponse, void(const std::string& user_id));
    194   MOCK_METHOD0(OnOAuthError, void());
    195   MOCK_METHOD1(OnNetworkError, void(int response_code));
    196 
    197   // gMock doesn't like methods that take or return scoped_ptr.  A
    198   // work-around is to create a mock method that takes a raw ptr, and
    199   // override the problematic method to call through to it.
    200   // https://groups.google.com/a/chromium.org/d/msg/chromium-dev/01sDxsJ1OYw/I_S0xCBRF2oJ
    201   MOCK_METHOD1(OnGetTokenInfoResponsePtr,
    202                void(const base::DictionaryValue* token_info));
    203   virtual void OnGetTokenInfoResponse(
    204       scoped_ptr<base::DictionaryValue> token_info) OVERRIDE {
    205     token_info_.reset(token_info.release());
    206     OnGetTokenInfoResponsePtr(token_info_.get());
    207   }
    208 
    209  private:
    210   scoped_ptr<base::DictionaryValue> token_info_;
    211   DISALLOW_COPY_AND_ASSIGN(MockGaiaOAuthClientDelegate);
    212 };
    213 
    214 TEST_F(GaiaOAuthClientTest, NetworkFailure) {
    215   int response_code = net::HTTP_INTERNAL_SERVER_ERROR;
    216 
    217   MockGaiaOAuthClientDelegate delegate;
    218   EXPECT_CALL(delegate, OnNetworkError(response_code))
    219       .Times(1);
    220 
    221   MockOAuthFetcherFactory factory;
    222   factory.set_response_code(response_code);
    223   factory.set_max_failure_count(4);
    224 
    225   GaiaOAuthClient auth(GetRequestContext());
    226   auth.GetTokensFromAuthCode(client_info_, "auth_code", 2, &delegate);
    227 }
    228 
    229 TEST_F(GaiaOAuthClientTest, NetworkFailureRecover) {
    230   int response_code = net::HTTP_INTERNAL_SERVER_ERROR;
    231 
    232   MockGaiaOAuthClientDelegate delegate;
    233   EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken,
    234       kTestExpiresIn)).Times(1);
    235 
    236   MockOAuthFetcherFactory factory;
    237   factory.set_response_code(response_code);
    238   factory.set_max_failure_count(4);
    239   factory.set_results(kDummyGetTokensResult);
    240 
    241   GaiaOAuthClient auth(GetRequestContext());
    242   auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
    243 }
    244 
    245 TEST_F(GaiaOAuthClientTest, OAuthFailure) {
    246   int response_code = net::HTTP_BAD_REQUEST;
    247 
    248   MockGaiaOAuthClientDelegate delegate;
    249   EXPECT_CALL(delegate, OnOAuthError()).Times(1);
    250 
    251   MockOAuthFetcherFactory factory;
    252   factory.set_response_code(response_code);
    253   factory.set_max_failure_count(-1);
    254   factory.set_results(kDummyGetTokensResult);
    255 
    256   GaiaOAuthClient auth(GetRequestContext());
    257   auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
    258 }
    259 
    260 
    261 TEST_F(GaiaOAuthClientTest, GetTokensSuccess) {
    262   MockGaiaOAuthClientDelegate delegate;
    263   EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken,
    264       kTestExpiresIn)).Times(1);
    265 
    266   MockOAuthFetcherFactory factory;
    267   factory.set_results(kDummyGetTokensResult);
    268 
    269   GaiaOAuthClient auth(GetRequestContext());
    270   auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
    271 }
    272 
    273 TEST_F(GaiaOAuthClientTest, RefreshTokenSuccess) {
    274   MockGaiaOAuthClientDelegate delegate;
    275   EXPECT_CALL(delegate, OnRefreshTokenResponse(kTestAccessToken,
    276       kTestExpiresIn)).Times(1);
    277 
    278   MockOAuthFetcherFactory factory;
    279   factory.set_results(kDummyRefreshTokenResult);
    280   factory.set_complete_immediately(false);
    281 
    282   GaiaOAuthClient auth(GetRequestContext());
    283   auth.RefreshToken(client_info_, "refresh_token", std::vector<std::string>(),
    284                     -1, &delegate);
    285   EXPECT_THAT(factory.get_url_fetcher()->upload_data(),
    286               Not(HasSubstr("scope")));
    287   factory.get_url_fetcher()->Finish();
    288 }
    289 
    290 TEST_F(GaiaOAuthClientTest, RefreshTokenDownscopingSuccess) {
    291   MockGaiaOAuthClientDelegate delegate;
    292   EXPECT_CALL(delegate, OnRefreshTokenResponse(kTestAccessToken,
    293       kTestExpiresIn)).Times(1);
    294 
    295   MockOAuthFetcherFactory factory;
    296   factory.set_results(kDummyRefreshTokenResult);
    297   factory.set_complete_immediately(false);
    298 
    299   GaiaOAuthClient auth(GetRequestContext());
    300   auth.RefreshToken(client_info_, "refresh_token",
    301                     std::vector<std::string>(1, "scope4test"), -1, &delegate);
    302   EXPECT_THAT(factory.get_url_fetcher()->upload_data(),
    303               HasSubstr("&scope=scope4test"));
    304   factory.get_url_fetcher()->Finish();
    305 }
    306 
    307 
    308 TEST_F(GaiaOAuthClientTest, GetUserEmail) {
    309   MockGaiaOAuthClientDelegate delegate;
    310   EXPECT_CALL(delegate, OnGetUserEmailResponse(kTestUserEmail)).Times(1);
    311 
    312   MockOAuthFetcherFactory factory;
    313   factory.set_results(kDummyUserInfoResult);
    314 
    315   GaiaOAuthClient auth(GetRequestContext());
    316   auth.GetUserEmail("access_token", 1, &delegate);
    317 }
    318 
    319 TEST_F(GaiaOAuthClientTest, GetUserId) {
    320   MockGaiaOAuthClientDelegate delegate;
    321   EXPECT_CALL(delegate, OnGetUserIdResponse(kTestUserId)).Times(1);
    322 
    323   MockOAuthFetcherFactory factory;
    324   factory.set_results(kDummyUserIdResult);
    325 
    326   GaiaOAuthClient auth(GetRequestContext());
    327   auth.GetUserId("access_token", 1, &delegate);
    328 }
    329 
    330 TEST_F(GaiaOAuthClientTest, GetTokenInfo) {
    331   const base::DictionaryValue* captured_result;
    332 
    333   MockGaiaOAuthClientDelegate delegate;
    334   EXPECT_CALL(delegate, OnGetTokenInfoResponsePtr(_))
    335       .WillOnce(SaveArg<0>(&captured_result));
    336 
    337   MockOAuthFetcherFactory factory;
    338   factory.set_results(kDummyTokenInfoResult);
    339 
    340   GaiaOAuthClient auth(GetRequestContext());
    341   auth.GetTokenInfo("access_token", 1, &delegate);
    342 
    343   std::string issued_to;
    344   ASSERT_TRUE(captured_result->GetString("issued_to",  &issued_to));
    345   ASSERT_EQ("1234567890.apps.googleusercontent.com", issued_to);
    346 }
    347 
    348 }  // namespace gaia
    349