Roll src/third_party/WebKit 6b63e20:35e1984 (svn 201060:201061)
[chromium-blink-merge.git] / google_apis / gaia / oauth2_mint_token_flow_unittest.cc
blobe9eecbca43c0c7b0b775b15e7f4a86cfcce76c7c
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 OAuth2MintTokenFlow.
7 #include <string>
8 #include <vector>
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/base/net_errors.h"
18 #include "net/url_request/test_url_fetcher_factory.h"
19 #include "net/url_request/url_request_status.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using net::TestURLFetcher;
24 using net::URLFetcher;
25 using net::URLRequestStatus;
26 using testing::_;
27 using testing::StrictMock;
29 namespace {
31 static const char kValidTokenResponse[] =
32 "{"
33 " \"token\": \"at1\","
34 " \"issueAdvice\": \"Auto\","
35 " \"expiresIn\": \"3600\""
36 "}";
37 static const char kTokenResponseNoAccessToken[] =
38 "{"
39 " \"issueAdvice\": \"Auto\""
40 "}";
42 static const char kValidIssueAdviceResponse[] =
43 "{"
44 " \"issueAdvice\": \"consent\","
45 " \"consent\": {"
46 " \"oauthClient\": {"
47 " \"name\": \"Test app\","
48 " \"iconUri\": \"\","
49 " \"developerEmail\": \"munjal@chromium.org\""
50 " },"
51 " \"scopes\": ["
52 " {"
53 " \"description\": \"Manage your calendars\","
54 " \"detail\": \"\nView and manage your calendars\n\""
55 " },"
56 " {"
57 " \"description\": \"Manage your documents\","
58 " \"detail\": \"\nView your documents\nUpload new documents\n\""
59 " }"
60 " ]"
61 " }"
62 "}";
64 static const char kIssueAdviceResponseNoDescription[] =
65 "{"
66 " \"issueAdvice\": \"consent\","
67 " \"consent\": {"
68 " \"oauthClient\": {"
69 " \"name\": \"Test app\","
70 " \"iconUri\": \"\","
71 " \"developerEmail\": \"munjal@chromium.org\""
72 " },"
73 " \"scopes\": ["
74 " {"
75 " \"description\": \"Manage your calendars\","
76 " \"detail\": \"\nView and manage your calendars\n\""
77 " },"
78 " {"
79 " \"detail\": \"\nView your documents\nUpload new documents\n\""
80 " }"
81 " ]"
82 " }"
83 "}";
85 static const char kIssueAdviceResponseNoDetail[] =
86 "{"
87 " \"issueAdvice\": \"consent\","
88 " \"consent\": {"
89 " \"oauthClient\": {"
90 " \"name\": \"Test app\","
91 " \"iconUri\": \"\","
92 " \"developerEmail\": \"munjal@chromium.org\""
93 " },"
94 " \"scopes\": ["
95 " {"
96 " \"description\": \"Manage your calendars\","
97 " \"detail\": \"\nView and manage your calendars\n\""
98 " },"
99 " {"
100 " \"description\": \"Manage your documents\""
101 " }"
102 " ]"
103 " }"
104 "}";
106 std::vector<std::string> CreateTestScopes() {
107 std::vector<std::string> scopes;
108 scopes.push_back("http://scope1");
109 scopes.push_back("http://scope2");
110 return scopes;
113 static IssueAdviceInfo CreateIssueAdvice() {
114 IssueAdviceInfo ia;
115 IssueAdviceInfoEntry e1;
116 e1.description = base::ASCIIToUTF16("Manage your calendars");
117 e1.details.push_back(base::ASCIIToUTF16("View and manage your calendars"));
118 ia.push_back(e1);
119 IssueAdviceInfoEntry e2;
120 e2.description = base::ASCIIToUTF16("Manage your documents");
121 e2.details.push_back(base::ASCIIToUTF16("View your documents"));
122 e2.details.push_back(base::ASCIIToUTF16("Upload new documents"));
123 ia.push_back(e2);
124 return ia;
127 class MockDelegate : public OAuth2MintTokenFlow::Delegate {
128 public:
129 MockDelegate() {}
130 ~MockDelegate() {}
132 MOCK_METHOD2(OnMintTokenSuccess, void(const std::string& access_token,
133 int time_to_live));
134 MOCK_METHOD1(OnIssueAdviceSuccess,
135 void (const IssueAdviceInfo& issue_advice));
136 MOCK_METHOD1(OnMintTokenFailure,
137 void(const GoogleServiceAuthError& error));
140 class MockMintTokenFlow : public OAuth2MintTokenFlow {
141 public:
142 explicit MockMintTokenFlow(MockDelegate* delegate,
143 const OAuth2MintTokenFlow::Parameters& parameters)
144 : OAuth2MintTokenFlow(delegate, parameters) {}
145 ~MockMintTokenFlow() {}
147 MOCK_METHOD0(CreateAccessTokenFetcher, OAuth2AccessTokenFetcher*());
150 } // namespace
152 class OAuth2MintTokenFlowTest : public testing::Test {
153 public:
154 OAuth2MintTokenFlowTest() {}
155 virtual ~OAuth2MintTokenFlowTest() { }
157 protected:
158 void CreateFlow(OAuth2MintTokenFlow::Mode mode) {
159 return CreateFlow(&delegate_, mode, "");
162 void CreateFlowWithDeviceId(const std::string& device_id) {
163 return CreateFlow(&delegate_, OAuth2MintTokenFlow::MODE_ISSUE_ADVICE,
164 device_id);
167 void CreateFlow(MockDelegate* delegate,
168 OAuth2MintTokenFlow::Mode mode,
169 const std::string& device_id) {
170 std::string ext_id = "ext1";
171 std::string client_id = "client1";
172 std::vector<std::string> scopes(CreateTestScopes());
173 flow_.reset(new MockMintTokenFlow(
174 delegate, OAuth2MintTokenFlow::Parameters(ext_id, client_id, scopes,
175 device_id, mode)));
178 // Helper to parse the given string to DictionaryValue.
179 static base::DictionaryValue* ParseJson(const std::string& str) {
180 scoped_ptr<base::Value> value = base::JSONReader::Read(str);
181 EXPECT_TRUE(value.get());
182 EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
183 return static_cast<base::DictionaryValue*>(value.release());
186 scoped_ptr<MockMintTokenFlow> flow_;
187 StrictMock<MockDelegate> delegate_;
190 TEST_F(OAuth2MintTokenFlowTest, CreateApiCallBody) {
191 { // Issue advice mode.
192 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
193 std::string body = flow_->CreateApiCallBody();
194 std::string expected_body(
195 "force=false"
196 "&response_type=none"
197 "&scope=http://scope1+http://scope2"
198 "&client_id=client1"
199 "&origin=ext1");
200 EXPECT_EQ(expected_body, body);
202 { // Record grant mode.
203 CreateFlow(OAuth2MintTokenFlow::MODE_RECORD_GRANT);
204 std::string body = flow_->CreateApiCallBody();
205 std::string expected_body(
206 "force=true"
207 "&response_type=none"
208 "&scope=http://scope1+http://scope2"
209 "&client_id=client1"
210 "&origin=ext1");
211 EXPECT_EQ(expected_body, body);
213 { // Mint token no force mode.
214 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
215 std::string body = flow_->CreateApiCallBody();
216 std::string expected_body(
217 "force=false"
218 "&response_type=token"
219 "&scope=http://scope1+http://scope2"
220 "&client_id=client1"
221 "&origin=ext1");
222 EXPECT_EQ(expected_body, body);
224 { // Mint token force mode.
225 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
226 std::string body = flow_->CreateApiCallBody();
227 std::string expected_body(
228 "force=true"
229 "&response_type=token"
230 "&scope=http://scope1+http://scope2"
231 "&client_id=client1"
232 "&origin=ext1");
233 EXPECT_EQ(expected_body, body);
235 { // Mint token with device_id.
236 CreateFlowWithDeviceId("device_id1");
237 std::string body = flow_->CreateApiCallBody();
238 std::string expected_body(
239 "force=false"
240 "&response_type=none"
241 "&scope=http://scope1+http://scope2"
242 "&client_id=client1"
243 "&origin=ext1"
244 "&device_id=device_id1"
245 "&device_type=chrome"
246 "&lib_ver=extension");
247 EXPECT_EQ(expected_body, body);
251 TEST_F(OAuth2MintTokenFlowTest, ParseMintTokenResponse) {
252 { // Access token missing.
253 scoped_ptr<base::DictionaryValue> json(
254 ParseJson(kTokenResponseNoAccessToken));
255 std::string at;
256 int ttl;
257 EXPECT_FALSE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at,
258 &ttl));
259 EXPECT_TRUE(at.empty());
261 { // All good.
262 scoped_ptr<base::DictionaryValue> json(ParseJson(kValidTokenResponse));
263 std::string at;
264 int ttl;
265 EXPECT_TRUE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at,
266 &ttl));
267 EXPECT_EQ("at1", at);
268 EXPECT_EQ(3600, ttl);
272 TEST_F(OAuth2MintTokenFlowTest, ParseIssueAdviceResponse) {
273 { // Description missing.
274 scoped_ptr<base::DictionaryValue> json(
275 ParseJson(kIssueAdviceResponseNoDescription));
276 IssueAdviceInfo ia;
277 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
278 json.get(), &ia));
279 EXPECT_TRUE(ia.empty());
281 { // Detail missing.
282 scoped_ptr<base::DictionaryValue> json(
283 ParseJson(kIssueAdviceResponseNoDetail));
284 IssueAdviceInfo ia;
285 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
286 json.get(), &ia));
287 EXPECT_TRUE(ia.empty());
289 { // All good.
290 scoped_ptr<base::DictionaryValue> json(
291 ParseJson(kValidIssueAdviceResponse));
292 IssueAdviceInfo ia;
293 EXPECT_TRUE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
294 json.get(), &ia));
295 IssueAdviceInfo ia_expected(CreateIssueAdvice());
296 EXPECT_EQ(ia_expected, ia);
300 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallSuccess) {
301 { // No body.
302 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
303 url_fetcher.SetResponseString(std::string());
304 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
305 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
306 flow_->ProcessApiCallSuccess(&url_fetcher);
308 { // Bad json.
309 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
310 url_fetcher.SetResponseString("foo");
311 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
312 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
313 flow_->ProcessApiCallSuccess(&url_fetcher);
315 { // Valid json: no access token.
316 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
317 url_fetcher.SetResponseString(kTokenResponseNoAccessToken);
318 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
319 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
320 flow_->ProcessApiCallSuccess(&url_fetcher);
322 { // Valid json: good token response.
323 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
324 url_fetcher.SetResponseString(kValidTokenResponse);
325 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
326 EXPECT_CALL(delegate_, OnMintTokenSuccess("at1", 3600));
327 flow_->ProcessApiCallSuccess(&url_fetcher);
329 { // Valid json: no description.
330 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
331 url_fetcher.SetResponseString(kIssueAdviceResponseNoDescription);
332 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
333 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
334 flow_->ProcessApiCallSuccess(&url_fetcher);
336 { // Valid json: no detail.
337 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
338 url_fetcher.SetResponseString(kIssueAdviceResponseNoDetail);
339 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
340 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
341 flow_->ProcessApiCallSuccess(&url_fetcher);
343 { // Valid json: good issue advice response.
344 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
345 url_fetcher.SetResponseString(kValidIssueAdviceResponse);
346 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
347 IssueAdviceInfo ia(CreateIssueAdvice());
348 EXPECT_CALL(delegate_, OnIssueAdviceSuccess(ia));
349 flow_->ProcessApiCallSuccess(&url_fetcher);
353 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallFailure) {
354 { // Null delegate should work fine.
355 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
356 url_fetcher.set_status(URLRequestStatus::FromError(net::ERR_FAILED));
357 CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE, "");
358 flow_->ProcessApiCallFailure(&url_fetcher);
361 { // Non-null delegate.
362 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
363 url_fetcher.set_status(URLRequestStatus::FromError(net::ERR_FAILED));
364 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
365 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
366 flow_->ProcessApiCallFailure(&url_fetcher);