1// Copyright 2014 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 <string>
6#include <vector>
7
8#include "base/memory/scoped_ptr.h"
9#include "base/message_loop/message_loop.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "base/strings/string_util.h"
12#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
13#include "components/signin/core/browser/account_service_flag_fetcher.h"
14#include "google_apis/gaia/gaia_urls.h"
15#include "net/url_request/test_url_fetcher_factory.h"
16#include "net/url_request/url_request_test_util.h"
17#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20const char kAccountId[] = "user@gmail.com";
21const char kDifferentAccountId[] = "some_other_user@gmail.com";
22
23const int kGaiaAuthFetcherURLFetcherID = 0;
24
25// TODO(treib): This class should really live in components/signin/ next to the
26// AccountServiceFlagFetcher, but it uses the FakePO2TS which lives in
27// chrome/browser/ (because it uses the AndroidPO2TS which depends on stuff from
28// chrome/browser/). So when the AndroidPO2TS is componentized, then this should
29// move as well.
30class AccountServiceFlagFetcherTest : public testing::Test {
31 public:
32  AccountServiceFlagFetcherTest()
33      : request_context_(new net::TestURLRequestContextGetter(
34            base::MessageLoopProxy::current())) {
35    service_flags_.push_back("some_flag");
36    service_flags_.push_back("another_flag");
37    service_flags_.push_back("andonemore");
38  }
39
40  MOCK_METHOD2(OnFlagsFetched,
41               void(AccountServiceFlagFetcher::ResultCode result,
42                    const std::vector<std::string>& flags));
43
44 protected:
45  net::TestURLFetcher* GetLoginURLFetcher() {
46    net::TestURLFetcher* fetcher =
47        url_fetcher_factory_.GetFetcherByID(kGaiaAuthFetcherURLFetcherID);
48    EXPECT_TRUE(fetcher);
49
50    EXPECT_EQ(GaiaUrls::GetInstance()->oauth1_login_url(),
51              fetcher->GetOriginalURL());
52
53    return fetcher;
54  }
55
56  net::TestURLFetcher* GetGetUserInfoURLFetcher() {
57    net::TestURLFetcher* fetcher =
58        url_fetcher_factory_.GetFetcherByID(kGaiaAuthFetcherURLFetcherID);
59    EXPECT_TRUE(fetcher);
60
61    EXPECT_EQ(GaiaUrls::GetInstance()->get_user_info_url(),
62              fetcher->GetOriginalURL());
63
64    return fetcher;
65  }
66
67  void SendValidLoginResponse() {
68    net::TestURLFetcher* fetcher = GetLoginURLFetcher();
69    fetcher->set_status(
70        net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
71    fetcher->set_response_code(net::HTTP_OK);
72    fetcher->SetResponseString(std::string("SID=sid\nLSID=lsid\nAuth=auth\n"));
73    fetcher->delegate()->OnURLFetchComplete(fetcher);
74  }
75
76  void SendFailedLoginResponse() {
77    net::TestURLFetcher* fetcher = GetLoginURLFetcher();
78    fetcher->set_status(
79        net::URLRequestStatus(net::URLRequestStatus::CANCELED, 0));
80    fetcher->set_response_code(net::HTTP_OK);
81    fetcher->SetResponseString(std::string());
82    fetcher->delegate()->OnURLFetchComplete(fetcher);
83  }
84
85  void SendValidGetUserInfoResponse() {
86    net::TestURLFetcher* fetcher = GetGetUserInfoURLFetcher();
87    fetcher->set_status(
88        net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
89    fetcher->set_response_code(net::HTTP_OK);
90    fetcher->SetResponseString(BuildGetUserInfoResponse());
91    fetcher->delegate()->OnURLFetchComplete(fetcher);
92  }
93
94  void SendInvalidGetUserInfoResponse() {
95    net::TestURLFetcher* fetcher = GetGetUserInfoURLFetcher();
96    fetcher->set_status(
97        net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
98    fetcher->set_response_code(net::HTTP_OK);
99    fetcher->SetResponseString(std::string("allServicesIsMissing=true"));
100    fetcher->delegate()->OnURLFetchComplete(fetcher);
101  }
102
103  void SendFailedGetUserInfoResponse() {
104    net::TestURLFetcher* fetcher = GetGetUserInfoURLFetcher();
105    fetcher->set_status(
106        net::URLRequestStatus(net::URLRequestStatus::CANCELED, 0));
107    fetcher->set_response_code(net::HTTP_OK);
108    fetcher->SetResponseString(std::string());
109    fetcher->delegate()->OnURLFetchComplete(fetcher);
110  }
111
112  std::string BuildGetUserInfoResponse() const {
113    return "allServices=" + JoinString(service_flags_, ',');
114  }
115
116  base::MessageLoop message_loop_;
117  FakeProfileOAuth2TokenService token_service_;
118  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
119  net::TestURLFetcherFactory url_fetcher_factory_;
120  net::ResponseCookies cookies_;
121  std::vector<std::string> service_flags_;
122};
123
124TEST_F(AccountServiceFlagFetcherTest, Success) {
125  token_service_.UpdateCredentials(kAccountId, "refresh_token");
126
127  AccountServiceFlagFetcher fetcher(
128      kAccountId,
129      &token_service_,
130      request_context_.get(),
131      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
132                 base::Unretained(this)));
133
134  // Since a refresh token is already available, we should immediately get a
135  // request for an access token.
136  EXPECT_EQ(1U, token_service_.GetPendingRequests().size());
137
138  token_service_.IssueAllTokensForAccount(
139      kAccountId,
140      "access_token",
141      base::Time::Now() + base::TimeDelta::FromHours(1));
142
143  SendValidLoginResponse();
144
145  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::SUCCESS,
146                                    service_flags_));
147  SendValidGetUserInfoResponse();
148}
149
150TEST_F(AccountServiceFlagFetcherTest, SuccessAfterWaitingForRefreshToken) {
151  AccountServiceFlagFetcher fetcher(
152      kAccountId,
153      &token_service_,
154      request_context_.get(),
155      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
156                 base::Unretained(this)));
157
158  // Since there is no refresh token yet, we should not get a request for an
159  // access token at this point.
160  EXPECT_EQ(0U, token_service_.GetPendingRequests().size());
161
162  token_service_.UpdateCredentials(kAccountId, "refresh_token");
163
164  // Now there is a refresh token and we should have got a request for an
165  // access token.
166  EXPECT_EQ(1U, token_service_.GetPendingRequests().size());
167
168  token_service_.IssueAllTokensForAccount(
169      kAccountId,
170      "access_token",
171      base::Time::Now() + base::TimeDelta::FromHours(1));
172
173  SendValidLoginResponse();
174
175  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::SUCCESS,
176                                    service_flags_));
177  SendValidGetUserInfoResponse();
178}
179
180TEST_F(AccountServiceFlagFetcherTest, NoRefreshToken) {
181  AccountServiceFlagFetcher fetcher(
182      kAccountId,
183      &token_service_,
184      request_context_.get(),
185      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
186                 base::Unretained(this)));
187
188  token_service_.UpdateCredentials(kDifferentAccountId, "refresh_token");
189
190  // Credentials for a different user should be ignored, i.e. not result in a
191  // request for an access token.
192  EXPECT_EQ(0U, token_service_.GetPendingRequests().size());
193
194  // After all refresh tokens have been loaded, there is still no token for our
195  // user, so we expect a token error.
196  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::TOKEN_ERROR,
197                                    std::vector<std::string>()));
198  token_service_.IssueAllRefreshTokensLoaded();
199}
200
201TEST_F(AccountServiceFlagFetcherTest, GetTokenFailure) {
202  token_service_.UpdateCredentials(kAccountId, "refresh_token");
203
204  AccountServiceFlagFetcher fetcher(
205      kAccountId,
206      &token_service_,
207      request_context_.get(),
208      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
209                 base::Unretained(this)));
210
211  // On failure to get an access token we expect a token error.
212  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::TOKEN_ERROR,
213                                    std::vector<std::string>()));
214  token_service_.IssueErrorForAllPendingRequestsForAccount(
215      kAccountId,
216      GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
217}
218
219TEST_F(AccountServiceFlagFetcherTest, ClientLoginFailure) {
220  token_service_.UpdateCredentials(kAccountId, "refresh_token");
221
222  AccountServiceFlagFetcher fetcher(
223      kAccountId,
224      &token_service_,
225      request_context_.get(),
226      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
227                 base::Unretained(this)));
228
229  token_service_.IssueAllTokensForAccount(
230      kAccountId,
231      "access_token",
232      base::Time::Now() + base::TimeDelta::FromHours(1));
233
234  // Login failure should result in a service error.
235  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::SERVICE_ERROR,
236                                    std::vector<std::string>()));
237  SendFailedLoginResponse();
238}
239
240TEST_F(AccountServiceFlagFetcherTest, GetUserInfoInvalidResponse) {
241  token_service_.UpdateCredentials(kAccountId, "refresh_token");
242
243  AccountServiceFlagFetcher fetcher(
244      kAccountId,
245      &token_service_,
246      request_context_.get(),
247      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
248                 base::Unretained(this)));
249
250  token_service_.IssueAllTokensForAccount(
251      kAccountId,
252      "access_token",
253      base::Time::Now() + base::TimeDelta::FromHours(1));
254
255  SendValidLoginResponse();
256
257  // Invalid response data from GetUserInfo should result in a service error.
258  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::SERVICE_ERROR,
259                                    std::vector<std::string>()));
260  SendInvalidGetUserInfoResponse();
261}
262
263TEST_F(AccountServiceFlagFetcherTest, GetUserInfoFailure) {
264  token_service_.UpdateCredentials(kAccountId, "refresh_token");
265
266  AccountServiceFlagFetcher fetcher(
267      kAccountId,
268      &token_service_,
269      request_context_.get(),
270      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
271                 base::Unretained(this)));
272
273  token_service_.IssueAllTokensForAccount(
274      kAccountId,
275      "access_token",
276      base::Time::Now() + base::TimeDelta::FromHours(1));
277
278  SendValidLoginResponse();
279
280  // Failed GetUserInfo call should result in a service error.
281  EXPECT_CALL(*this, OnFlagsFetched(AccountServiceFlagFetcher::SERVICE_ERROR,
282                                    std::vector<std::string>()));
283  SendFailedGetUserInfoResponse();
284}
285
286TEST_F(AccountServiceFlagFetcherTest, DestroyFetcher) {
287  token_service_.UpdateCredentials(kAccountId, "refresh_token");
288
289  // When the fetcher is destroyed before the request completes, OnFlagsFetched
290  // should not be called.
291  EXPECT_CALL(*this, OnFlagsFetched(testing::_, testing::_)).Times(0);
292
293  AccountServiceFlagFetcher fetcher(
294      kAccountId,
295      &token_service_,
296      request_context_.get(),
297      base::Bind(&AccountServiceFlagFetcherTest::OnFlagsFetched,
298                 base::Unretained(this)));
299
300  token_service_.IssueAllTokensForAccount(
301      kAccountId,
302      "access_token",
303      base::Time::Now() + base::TimeDelta::FromHours(1));
304
305  SendValidLoginResponse();
306  // Do not send a GetUserInfo response, but make sure the request is there.
307  GetGetUserInfoURLFetcher();
308}
309