Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / google_apis / gaia / oauth2_mint_token_flow_unittest.cc
blob913d55535474fc8e924fe8bcd832155aac5d54e0
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/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;
25 using testing::_;
26 using testing::StrictMock;
28 namespace {
30 static const char kValidTokenResponse[] =
31 "{"
32 " \"token\": \"at1\","
33 " \"issueAdvice\": \"Auto\","
34 " \"expiresIn\": \"3600\""
35 "}";
36 static const char kTokenResponseNoAccessToken[] =
37 "{"
38 " \"issueAdvice\": \"Auto\""
39 "}";
41 static const char kValidIssueAdviceResponse[] =
42 "{"
43 " \"issueAdvice\": \"consent\","
44 " \"consent\": {"
45 " \"oauthClient\": {"
46 " \"name\": \"Test app\","
47 " \"iconUri\": \"\","
48 " \"developerEmail\": \"munjal@chromium.org\""
49 " },"
50 " \"scopes\": ["
51 " {"
52 " \"description\": \"Manage your calendars\","
53 " \"detail\": \"\nView and manage your calendars\n\""
54 " },"
55 " {"
56 " \"description\": \"Manage your documents\","
57 " \"detail\": \"\nView your documents\nUpload new documents\n\""
58 " }"
59 " ]"
60 " }"
61 "}";
63 static const char kIssueAdviceResponseNoDescription[] =
64 "{"
65 " \"issueAdvice\": \"consent\","
66 " \"consent\": {"
67 " \"oauthClient\": {"
68 " \"name\": \"Test app\","
69 " \"iconUri\": \"\","
70 " \"developerEmail\": \"munjal@chromium.org\""
71 " },"
72 " \"scopes\": ["
73 " {"
74 " \"description\": \"Manage your calendars\","
75 " \"detail\": \"\nView and manage your calendars\n\""
76 " },"
77 " {"
78 " \"detail\": \"\nView your documents\nUpload new documents\n\""
79 " }"
80 " ]"
81 " }"
82 "}";
84 static const char kIssueAdviceResponseNoDetail[] =
85 "{"
86 " \"issueAdvice\": \"consent\","
87 " \"consent\": {"
88 " \"oauthClient\": {"
89 " \"name\": \"Test app\","
90 " \"iconUri\": \"\","
91 " \"developerEmail\": \"munjal@chromium.org\""
92 " },"
93 " \"scopes\": ["
94 " {"
95 " \"description\": \"Manage your calendars\","
96 " \"detail\": \"\nView and manage your calendars\n\""
97 " },"
98 " {"
99 " \"description\": \"Manage your documents\""
100 " }"
101 " ]"
102 " }"
103 "}";
105 std::vector<std::string> CreateTestScopes() {
106 std::vector<std::string> scopes;
107 scopes.push_back("http://scope1");
108 scopes.push_back("http://scope2");
109 return scopes;
112 static IssueAdviceInfo CreateIssueAdvice() {
113 IssueAdviceInfo ia;
114 IssueAdviceInfoEntry e1;
115 e1.description = base::ASCIIToUTF16("Manage your calendars");
116 e1.details.push_back(base::ASCIIToUTF16("View and manage your calendars"));
117 ia.push_back(e1);
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"));
122 ia.push_back(e2);
123 return ia;
126 class MockDelegate : public OAuth2MintTokenFlow::Delegate {
127 public:
128 MockDelegate() {}
129 ~MockDelegate() {}
131 MOCK_METHOD2(OnMintTokenSuccess, void(const std::string& access_token,
132 int time_to_live));
133 MOCK_METHOD1(OnIssueAdviceSuccess,
134 void (const IssueAdviceInfo& issue_advice));
135 MOCK_METHOD1(OnMintTokenFailure,
136 void(const GoogleServiceAuthError& error));
139 class MockMintTokenFlow : public OAuth2MintTokenFlow {
140 public:
141 explicit MockMintTokenFlow(MockDelegate* delegate,
142 const OAuth2MintTokenFlow::Parameters& parameters)
143 : OAuth2MintTokenFlow(delegate, parameters) {}
144 ~MockMintTokenFlow() {}
146 MOCK_METHOD0(CreateAccessTokenFetcher, OAuth2AccessTokenFetcher*());
149 } // namespace
151 class OAuth2MintTokenFlowTest : public testing::Test {
152 public:
153 OAuth2MintTokenFlowTest() {}
154 virtual ~OAuth2MintTokenFlowTest() { }
156 protected:
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,
163 device_id);
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,
174 device_id, mode)));
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(
194 "force=false"
195 "&response_type=none"
196 "&scope=http://scope1+http://scope2"
197 "&client_id=client1"
198 "&origin=ext1");
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(
205 "force=true"
206 "&response_type=none"
207 "&scope=http://scope1+http://scope2"
208 "&client_id=client1"
209 "&origin=ext1");
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(
216 "force=false"
217 "&response_type=token"
218 "&scope=http://scope1+http://scope2"
219 "&client_id=client1"
220 "&origin=ext1");
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(
227 "force=true"
228 "&response_type=token"
229 "&scope=http://scope1+http://scope2"
230 "&client_id=client1"
231 "&origin=ext1");
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(
238 "force=false"
239 "&response_type=none"
240 "&scope=http://scope1+http://scope2"
241 "&client_id=client1"
242 "&origin=ext1"
243 "&device_id=device_id1"
244 "&device_type=chrome"
245 "&lib_ver=extension");
246 EXPECT_EQ(expected_body, body);
250 TEST_F(OAuth2MintTokenFlowTest, ParseMintTokenResponse) {
251 { // Access token missing.
252 scoped_ptr<base::DictionaryValue> json(
253 ParseJson(kTokenResponseNoAccessToken));
254 std::string at;
255 int ttl;
256 EXPECT_FALSE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at,
257 &ttl));
258 EXPECT_TRUE(at.empty());
260 { // All good.
261 scoped_ptr<base::DictionaryValue> json(ParseJson(kValidTokenResponse));
262 std::string at;
263 int ttl;
264 EXPECT_TRUE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at,
265 &ttl));
266 EXPECT_EQ("at1", at);
267 EXPECT_EQ(3600, ttl);
271 TEST_F(OAuth2MintTokenFlowTest, ParseIssueAdviceResponse) {
272 { // Description missing.
273 scoped_ptr<base::DictionaryValue> json(
274 ParseJson(kIssueAdviceResponseNoDescription));
275 IssueAdviceInfo ia;
276 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
277 json.get(), &ia));
278 EXPECT_TRUE(ia.empty());
280 { // Detail missing.
281 scoped_ptr<base::DictionaryValue> json(
282 ParseJson(kIssueAdviceResponseNoDetail));
283 IssueAdviceInfo ia;
284 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
285 json.get(), &ia));
286 EXPECT_TRUE(ia.empty());
288 { // All good.
289 scoped_ptr<base::DictionaryValue> json(
290 ParseJson(kValidIssueAdviceResponse));
291 IssueAdviceInfo ia;
292 EXPECT_TRUE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
293 json.get(), &ia));
294 IssueAdviceInfo ia_expected(CreateIssueAdvice());
295 EXPECT_EQ(ia_expected, ia);
299 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallSuccess) {
300 { // No body.
301 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
302 url_fetcher.SetResponseString(std::string());
303 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
304 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
305 flow_->ProcessApiCallSuccess(&url_fetcher);
307 { // Bad json.
308 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
309 url_fetcher.SetResponseString("foo");
310 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
311 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
312 flow_->ProcessApiCallSuccess(&url_fetcher);
314 { // Valid json: no access token.
315 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
316 url_fetcher.SetResponseString(kTokenResponseNoAccessToken);
317 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
318 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
319 flow_->ProcessApiCallSuccess(&url_fetcher);
321 { // Valid json: good token response.
322 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
323 url_fetcher.SetResponseString(kValidTokenResponse);
324 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
325 EXPECT_CALL(delegate_, OnMintTokenSuccess("at1", 3600));
326 flow_->ProcessApiCallSuccess(&url_fetcher);
328 { // Valid json: no description.
329 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
330 url_fetcher.SetResponseString(kIssueAdviceResponseNoDescription);
331 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
332 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
333 flow_->ProcessApiCallSuccess(&url_fetcher);
335 { // Valid json: no detail.
336 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
337 url_fetcher.SetResponseString(kIssueAdviceResponseNoDetail);
338 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
339 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
340 flow_->ProcessApiCallSuccess(&url_fetcher);
342 { // Valid json: good issue advice response.
343 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
344 url_fetcher.SetResponseString(kValidIssueAdviceResponse);
345 CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
346 IssueAdviceInfo ia(CreateIssueAdvice());
347 EXPECT_CALL(delegate_, OnIssueAdviceSuccess(ia));
348 flow_->ProcessApiCallSuccess(&url_fetcher);
352 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallFailure) {
353 { // Null delegate should work fine.
354 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
355 url_fetcher.set_status(URLRequestStatus(URLRequestStatus::FAILED, 101));
356 CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE, "");
357 flow_->ProcessApiCallFailure(&url_fetcher);
360 { // Non-null delegate.
361 TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
362 url_fetcher.set_status(URLRequestStatus(URLRequestStatus::FAILED, 101));
363 CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
364 EXPECT_CALL(delegate_, OnMintTokenFailure(_));
365 flow_->ProcessApiCallFailure(&url_fetcher);