| Index: chrome/common/net/gaia/oauth2_mint_token_flow_unittest.cc
|
| ===================================================================
|
| --- chrome/common/net/gaia/oauth2_mint_token_flow_unittest.cc (revision 130985)
|
| +++ chrome/common/net/gaia/oauth2_mint_token_flow_unittest.cc (working copy)
|
| @@ -7,189 +7,351 @@
|
| #include <string>
|
| #include <vector>
|
|
|
| +#include "base/json/json_reader.h"
|
| #include "base/memory/scoped_ptr.h"
|
| -#include "chrome/common/net/gaia/gaia_urls.h"
|
| +#include "base/values.h"
|
| #include "chrome/common/net/gaia/google_service_auth_error.h"
|
| -#include "chrome/common/net/gaia/oauth2_access_token_consumer.h"
|
| -#include "chrome/common/net/gaia/oauth2_access_token_fetcher.h"
|
| -#include "chrome/common/net/gaia/oauth2_mint_token_consumer.h"
|
| -#include "chrome/common/net/gaia/oauth2_mint_token_fetcher.h"
|
| #include "chrome/common/net/gaia/oauth2_mint_token_flow.h"
|
| +#include "content/test/test_url_fetcher_factory.h"
|
| +#include "net/url_request/url_request_status.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| +using content::URLFetcher;
|
| +using net::URLRequestStatus;
|
| using testing::_;
|
| -using testing::Return;
|
| +using testing::StrictMock;
|
|
|
| namespace {
|
| +
|
| +static const char kValidTokenResponse[] =
|
| + "{"
|
| + " \"token\": \"at1\","
|
| + " \"issueAdvice\": \"Auto\""
|
| + "}";
|
| +static const char kTokenResponseNoAccessToken[] =
|
| + "{"
|
| + " \"issueAdvice\": \"Auto\""
|
| + "}";
|
| +
|
| +static const char kValidIssueAdviceResponse[] =
|
| + "{"
|
| + " \"issueAdvice\": \"consent\","
|
| + " \"consent\": {"
|
| + " \"oauthClient\": {"
|
| + " \"name\": \"Test app\","
|
| + " \"iconUri\": \"\","
|
| + " \"developerEmail\": \"munjal@chromium.org\""
|
| + " },"
|
| + " \"scopes\": ["
|
| + " {"
|
| + " \"description\": \"Manage your calendars\","
|
| + " \"detail\": \"\nView and manage your calendars\n\""
|
| + " },"
|
| + " {"
|
| + " \"description\": \"Manage your documents\","
|
| + " \"detail\": \"\nView your documents\nUpload new documents\n\""
|
| + " }"
|
| + " ]"
|
| + " }"
|
| + "}";
|
| +
|
| +static const char kIssueAdviceResponseNoDescription[] =
|
| + "{"
|
| + " \"issueAdvice\": \"consent\","
|
| + " \"consent\": {"
|
| + " \"oauthClient\": {"
|
| + " \"name\": \"Test app\","
|
| + " \"iconUri\": \"\","
|
| + " \"developerEmail\": \"munjal@chromium.org\""
|
| + " },"
|
| + " \"scopes\": ["
|
| + " {"
|
| + " \"description\": \"Manage your calendars\","
|
| + " \"detail\": \"\nView and manage your calendars\n\""
|
| + " },"
|
| + " {"
|
| + " \"detail\": \"\nView your documents\nUpload new documents\n\""
|
| + " }"
|
| + " ]"
|
| + " }"
|
| + "}";
|
| +
|
| +static const char kIssueAdviceResponseNoDetail[] =
|
| + "{"
|
| + " \"issueAdvice\": \"consent\","
|
| + " \"consent\": {"
|
| + " \"oauthClient\": {"
|
| + " \"name\": \"Test app\","
|
| + " \"iconUri\": \"\","
|
| + " \"developerEmail\": \"munjal@chromium.org\""
|
| + " },"
|
| + " \"scopes\": ["
|
| + " {"
|
| + " \"description\": \"Manage your calendars\","
|
| + " \"detail\": \"\nView and manage your calendars\n\""
|
| + " },"
|
| + " {"
|
| + " \"description\": \"Manage your documents\""
|
| + " }"
|
| + " ]"
|
| + " }"
|
| + "}";
|
| +
|
| std::vector<std::string> CreateTestScopes() {
|
| std::vector<std::string> scopes;
|
| - scopes.push_back("scope1");
|
| - scopes.push_back("scope2");
|
| + scopes.push_back("http://scope1");
|
| + scopes.push_back("http://scope2");
|
| return scopes;
|
| }
|
| +
|
| +static IssueAdviceInfo CreateIssueAdvice() {
|
| + IssueAdviceInfo ia;
|
| + IssueAdviceInfoEntry e1;
|
| + e1.description = "Manage your calendars";
|
| + e1.details.push_back("View and manage your calendars");
|
| + ia.push_back(e1);
|
| + IssueAdviceInfoEntry e2;
|
| + e2.description = "Manage your documents";
|
| + e2.details.push_back("View your documents");
|
| + e2.details.push_back("Upload new documents");
|
| + ia.push_back(e2);
|
| + return ia;
|
| }
|
|
|
| +} // namespace
|
| +
|
| class MockDelegate : public OAuth2MintTokenFlow::Delegate {
|
| public:
|
| MockDelegate() {}
|
| ~MockDelegate() {}
|
|
|
| MOCK_METHOD1(OnMintTokenSuccess, void(const std::string& access_token));
|
| + MOCK_METHOD1(OnIssueAdviceSuccess,
|
| + void (const IssueAdviceInfo& issue_advice));
|
| MOCK_METHOD1(OnMintTokenFailure,
|
| void(const GoogleServiceAuthError& error));
|
| };
|
|
|
| -class MockOAuth2AccessTokenFetcher : public OAuth2AccessTokenFetcher {
|
| +class MockMintTokenFlow : public OAuth2MintTokenFlow {
|
| public:
|
| - MockOAuth2AccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
|
| - net::URLRequestContextGetter* getter)
|
| - : OAuth2AccessTokenFetcher(consumer, getter) {}
|
| - ~MockOAuth2AccessTokenFetcher() {}
|
| + explicit MockMintTokenFlow(MockDelegate* delegate,
|
| + const OAuth2MintTokenFlow::Parameters& parameters )
|
| + : OAuth2MintTokenFlow(NULL, delegate, parameters) {}
|
| + ~MockMintTokenFlow() {}
|
|
|
| - MOCK_METHOD4(Start,
|
| - void (const std::string& client_id,
|
| - const std::string& client_secret,
|
| - const std::string& refresh_token,
|
| - const std::vector<std::string>& scopes));
|
| -};
|
| -
|
| -class MockOAuth2MintTokenFetcher : public OAuth2MintTokenFetcher {
|
| - public:
|
| - MockOAuth2MintTokenFetcher(OAuth2MintTokenConsumer* consumer,
|
| - net::URLRequestContextGetter* getter)
|
| - : OAuth2MintTokenFetcher(consumer, getter, "test") {}
|
| - ~MockOAuth2MintTokenFetcher() {}
|
| -
|
| - MOCK_METHOD4(Start,
|
| - void (const std::string& oauth_login_access_token,
|
| - const std::string& client_id,
|
| - const std::vector<std::string>& scopes,
|
| - const std::string& origin));
|
| -};
|
| -
|
| -class MockOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
|
| - public:
|
| - explicit MockOAuth2MintTokenFlow(MockDelegate* delegate)
|
| - : OAuth2MintTokenFlow(NULL, delegate) {}
|
| - ~MockOAuth2MintTokenFlow() {}
|
| -
|
| MOCK_METHOD0(CreateAccessTokenFetcher, OAuth2AccessTokenFetcher*());
|
| MOCK_METHOD0(CreateMintTokenFetcher, OAuth2MintTokenFetcher*());
|
| };
|
|
|
| class OAuth2MintTokenFlowTest : public testing::Test {
|
| public:
|
| - OAuth2MintTokenFlowTest() {
|
| - flow_.reset(new MockOAuth2MintTokenFlow(&delegate_));
|
| - access_token_fetcher_.reset(new MockOAuth2AccessTokenFetcher(
|
| - flow_.get(), NULL));
|
| - mint_token_fetcher_.reset(new MockOAuth2MintTokenFetcher(
|
| - flow_.get(), NULL));
|
| - }
|
| -
|
| + OAuth2MintTokenFlowTest() {}
|
| virtual ~OAuth2MintTokenFlowTest() { }
|
|
|
| protected:
|
| - void SetAccessTokenFetcherFailure(const std::string& rt,
|
| - const GoogleServiceAuthError& error) {
|
| - EXPECT_CALL(*access_token_fetcher_,
|
| - Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
|
| - GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
|
| - rt, std::vector<std::string>()))
|
| - .Times(1);
|
| - EXPECT_CALL(*flow_, CreateAccessTokenFetcher())
|
| - .WillOnce(Return(access_token_fetcher_.release()));
|
| - EXPECT_CALL(delegate_, OnMintTokenFailure(error))
|
| - .Times(1);
|
| + void CreateFlow(OAuth2MintTokenFlow::Mode mode) {
|
| + return CreateFlow(&delegate_, mode);
|
| }
|
|
|
| - void SetAccessTokenFetcherSuccess(const std::string& rt) {
|
| - EXPECT_CALL(*access_token_fetcher_,
|
| - Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
|
| - GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
|
| - rt, std::vector<std::string>()))
|
| - .Times(1);
|
| - EXPECT_CALL(*flow_, CreateAccessTokenFetcher())
|
| - .WillOnce(Return(access_token_fetcher_.release()));
|
| + void CreateFlow(MockDelegate* delegate,
|
| + OAuth2MintTokenFlow::Mode mode) {
|
| + std::string rt = "refresh_token";
|
| + std::string ext_id = "ext1";
|
| + std::string client_id = "client1";
|
| + std::vector<std::string> scopes(CreateTestScopes());
|
| + flow_.reset(new MockMintTokenFlow(
|
| + delegate,
|
| + OAuth2MintTokenFlow::Parameters(rt, ext_id, client_id, scopes, mode)));
|
| }
|
|
|
| - void SetMintTokenFetcherFailure(const std::string& rt,
|
| - const std::string& ext_id,
|
| - const std::string& client_id,
|
| - const std::vector<std::string>& scopes,
|
| - const GoogleServiceAuthError& error) {
|
| - EXPECT_CALL(*mint_token_fetcher_,
|
| - Start(rt, client_id, scopes, ext_id))
|
| - .Times(1);
|
| - EXPECT_CALL(*flow_, CreateMintTokenFetcher())
|
| - .WillOnce(Return(mint_token_fetcher_.release()));
|
| - EXPECT_CALL(delegate_, OnMintTokenFailure(error))
|
| - .Times(1);
|
| + // Helper to parse the given string to DictionaryValue.
|
| + static base::DictionaryValue* ParseJson(const std::string& str) {
|
| + base::JSONReader reader;
|
| + scoped_ptr<Value> value(reader.Read(str, false));
|
| + EXPECT_TRUE(value.get());
|
| + EXPECT_EQ(Value::TYPE_DICTIONARY, value->GetType());
|
| + return static_cast<base::DictionaryValue*>(value.release());
|
| }
|
|
|
| - void SetMintTokenFetcherSuccess(const std::string& rt,
|
| - const std::string& ext_id,
|
| - const std::string& client_id,
|
| - const std::vector<std::string>& scopes,
|
| - const std::string& at) {
|
| - EXPECT_CALL(*mint_token_fetcher_,
|
| - Start(rt, client_id, scopes, ext_id))
|
| - .Times(1);
|
| - EXPECT_CALL(*flow_, CreateMintTokenFetcher())
|
| - .WillOnce(Return(mint_token_fetcher_.release()));
|
| - EXPECT_CALL(delegate_, OnMintTokenSuccess(at))
|
| - .Times(1);
|
| - }
|
| -
|
| - scoped_ptr<MockOAuth2MintTokenFlow> flow_;
|
| - scoped_ptr<MockOAuth2AccessTokenFetcher> access_token_fetcher_;
|
| - scoped_ptr<MockOAuth2MintTokenFetcher> mint_token_fetcher_;
|
| - MockDelegate delegate_;
|
| + scoped_ptr<MockMintTokenFlow> flow_;
|
| + StrictMock<MockDelegate> delegate_;
|
| };
|
|
|
| -TEST_F(OAuth2MintTokenFlowTest, LoginAccessTokenFailure) {
|
| - std::string rt = "refresh_token";
|
| - std::string ext_id = "ext1";
|
| - std::string client_id = "client1";
|
| - std::vector<std::string> scopes(CreateTestScopes());
|
| - std::string at = "access_token";
|
| - GoogleServiceAuthError err(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
|
| +TEST_F(OAuth2MintTokenFlowTest, CreateApiCallBody) {
|
| + { // Issue advice mode.
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
|
| + std::string body = flow_->CreateApiCallBody();
|
| + std::string expected_body(
|
| + "force=false"
|
| + "&response_type=none"
|
| + "&scope=http://scope1+http://scope2"
|
| + "&client_id=client1"
|
| + "&origin=ext1");
|
| + EXPECT_EQ(expected_body, body);
|
| + }
|
| + { // Record grant mode.
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_RECORD_GRANT);
|
| + std::string body = flow_->CreateApiCallBody();
|
| + std::string expected_body(
|
| + "force=true"
|
| + "&response_type=none"
|
| + "&scope=http://scope1+http://scope2"
|
| + "&client_id=client1"
|
| + "&origin=ext1");
|
| + EXPECT_EQ(expected_body, body);
|
| + }
|
| + { // Mint token no force mode.
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + std::string body = flow_->CreateApiCallBody();
|
| + std::string expected_body(
|
| + "force=false"
|
| + "&response_type=token"
|
| + "&scope=http://scope1+http://scope2"
|
| + "&client_id=client1"
|
| + "&origin=ext1");
|
| + EXPECT_EQ(expected_body, body);
|
| + }
|
| + { // Mint token force mode.
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
|
| + std::string body = flow_->CreateApiCallBody();
|
| + std::string expected_body(
|
| + "force=true"
|
| + "&response_type=token"
|
| + "&scope=http://scope1+http://scope2"
|
| + "&client_id=client1"
|
| + "&origin=ext1");
|
| + EXPECT_EQ(expected_body, body);
|
| + }
|
| +}
|
|
|
| - SetAccessTokenFetcherFailure(rt, err);
|
| +TEST_F(OAuth2MintTokenFlowTest, ParseMintTokenResponse) {
|
| + { // Access token missing.
|
| + scoped_ptr<base::DictionaryValue> json(
|
| + ParseJson(kTokenResponseNoAccessToken));
|
| + std::string at;
|
| + EXPECT_FALSE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at));
|
| + EXPECT_TRUE(at.empty());
|
| + }
|
| + { // All good.
|
| + scoped_ptr<base::DictionaryValue> json(ParseJson(kValidTokenResponse));
|
| + std::string at;
|
| + EXPECT_TRUE(OAuth2MintTokenFlow::ParseMintTokenResponse(json.get(), &at));
|
| + EXPECT_EQ("at1", at);
|
| + }
|
| +}
|
|
|
| - flow_->Start(rt, ext_id, client_id, scopes);
|
| - flow_->OnGetTokenFailure(err);
|
| +TEST_F(OAuth2MintTokenFlowTest, ParseIssueAdviceResponse) {
|
| + { // Description missing.
|
| + scoped_ptr<base::DictionaryValue> json(
|
| + ParseJson(kIssueAdviceResponseNoDescription));
|
| + IssueAdviceInfo ia;
|
| + EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
|
| + json.get(), &ia));
|
| + EXPECT_TRUE(ia.empty());
|
| + }
|
| + { // Detail missing.
|
| + scoped_ptr<base::DictionaryValue> json(
|
| + ParseJson(kIssueAdviceResponseNoDetail));
|
| + IssueAdviceInfo ia;
|
| + EXPECT_FALSE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
|
| + json.get(), &ia));
|
| + EXPECT_TRUE(ia.empty());
|
| + }
|
| + { // All good.
|
| + scoped_ptr<base::DictionaryValue> json(
|
| + ParseJson(kValidIssueAdviceResponse));
|
| + IssueAdviceInfo ia;
|
| + EXPECT_TRUE(OAuth2MintTokenFlow::ParseIssueAdviceResponse(
|
| + json.get(), &ia));
|
| + IssueAdviceInfo ia_expected(CreateIssueAdvice());
|
| + EXPECT_EQ(ia_expected, ia);
|
| + }
|
| }
|
|
|
| -TEST_F(OAuth2MintTokenFlowTest, MintAccessTokenFailure) {
|
| - std::string rt = "refresh_token";
|
| - std::string ext_id = "ext1";
|
| - std::string client_id = "client1";
|
| - std::vector<std::string> scopes(CreateTestScopes());
|
| - std::string at = "access_token";
|
| - GoogleServiceAuthError err(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
|
| +TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallSuccess) {
|
| + { // No body.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString("");
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(_));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| + { // Bad json.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString("foo");
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(_));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| + { // Valid json: no access token.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString(kTokenResponseNoAccessToken);
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(_));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| + { // Valid json: good token response.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString(kValidTokenResponse);
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + EXPECT_CALL(delegate_, OnMintTokenSuccess("at1"));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| + { // Valid json: no description.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString(kIssueAdviceResponseNoDescription);
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(_));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| + { // Valid json: no detail.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString(kIssueAdviceResponseNoDetail);
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(_));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| + { // Valid json: good issue advice response.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.SetResponseString(kValidIssueAdviceResponse);
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
|
| + IssueAdviceInfo ia(CreateIssueAdvice());
|
| + EXPECT_CALL(delegate_, OnIssueAdviceSuccess(ia));
|
| + flow_->ProcessApiCallSuccess(&url_fetcher);
|
| + }
|
| +}
|
|
|
| - SetAccessTokenFetcherSuccess(rt);
|
| - SetMintTokenFetcherFailure(at, ext_id, client_id, scopes, err);
|
| +TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallFailure) {
|
| + { // Null delegate should work fine.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.set_status(URLRequestStatus(URLRequestStatus::FAILED, 101));
|
| + CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + flow_->ProcessApiCallFailure(&url_fetcher);
|
| + }
|
|
|
| - flow_->Start(rt, ext_id, client_id, scopes);
|
| - flow_->OnGetTokenSuccess(at);
|
| - flow_->OnMintTokenFailure(err);
|
| + { // Non-null delegate.
|
| + TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
|
| + url_fetcher.set_status(URLRequestStatus(URLRequestStatus::FAILED, 101));
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(_));
|
| + flow_->ProcessApiCallFailure(&url_fetcher);
|
| + }
|
| }
|
|
|
| -TEST_F(OAuth2MintTokenFlowTest, Success) {
|
| - std::string rt = "refresh_token";
|
| - std::string ext_id = "ext1";
|
| - std::string client_id = "client1";
|
| - std::vector<std::string> scopes(CreateTestScopes());
|
| - std::string at = "access_token";
|
| - std::string result = "app_access_token";
|
| +TEST_F(OAuth2MintTokenFlowTest, ProcessMintAccessTokenFailure) {
|
| + { // Null delegate should work fine.
|
| + GoogleServiceAuthError error(
|
| + GoogleServiceAuthError::FromConnectionError(101));
|
| + CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + flow_->ProcessMintAccessTokenFailure(error);
|
| + }
|
|
|
| - SetAccessTokenFetcherSuccess(rt);
|
| - SetMintTokenFetcherSuccess(at, ext_id, client_id, scopes, result);
|
| -
|
| - flow_->Start(rt, ext_id, client_id, scopes);
|
| - flow_->OnGetTokenSuccess(at);
|
| - flow_->OnMintTokenSuccess(result);
|
| + { // Non-null delegate.
|
| + GoogleServiceAuthError error(
|
| + GoogleServiceAuthError::FromConnectionError(101));
|
| + CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
|
| + EXPECT_CALL(delegate_, OnMintTokenFailure(error));
|
| + flow_->ProcessMintAccessTokenFailure(error);
|
| + }
|
| }
|
|
|