| Index: chrome/browser/extensions/api/identity/identity_apitest.cc
|
| ===================================================================
|
| --- chrome/browser/extensions/api/identity/identity_apitest.cc (revision 147987)
|
| +++ chrome/browser/extensions/api/identity/identity_apitest.cc (working copy)
|
| @@ -2,58 +2,389 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include "base/string_util.h"
|
| +#include "base/values.h"
|
| #include "chrome/browser/extensions/api/identity/identity_api.h"
|
| #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
|
| #include "chrome/browser/extensions/extension_apitest.h"
|
| +#include "chrome/browser/extensions/extension_browsertest.h"
|
| +#include "chrome/browser/extensions/extension_function_test_utils.h"
|
| +#include "chrome/browser/ui/webui/signin/login_ui_service.h"
|
| #include "chrome/common/net/gaia/google_service_auth_error.h"
|
| #include "chrome/common/net/gaia/oauth2_mint_token_flow.h"
|
| #include "chrome/common/chrome_switches.h"
|
| +#include "chrome/test/base/in_process_browser_test.h"
|
| #include "googleurl/src/gurl.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
|
|
| +using extensions::Extension;
|
| +using extensions::IdentityGetAuthTokenFunction;
|
| +using testing::_;
|
| +using testing::Return;
|
| +using testing::ReturnRef;
|
| +
|
| +namespace errors = extensions::identity_constants;
|
| +namespace utils = extension_function_test_utils;
|
| +
|
| namespace {
|
|
|
| -class IdentityInterceptor : public OAuth2MintTokenFlow::InterceptorForTests {
|
| +static const char kAccessToken[] = "auth_token";
|
| +
|
| +class TestLoginUI : public LoginUIService::LoginUI {
|
| public:
|
| - IdentityInterceptor() : called_(false) { }
|
| + virtual void FocusUI() OVERRIDE {}
|
| + virtual void CloseUI() OVERRIDE {}
|
| +};
|
|
|
| - virtual bool DoIntercept(const OAuth2MintTokenFlow* flow,
|
| - std::string* access_token,
|
| - GoogleServiceAuthError* error) OVERRIDE {
|
| - *access_token = "auth_token";
|
| - called_ = true;
|
| - return true;
|
| +class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
|
| + public:
|
| + enum ResultType {
|
| + ISSUE_ADVICE_SUCCESS,
|
| + MINT_TOKEN_SUCCESS,
|
| + MINT_TOKEN_FAILURE
|
| + };
|
| +
|
| + TestOAuth2MintTokenFlow(ResultType result,
|
| + OAuth2MintTokenFlow::Delegate* delegate)
|
| + : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()),
|
| + result_(result),
|
| + delegate_(delegate) {
|
| }
|
|
|
| - bool called() const { return called_; }
|
| + virtual void Start() OVERRIDE {
|
| + switch (result_) {
|
| + case ISSUE_ADVICE_SUCCESS: {
|
| + IssueAdviceInfo info;
|
| + delegate_->OnIssueAdviceSuccess(info);
|
| + break;
|
| + }
|
| + case MINT_TOKEN_SUCCESS: {
|
| + delegate_->OnMintTokenSuccess(kAccessToken);
|
| + break;
|
| + }
|
| + case MINT_TOKEN_FAILURE: {
|
| + GoogleServiceAuthError error(
|
| + GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
|
| + delegate_->OnMintTokenFailure(error);
|
| + break;
|
| + }
|
| + }
|
| + }
|
|
|
| private:
|
| - bool called_;
|
| + ResultType result_;
|
| + OAuth2MintTokenFlow::Delegate* delegate_;
|
| };
|
|
|
| -class WebAuthFlowInterceptor
|
| - : public extensions::WebAuthFlow::InterceptorForTests {
|
| +} // namespace
|
| +
|
| +class MockGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
|
| public:
|
| - WebAuthFlowInterceptor() : called_(false) { }
|
| + MockGetAuthTokenFunction() : install_ui_result_(false),
|
| + login_ui_shown_(false),
|
| + install_ui_shown_(false) {
|
| + }
|
|
|
| - virtual GURL DoIntercept(const GURL& provider_url) OVERRIDE {
|
| - called_ = true;
|
| - return GURL("https://abcd.chromiumapp.org/cb#access_token=tok");
|
| + void set_install_ui_result(bool result) {
|
| + install_ui_result_ = result;
|
| }
|
|
|
| - bool called() const { return called_; }
|
| + bool login_ui_shown() const {
|
| + return login_ui_shown_;
|
| + }
|
|
|
| + bool install_ui_shown() const {
|
| + return install_ui_shown_;
|
| + }
|
| +
|
| + virtual void StartObservingLoginService() OVERRIDE {
|
| + // Do nothing in tests.
|
| + }
|
| + virtual void StopObservingLoginService() OVERRIDE {
|
| + // Do nothing in tests.
|
| + }
|
| +
|
| + virtual void ShowLoginPopup() OVERRIDE {
|
| + login_ui_shown_ = true;
|
| + // Explicitly call OnLoginUIClosed.
|
| + TestLoginUI login_ui;;
|
| + OnLoginUIClosed(&login_ui);
|
| + }
|
| +
|
| + virtual void ShowOAuthApprovalDialog(
|
| + const IssueAdviceInfo& issue_advice) OVERRIDE {
|
| + install_ui_shown_ = true;
|
| + // Call InstallUIProceed or InstallUIAbort based on the flag.
|
| + if (install_ui_result_)
|
| + InstallUIProceed();
|
| + else
|
| + InstallUIAbort(true);
|
| + }
|
| +
|
| + MOCK_CONST_METHOD0(HasLoginToken, bool ());
|
| + MOCK_METHOD1(CreateMintTokenFlow,
|
| + OAuth2MintTokenFlow* (OAuth2MintTokenFlow::Mode mode));
|
| private:
|
| - bool called_;
|
| + ~MockGetAuthTokenFunction() {}
|
| + bool install_ui_result_;
|
| + bool login_ui_shown_;
|
| + bool install_ui_shown_;
|
| };
|
|
|
| -} // namespace
|
| +class GetAuthTokenFunctionTest : public ExtensionBrowserTest {
|
| + protected:
|
| + enum OAuth2Fields {
|
| + NONE = 0,
|
| + CLIENT_ID = 1,
|
| + SCOPES = 2
|
| + };
|
|
|
| -IN_PROC_BROWSER_TEST_F(PlatformAppApiTest, Identity) {
|
| - IdentityInterceptor id_interceptor;
|
| - OAuth2MintTokenFlow::SetInterceptorForTests(&id_interceptor);
|
| - WebAuthFlowInterceptor waf_interceptor;
|
| - extensions::WebAuthFlow::SetInterceptorForTests(&waf_interceptor);
|
| - ASSERT_TRUE(RunExtensionTest("identity")) << message_;
|
| - ASSERT_TRUE(id_interceptor.called());
|
| - ASSERT_TRUE(waf_interceptor.called());
|
| + ~GetAuthTokenFunctionTest() {}
|
| +
|
| + // Helper to create an extension with specific OAuth2Info fields set.
|
| + // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
|
| + const Extension* CreateExtension(int fields_to_set) {
|
| + const Extension* ext = LoadExtension(
|
| + test_data_dir_.AppendASCII("platform_apps/oauth2"));
|
| + Extension::OAuth2Info& oauth2_info = const_cast<Extension::OAuth2Info&>(
|
| + ext->oauth2_info());
|
| + if ((fields_to_set & CLIENT_ID) != 0)
|
| + oauth2_info.client_id = "client1";
|
| + if ((fields_to_set & SCOPES) != 0) {
|
| + oauth2_info.scopes.push_back("scope1");
|
| + oauth2_info.scopes.push_back("scope2");
|
| + }
|
| + return ext;
|
| + }
|
| };
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + NoClientId) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(SCOPES));
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{}]", browser());
|
| + EXPECT_EQ(std::string(errors::kInvalidClientId), error);
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + NoScopes) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID));
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{}]", browser());
|
| + EXPECT_EQ(std::string(errors::kInvalidScopes), error);
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + NonInteractiveNotSignedIn) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{}]", browser());
|
| + EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + NonInteractiveMintFailure) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{}]", browser());
|
| + EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + NonInteractiveSuccess) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
|
| + scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
|
| + func.get(), "[{}]", browser()));
|
| + std::string access_token;
|
| + EXPECT_TRUE(value->GetAsString(&access_token));
|
| + EXPECT_EQ(std::string(kAccessToken), access_token);
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveLoginCanceled) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken()).WillRepeatedly(Return(false));
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{\"interactive\": true}]", browser());
|
| + EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
|
| + EXPECT_TRUE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveLoginSuccessMintFailure) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(false))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{\"interactive\": true}]", browser());
|
| + EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
|
| + EXPECT_TRUE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveLoginSuccessMintSuccess) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(false))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
|
| + scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
|
| + func.get(), "[{\"interactive\": true}]", browser()));
|
| + std::string access_token;
|
| + EXPECT_TRUE(value->GetAsString(&access_token));
|
| + EXPECT_EQ(std::string(kAccessToken), access_token);
|
| + EXPECT_TRUE(func->login_ui_shown());
|
| + EXPECT_FALSE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveLoginSuccessApprovalAborted) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(false))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
|
| + func->set_install_ui_result(false);
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{\"interactive\": true}]", browser());
|
| + EXPECT_EQ(std::string(errors::kUserRejected), error);
|
| + EXPECT_TRUE(func->login_ui_shown());
|
| + EXPECT_TRUE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveLoginSuccessApprovalDoneMintFailure) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(false))
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
|
| + TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
|
| + .WillOnce(Return(flow1))
|
| + .WillOnce(Return(flow2));
|
| +
|
| + func->set_install_ui_result(true);
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{\"interactive\": true}]", browser());
|
| + EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
|
| + EXPECT_TRUE(func->login_ui_shown());
|
| + EXPECT_TRUE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveLoginSuccessApprovalDoneMintSuccess) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(false))
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
|
| + TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
|
| + .WillOnce(Return(flow1))
|
| + .WillOnce(Return(flow2));
|
| +
|
| + func->set_install_ui_result(true);
|
| + scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
|
| + func.get(), "[{\"interactive\": true}]", browser()));
|
| + std::string access_token;
|
| + EXPECT_TRUE(value->GetAsString(&access_token));
|
| + EXPECT_EQ(std::string(kAccessToken), access_token);
|
| + EXPECT_TRUE(func->login_ui_shown());
|
| + EXPECT_TRUE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveApprovalAborted) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
|
| + func->set_install_ui_result(false);
|
| + std::string error = utils::RunFunctionAndReturnError(
|
| + func.get(), "[{\"interactive\": true}]", browser());
|
| + EXPECT_EQ(std::string(errors::kUserRejected), error);
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_TRUE(func->install_ui_shown());
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
|
| + InteractiveApprovalDoneMintSuccess) {
|
| + scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
|
| + func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
|
| + EXPECT_CALL(*func.get(), HasLoginToken())
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true))
|
| + .WillOnce(Return(true));
|
| + TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
|
| + TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow(
|
| + TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
|
| + EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
|
| + .WillOnce(Return(flow1))
|
| + .WillOnce(Return(flow2));
|
| +
|
| + func->set_install_ui_result(true);
|
| + scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
|
| + func.get(), "[{\"interactive\": true}]", browser()));
|
| + std::string access_token;
|
| + EXPECT_TRUE(value->GetAsString(&access_token));
|
| + EXPECT_EQ(std::string(kAccessToken), access_token);
|
| + EXPECT_FALSE(func->login_ui_shown());
|
| + EXPECT_TRUE(func->install_ui_shown());
|
| +}
|
|
|