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.
5 // A complete set of unit tests for OAuth2MintTokenFlow.
10 #include "base/json/json_reader.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "google_apis/gaia/google_service_auth_error.h"
15 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
16 #include "google_apis/gaia/oauth2_mint_token_flow.h"
17 #include "net/url_request/test_url_fetcher_factory.h"
18 #include "net/url_request/url_request_status.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using net::TestURLFetcher
;
23 using net::URLFetcher
;
24 using net::URLRequestStatus
;
26 using testing::StrictMock
;
30 static const char kValidTokenResponse
[] =
32 " \"token\": \"at1\","
33 " \"issueAdvice\": \"Auto\","
34 " \"expiresIn\": \"3600\""
36 static const char kTokenResponseNoAccessToken
[] =
38 " \"issueAdvice\": \"Auto\""
41 static const char kValidIssueAdviceResponse
[] =
43 " \"issueAdvice\": \"consent\","
46 " \"name\": \"Test app\","
48 " \"developerEmail\": \"munjal@chromium.org\""
52 " \"description\": \"Manage your calendars\","
53 " \"detail\": \"\nView and manage your calendars\n\""
56 " \"description\": \"Manage your documents\","
57 " \"detail\": \"\nView your documents\nUpload new documents\n\""
63 static const char kIssueAdviceResponseNoDescription
[] =
65 " \"issueAdvice\": \"consent\","
68 " \"name\": \"Test app\","
70 " \"developerEmail\": \"munjal@chromium.org\""
74 " \"description\": \"Manage your calendars\","
75 " \"detail\": \"\nView and manage your calendars\n\""
78 " \"detail\": \"\nView your documents\nUpload new documents\n\""
84 static const char kIssueAdviceResponseNoDetail
[] =
86 " \"issueAdvice\": \"consent\","
89 " \"name\": \"Test app\","
91 " \"developerEmail\": \"munjal@chromium.org\""
95 " \"description\": \"Manage your calendars\","
96 " \"detail\": \"\nView and manage your calendars\n\""
99 " \"description\": \"Manage your documents\""
105 std::vector
<std::string
> CreateTestScopes() {
106 std::vector
<std::string
> scopes
;
107 scopes
.push_back("http://scope1");
108 scopes
.push_back("http://scope2");
112 static IssueAdviceInfo
CreateIssueAdvice() {
114 IssueAdviceInfoEntry e1
;
115 e1
.description
= base::ASCIIToUTF16("Manage your calendars");
116 e1
.details
.push_back(base::ASCIIToUTF16("View and manage your calendars"));
118 IssueAdviceInfoEntry e2
;
119 e2
.description
= base::ASCIIToUTF16("Manage your documents");
120 e2
.details
.push_back(base::ASCIIToUTF16("View your documents"));
121 e2
.details
.push_back(base::ASCIIToUTF16("Upload new documents"));
126 class MockDelegate
: public OAuth2MintTokenFlow::Delegate
{
131 MOCK_METHOD2(OnMintTokenSuccess
, void(const std::string
& access_token
,
133 MOCK_METHOD1(OnIssueAdviceSuccess
,
134 void (const IssueAdviceInfo
& issue_advice
));
135 MOCK_METHOD1(OnMintTokenFailure
,
136 void(const GoogleServiceAuthError
& error
));
139 class MockMintTokenFlow
: public OAuth2MintTokenFlow
{
141 explicit MockMintTokenFlow(MockDelegate
* delegate
,
142 const OAuth2MintTokenFlow::Parameters
& parameters
)
143 : OAuth2MintTokenFlow(delegate
, parameters
) {}
144 ~MockMintTokenFlow() {}
146 MOCK_METHOD0(CreateAccessTokenFetcher
, OAuth2AccessTokenFetcher
*());
151 class OAuth2MintTokenFlowTest
: public testing::Test
{
153 OAuth2MintTokenFlowTest() {}
154 virtual ~OAuth2MintTokenFlowTest() { }
157 void CreateFlow(OAuth2MintTokenFlow::Mode mode
) {
158 return CreateFlow(&delegate_
, mode
, "");
161 void CreateFlowWithDeviceId(const std::string
& device_id
) {
162 return CreateFlow(&delegate_
, OAuth2MintTokenFlow::MODE_ISSUE_ADVICE
,
166 void CreateFlow(MockDelegate
* delegate
,
167 OAuth2MintTokenFlow::Mode mode
,
168 const std::string
& device_id
) {
169 std::string ext_id
= "ext1";
170 std::string client_id
= "client1";
171 std::vector
<std::string
> scopes(CreateTestScopes());
172 flow_
.reset(new MockMintTokenFlow(
173 delegate
, OAuth2MintTokenFlow::Parameters(ext_id
, client_id
, scopes
,
177 // Helper to parse the given string to DictionaryValue.
178 static base::DictionaryValue
* ParseJson(const std::string
& str
) {
179 scoped_ptr
<base::Value
> value(base::JSONReader::Read(str
));
180 EXPECT_TRUE(value
.get());
181 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, value
->GetType());
182 return static_cast<base::DictionaryValue
*>(value
.release());
185 scoped_ptr
<MockMintTokenFlow
> flow_
;
186 StrictMock
<MockDelegate
> delegate_
;
189 TEST_F(OAuth2MintTokenFlowTest
, CreateApiCallBody
) {
190 { // Issue advice mode.
191 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE
);
192 std::string body
= flow_
->CreateApiCallBody();
193 std::string
expected_body(
195 "&response_type=none"
196 "&scope=http://scope1+http://scope2"
199 EXPECT_EQ(expected_body
, body
);
201 { // Record grant mode.
202 CreateFlow(OAuth2MintTokenFlow::MODE_RECORD_GRANT
);
203 std::string body
= flow_
->CreateApiCallBody();
204 std::string
expected_body(
206 "&response_type=none"
207 "&scope=http://scope1+http://scope2"
210 EXPECT_EQ(expected_body
, body
);
212 { // Mint token no force mode.
213 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
);
214 std::string body
= flow_
->CreateApiCallBody();
215 std::string
expected_body(
217 "&response_type=token"
218 "&scope=http://scope1+http://scope2"
221 EXPECT_EQ(expected_body
, body
);
223 { // Mint token force mode.
224 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE
);
225 std::string body
= flow_
->CreateApiCallBody();
226 std::string
expected_body(
228 "&response_type=token"
229 "&scope=http://scope1+http://scope2"
232 EXPECT_EQ(expected_body
, body
);
234 { // Mint token with device_id.
235 CreateFlowWithDeviceId("device_id1");
236 std::string body
= flow_
->CreateApiCallBody();
237 std::string
expected_body(
239 "&response_type=none"
240 "&scope=http://scope1+http://scope2"
243 "&device_id=device_id1"
244 "&device_type=chrome");
245 EXPECT_EQ(expected_body
, body
);
249 TEST_F(OAuth2MintTokenFlowTest
, ParseMintTokenResponse
) {
250 { // Access token missing.
251 scoped_ptr
<base::DictionaryValue
> json(
252 ParseJson(kTokenResponseNoAccessToken
));
255 EXPECT_FALSE(OAuth2MintTokenFlow::ParseMintTokenResponse(json
.get(), &at
,
257 EXPECT_TRUE(at
.empty());
260 scoped_ptr
<base::DictionaryValue
> json(ParseJson(kValidTokenResponse
));
263 EXPECT_TRUE(OAuth2MintTokenFlow::ParseMintTokenResponse(json
.get(), &at
,
265 EXPECT_EQ("at1", at
);
266 EXPECT_EQ(3600, ttl
);
270 TEST_F(OAuth2MintTokenFlowTest
, ParseIssueAdviceResponse
) {
271 { // Description missing.
272 scoped_ptr
<base::DictionaryValue
> json(
273 ParseJson(kIssueAdviceResponseNoDescription
));
275 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
277 EXPECT_TRUE(ia
.empty());
280 scoped_ptr
<base::DictionaryValue
> json(
281 ParseJson(kIssueAdviceResponseNoDetail
));
283 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
285 EXPECT_TRUE(ia
.empty());
288 scoped_ptr
<base::DictionaryValue
> json(
289 ParseJson(kValidIssueAdviceResponse
));
291 EXPECT_TRUE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
293 IssueAdviceInfo
ia_expected(CreateIssueAdvice());
294 EXPECT_EQ(ia_expected
, ia
);
298 TEST_F(OAuth2MintTokenFlowTest
, ProcessApiCallSuccess
) {
300 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
301 url_fetcher
.SetResponseString(std::string());
302 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
);
303 EXPECT_CALL(delegate_
, OnMintTokenFailure(_
));
304 flow_
->ProcessApiCallSuccess(&url_fetcher
);
307 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
308 url_fetcher
.SetResponseString("foo");
309 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
);
310 EXPECT_CALL(delegate_
, OnMintTokenFailure(_
));
311 flow_
->ProcessApiCallSuccess(&url_fetcher
);
313 { // Valid json: no access token.
314 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
315 url_fetcher
.SetResponseString(kTokenResponseNoAccessToken
);
316 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
);
317 EXPECT_CALL(delegate_
, OnMintTokenFailure(_
));
318 flow_
->ProcessApiCallSuccess(&url_fetcher
);
320 { // Valid json: good token response.
321 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
322 url_fetcher
.SetResponseString(kValidTokenResponse
);
323 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
);
324 EXPECT_CALL(delegate_
, OnMintTokenSuccess("at1", 3600));
325 flow_
->ProcessApiCallSuccess(&url_fetcher
);
327 { // Valid json: no description.
328 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
329 url_fetcher
.SetResponseString(kIssueAdviceResponseNoDescription
);
330 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE
);
331 EXPECT_CALL(delegate_
, OnMintTokenFailure(_
));
332 flow_
->ProcessApiCallSuccess(&url_fetcher
);
334 { // Valid json: no detail.
335 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
336 url_fetcher
.SetResponseString(kIssueAdviceResponseNoDetail
);
337 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE
);
338 EXPECT_CALL(delegate_
, OnMintTokenFailure(_
));
339 flow_
->ProcessApiCallSuccess(&url_fetcher
);
341 { // Valid json: good issue advice response.
342 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
343 url_fetcher
.SetResponseString(kValidIssueAdviceResponse
);
344 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE
);
345 IssueAdviceInfo
ia(CreateIssueAdvice());
346 EXPECT_CALL(delegate_
, OnIssueAdviceSuccess(ia
));
347 flow_
->ProcessApiCallSuccess(&url_fetcher
);
351 TEST_F(OAuth2MintTokenFlowTest
, ProcessApiCallFailure
) {
352 { // Null delegate should work fine.
353 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
354 url_fetcher
.set_status(URLRequestStatus(URLRequestStatus::FAILED
, 101));
355 CreateFlow(NULL
, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
, "");
356 flow_
->ProcessApiCallFailure(&url_fetcher
);
359 { // Non-null delegate.
360 TestURLFetcher
url_fetcher(1, GURL("http://www.google.com"), NULL
);
361 url_fetcher
.set_status(URLRequestStatus(URLRequestStatus::FAILED
, 101));
362 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE
);
363 EXPECT_CALL(delegate_
, OnMintTokenFailure(_
));
364 flow_
->ProcessApiCallFailure(&url_fetcher
);