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.
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/values.h"
13 #include "chrome/browser/supervised_user/child_accounts/family_info_fetcher.h"
14 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
15 #include "net/base/net_errors.h"
16 #include "net/url_request/test_url_fetcher_factory.h"
17 #include "net/url_request/url_request_test_util.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 const char kAccountId
[] = "user@gmail.com";
22 const char kDifferentAccountId
[] = "some_other_user@gmail.com";
23 const int kFamilyInfoFetcherURLFetcherID
= 0;
25 bool operator==(const FamilyInfoFetcher::FamilyProfile
& family1
,
26 const FamilyInfoFetcher::FamilyProfile
& family2
) {
27 return family1
.id
== family2
.id
&&
28 family1
.name
== family2
.name
;
31 bool operator==(const FamilyInfoFetcher::FamilyMember
& account1
,
32 const FamilyInfoFetcher::FamilyMember
& account2
) {
33 return account1
.obfuscated_gaia_id
== account2
.obfuscated_gaia_id
&&
34 account1
.role
== account2
.role
&&
35 account1
.display_name
== account2
.display_name
&&
36 account1
.email
== account2
.email
&&
37 account1
.profile_url
== account2
.profile_url
&&
38 account1
.profile_image_url
== account2
.profile_image_url
;
43 std::string
BuildGetFamilyProfileResponse(
44 const FamilyInfoFetcher::FamilyProfile
& family
) {
45 base::DictionaryValue dict
;
46 base::DictionaryValue
* family_dict
= new base::DictionaryValue
;
47 family_dict
->SetStringWithoutPathExpansion("familyId", family
.id
);
48 base::DictionaryValue
* profile_dict
= new base::DictionaryValue
;
49 profile_dict
->SetStringWithoutPathExpansion("name", family
.name
);
50 family_dict
->SetWithoutPathExpansion("profile", profile_dict
);
51 dict
.SetWithoutPathExpansion("family", family_dict
);
53 base::JSONWriter::Write(dict
, &result
);
57 std::string
BuildEmptyGetFamilyProfileResponse() {
58 base::DictionaryValue dict
;
59 base::DictionaryValue
* family_dict
= new base::DictionaryValue
;
60 dict
.SetWithoutPathExpansion("family", family_dict
);
62 base::JSONWriter::Write(dict
, &result
);
66 std::string
BuildGetFamilyMembersResponse(
67 const std::vector
<FamilyInfoFetcher::FamilyMember
>& members
) {
68 base::DictionaryValue dict
;
69 base::ListValue
* list
= new base::ListValue
;
70 for (size_t i
= 0; i
< members
.size(); i
++) {
71 const FamilyInfoFetcher::FamilyMember
& member
= members
[i
];
72 base::DictionaryValue
* member_dict
= new base::DictionaryValue
;
73 member_dict
->SetStringWithoutPathExpansion("userId",
74 member
.obfuscated_gaia_id
);
75 member_dict
->SetStringWithoutPathExpansion(
76 "role", FamilyInfoFetcher::RoleToString(member
.role
));
77 if (!member
.display_name
.empty() ||
78 !member
.email
.empty() ||
79 !member
.profile_url
.empty() ||
80 !member
.profile_image_url
.empty()) {
81 base::DictionaryValue
* profile_dict
= new base::DictionaryValue
;
82 if (!member
.display_name
.empty())
83 profile_dict
->SetStringWithoutPathExpansion("displayName",
85 if (!member
.email
.empty())
86 profile_dict
->SetStringWithoutPathExpansion("email",
88 if (!member
.profile_url
.empty())
89 profile_dict
->SetStringWithoutPathExpansion("profileUrl",
91 if (!member
.profile_image_url
.empty())
92 profile_dict
->SetStringWithoutPathExpansion("profileImageUrl",
93 member
.profile_image_url
);
95 member_dict
->SetWithoutPathExpansion("profile", profile_dict
);
97 list
->Append(member_dict
);
99 dict
.SetWithoutPathExpansion("members", list
);
101 base::JSONWriter::Write(dict
, &result
);
107 class FamilyInfoFetcherTest
: public testing::Test
,
108 public FamilyInfoFetcher::Consumer
{
110 FamilyInfoFetcherTest()
111 : request_context_(new net::TestURLRequestContextGetter(
112 base::ThreadTaskRunnerHandle::Get())),
113 fetcher_(this, kAccountId
, &token_service_
, request_context_
.get()) {}
115 MOCK_METHOD1(OnGetFamilyProfileSuccess
,
116 void(const FamilyInfoFetcher::FamilyProfile
& family
));
117 MOCK_METHOD1(OnGetFamilyMembersSuccess
,
118 void(const std::vector
<FamilyInfoFetcher::FamilyMember
>&
120 MOCK_METHOD1(OnFailure
, void(FamilyInfoFetcher::ErrorCode error
));
123 void IssueRefreshToken() {
124 token_service_
.UpdateCredentials(kAccountId
, "refresh_token");
127 void IssueRefreshTokenForDifferentAccount() {
128 token_service_
.UpdateCredentials(kDifferentAccountId
, "refresh_token");
131 void IssueAccessToken() {
132 token_service_
.IssueAllTokensForAccount(
135 base::Time::Now() + base::TimeDelta::FromHours(1));
138 net::TestURLFetcher
* GetURLFetcher() {
139 net::TestURLFetcher
* url_fetcher
=
140 url_fetcher_factory_
.GetFetcherByID(
141 kFamilyInfoFetcherURLFetcherID
);
142 EXPECT_TRUE(url_fetcher
);
146 void SendResponse(net::Error error
, const std::string
& response
) {
147 net::TestURLFetcher
* url_fetcher
= GetURLFetcher();
148 url_fetcher
->set_status(net::URLRequestStatus::FromError(error
));
149 url_fetcher
->set_response_code(net::HTTP_OK
);
150 url_fetcher
->SetResponseString(response
);
151 url_fetcher
->delegate()->OnURLFetchComplete(url_fetcher
);
154 void SendValidGetFamilyProfileResponse(
155 const FamilyInfoFetcher::FamilyProfile
& family
) {
156 SendResponse(net::OK
, BuildGetFamilyProfileResponse(family
));
159 void SendValidGetFamilyMembersResponse(
160 const std::vector
<FamilyInfoFetcher::FamilyMember
>& members
) {
161 SendResponse(net::OK
, BuildGetFamilyMembersResponse(members
));
164 void SendInvalidGetFamilyProfileResponse() {
165 SendResponse(net::OK
, BuildEmptyGetFamilyProfileResponse());
168 void SendFailedResponse() {
169 SendResponse(net::ERR_ABORTED
, std::string());
172 base::MessageLoop message_loop_
;
173 FakeProfileOAuth2TokenService token_service_
;
174 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_
;
175 net::TestURLFetcherFactory url_fetcher_factory_
;
176 FamilyInfoFetcher fetcher_
;
180 TEST_F(FamilyInfoFetcherTest
, GetFamilyProfileSuccess
) {
183 fetcher_
.StartGetFamilyProfile();
185 // Since a refresh token is already available, we should immediately get a
186 // request for an access token.
187 EXPECT_EQ(1U, token_service_
.GetPendingRequests().size());
191 FamilyInfoFetcher::FamilyProfile
family("test", "My Test Family");
192 EXPECT_CALL(*this, OnGetFamilyProfileSuccess(family
));
193 SendValidGetFamilyProfileResponse(family
);
196 TEST_F(FamilyInfoFetcherTest
, GetFamilyMembersSuccess
) {
199 fetcher_
.StartGetFamilyMembers();
201 // Since a refresh token is already available, we should immediately get a
202 // request for an access token.
203 EXPECT_EQ(1U, token_service_
.GetPendingRequests().size());
207 std::vector
<FamilyInfoFetcher::FamilyMember
> members
;
209 FamilyInfoFetcher::FamilyMember("someObfuscatedGaiaId",
210 FamilyInfoFetcher::HEAD_OF_HOUSEHOLD
,
213 "http://profile.url/homer",
214 "http://profile.url/homer/image"));
216 FamilyInfoFetcher::FamilyMember("anotherObfuscatedGaiaId",
217 FamilyInfoFetcher::PARENT
,
220 "http://profile.url/marge",
223 FamilyInfoFetcher::FamilyMember("obfuscatedGaiaId3",
224 FamilyInfoFetcher::CHILD
,
228 "http://profile.url/lisa/image"));
230 FamilyInfoFetcher::FamilyMember("obfuscatedGaiaId4",
231 FamilyInfoFetcher::CHILD
,
237 FamilyInfoFetcher::FamilyMember("obfuscatedGaiaId5",
238 FamilyInfoFetcher::MEMBER
,
244 EXPECT_CALL(*this, OnGetFamilyMembersSuccess(members
));
245 SendValidGetFamilyMembersResponse(members
);
249 TEST_F(FamilyInfoFetcherTest
, SuccessAfterWaitingForRefreshToken
) {
250 fetcher_
.StartGetFamilyProfile();
252 // Since there is no refresh token yet, we should not get a request for an
253 // access token at this point.
254 EXPECT_EQ(0U, token_service_
.GetPendingRequests().size());
258 // Now there is a refresh token and we should have got a request for an
260 EXPECT_EQ(1U, token_service_
.GetPendingRequests().size());
264 FamilyInfoFetcher::FamilyProfile
family("test", "My Test Family");
265 EXPECT_CALL(*this, OnGetFamilyProfileSuccess(family
));
266 SendValidGetFamilyProfileResponse(family
);
269 TEST_F(FamilyInfoFetcherTest
, NoRefreshToken
) {
270 fetcher_
.StartGetFamilyProfile();
272 IssueRefreshTokenForDifferentAccount();
274 // Credentials for a different user should be ignored, i.e. not result in a
275 // request for an access token.
276 EXPECT_EQ(0U, token_service_
.GetPendingRequests().size());
278 // After all refresh tokens have been loaded, there is still no token for our
279 // user, so we expect a token error.
280 EXPECT_CALL(*this, OnFailure(FamilyInfoFetcher::TOKEN_ERROR
));
281 token_service_
.LoadCredentials("");
284 TEST_F(FamilyInfoFetcherTest
, GetTokenFailure
) {
287 fetcher_
.StartGetFamilyProfile();
289 // On failure to get an access token we expect a token error.
290 EXPECT_CALL(*this, OnFailure(FamilyInfoFetcher::TOKEN_ERROR
));
291 token_service_
.IssueErrorForAllPendingRequestsForAccount(
293 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
));
296 TEST_F(FamilyInfoFetcherTest
, InvalidResponse
) {
299 fetcher_
.StartGetFamilyProfile();
303 // Invalid response data should result in a service error.
304 EXPECT_CALL(*this, OnFailure(FamilyInfoFetcher::SERVICE_ERROR
));
305 SendInvalidGetFamilyProfileResponse();
308 TEST_F(FamilyInfoFetcherTest
, FailedResponse
) {
311 fetcher_
.StartGetFamilyProfile();
315 // Failed API call should result in a network error.
316 EXPECT_CALL(*this, OnFailure(FamilyInfoFetcher::NETWORK_ERROR
));
317 SendFailedResponse();