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