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