Adds thunks for getting platform handles
[chromium-blink-merge.git] / google_apis / gaia / oauth2_mint_token_flow_unittest.cc
blob52b9ee10fd68715f2f0a82b9d1a89a95fd890f23
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 EXPECT_EQ(expected_body, body);
249 TEST_F(OAuth2MintTokenFlowTest, ParseMintTokenResponse) {
250 { // Access token missing.
251 scoped_ptr<base::DictionaryValue> json(
252 ParseJson(kTokenResponseNoAccessToken));
253 std::string at;
254 int ttl;
255 EXPECT_FALSE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at,
256 &ttl));
257 EXPECT_TRUE(at.empty());
259 { // All good.
260 scoped_ptr<base::DictionaryValue> json(ParseJson(kValidTokenResponse));
261 std::string at;
262 int ttl;
263 EXPECT_TRUE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at,
264 &ttl));
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));
274 IssueAdviceInfo ia;
275 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
276 json.get(), &ia));
277 EXPECT_TRUE(ia.empty());
279 { // Detail missing.
280 scoped_ptr<base::DictionaryValue> json(
281 ParseJson(kIssueAdviceResponseNoDetail));
282 IssueAdviceInfo ia;
283 EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
284 json.get(), &ia));
285 EXPECT_TRUE(ia.empty());
287 { // All good.
288 scoped_ptr<base::DictionaryValue> json(
289 ParseJson(kValidIssueAdviceResponse));
290 IssueAdviceInfo ia;
291 EXPECT_TRUE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
292 json.get(), &ia));
293 IssueAdviceInfo ia_expected(CreateIssueAdvice());
294 EXPECT_EQ(ia_expected, ia);
298 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallSuccess) {
299 { // No body.
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);
306 { // Bad json.
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);