Commit 8669b846 authored by Yiming Zhou's avatar Yiming Zhou Committed by Commit Bot

Support password manager scenarios in the captured sites test framework

Bug: 847905
Change-Id: Ic8da3d3d2214a06cf0cc8a180d66a81fbc89ed90
Reviewed-on: https://chromium-review.googlesource.com/1214208
Commit-Queue: Yiming Zhou <uwyiming@google.com>
Reviewed-by: default avatarSebastien Seguin-Gagnon <sebsg@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593060}
parent a5a00728
......@@ -52,6 +52,13 @@ namespace {
const base::TimeDelta autofill_wait_for_action_interval =
base::TimeDelta::FromSeconds(5);
struct GetParamAsString {
template <class ParamType>
std::string operator()(const testing::TestParamInfo<ParamType>& info) const {
return info.param;
}
};
base::FilePath GetReplayFilesDirectory() {
base::FilePath src_dir;
if (base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) {
......@@ -248,13 +255,6 @@ IN_PROC_BROWSER_TEST_P(AutofillCapturedSitesInteractiveTest, Recipe) {
recipe_replayer()->ReplayTest(capture_file_path, recipe_file_path));
}
struct GetParamAsString {
template <class ParamType>
std::string operator()(const testing::TestParamInfo<ParamType>& info) const {
return info.param;
}
};
INSTANTIATE_TEST_CASE_P(,
AutofillCapturedSitesInteractiveTest,
testing::ValuesIn(GetCapturedSites()),
......
......@@ -30,7 +30,7 @@ const base::TimeDelta default_action_timeout = base::TimeDelta::FromSeconds(30);
// The amount of time to wait for a page to trigger a paint in response to a
// an ation. The Captured Site Automation Framework uses this timeout to
// break out of a wait loop after a hover action.
const base::TimeDelta visual_update_timeout = base::TimeDelta::FromSeconds(5);
const base::TimeDelta visual_update_timeout = base::TimeDelta::FromSeconds(20);
std::string FilePathToUTF8(const base::FilePath::StringType& str);
......@@ -148,6 +148,16 @@ class TestRecipeReplayChromeFeatureActionExecutor {
virtual bool AutofillForm(content::RenderFrameHost* frame,
const std::string& focus_element_css_selector,
const int attempts = 1);
// Chrome Password Manager feature methods.
virtual bool AddCredential(const std::string& origin,
const std::string& username,
const std::string& password);
virtual bool SavePassword();
virtual bool UpdatePassword();
virtual bool HasChromeShownSavePasswordPrompt();
virtual bool HasChromeStoredCredential(const std::string& origin,
const std::string& username,
const std::string& password);
protected:
TestRecipeReplayChromeFeatureActionExecutor();
......@@ -227,10 +237,14 @@ class TestRecipeReplayer {
bool ExecuteHoverAction(const base::DictionaryValue& action);
bool ExecutePressEnterAction(const base::DictionaryValue& action);
bool ExecuteRunCommandAction(const base::DictionaryValue& action);
bool ExecuteSavePasswordAction(const base::DictionaryValue& action);
bool ExecuteSelectDropdownAction(const base::DictionaryValue& action);
bool ExecuteTypeAction(const base::DictionaryValue& action);
bool ExecuteTypePasswordAction(const base::DictionaryValue& action);
bool ExecuteUpdatePasswordAction(const base::DictionaryValue& action);
bool ExecuteValidateFieldValueAction(const base::DictionaryValue& action);
bool ExecuteValidateNoSavePasswordPromptAction(
const base::DictionaryValue& action);
bool ExecuteWaitForStateAction(const base::DictionaryValue& action);
bool GetTargetHTMLElementXpathFromAction(const base::DictionaryValue& action,
std::string* xpath);
......@@ -256,6 +270,9 @@ class TestRecipeReplayer {
const std::string& expected_value,
const bool ignoreCase = false);
void NavigateAwayAndDismissBeforeUnloadDialog();
bool HasChromeStoredCredential(const base::DictionaryValue& action,
bool* stored_cred);
bool SetupSavedPasswords(const base::Value& saved_password_list_container);
Browser* browser_;
TestRecipeReplayChromeFeatureActionExecutor* feature_action_executor_;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <utility>
#include "base/files/file_enumerator.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/autofill/captured_sites_test_utils.h"
#include "chrome/browser/password_manager/password_manager_test_base.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
#include "chrome/browser/ui/tab_dialogs.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "content/public/test/test_utils.h"
namespace {
// Return path to the Password Manager captured sites test directory. The
// directory contains site capture files and test recipe replay files.
base::FilePath GetReplayFilesDirectory() {
base::FilePath src_dir;
if (base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) {
return src_dir.Append(
FILE_PATH_LITERAL("chrome/test/data/password/captured_sites/sign_in"));
}
ADD_FAILURE() << "Unable to obtain the Chromium src directory!";
src_dir.clear();
return src_dir;
}
// Iterate through Password Manager's Web Page Replay capture file directory to
// look for captures sites and automation recipe files. Return a list of sites
// for which recipe-based testing is available.
std::vector<std::string> GetCapturedSites() {
std::vector<std::string> sites;
base::FileEnumerator capture_files(GetReplayFilesDirectory(), false,
base::FileEnumerator::FILES);
for (base::FilePath file = capture_files.Next(); !file.empty();
file = capture_files.Next()) {
// If a site capture file is found, also look to see if the directory has
// a corresponding recorded action recipe log file.
// A site capture file has no extension. A recorded action recipe log file
// has the '.test' extension.
if (file.Extension().empty() &&
base::PathExists(file.AddExtension(FILE_PATH_LITERAL(".test")))) {
sites.push_back(
captured_sites_test_utils::FilePathToUTF8(file.BaseName().value()));
}
}
std::sort(sites.begin(), sites.end());
return sites;
}
struct GetParamAsString {
template <class ParamType>
std::string operator()(const testing::TestParamInfo<ParamType>& info) const {
return info.param;
}
};
} // namespace
namespace password_manager {
// Harness for running password manager scenarios on captured real-world sites.
// Test params:
// - string Recipe: the name of the captured site file and the test recipe
// file.
class CapturedSitesPasswordManagerBrowserTest
: public InProcessBrowserTest,
public captured_sites_test_utils::
TestRecipeReplayChromeFeatureActionExecutor,
public ::testing::WithParamInterface<std::string> {
public:
// TestRecipeReplayChromeFeatureActionExecutor:
bool AddCredential(const std::string& origin,
const std::string& username,
const std::string& password) override {
scoped_refptr<password_manager::TestPasswordStore> password_store =
static_cast<password_manager::TestPasswordStore*>(
PasswordStoreFactory::GetForProfile(
browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
.get());
autofill::PasswordForm signin_form;
signin_form.origin = GURL(origin);
signin_form.signon_realm = origin;
signin_form.password_value = base::ASCIIToUTF16(password);
signin_form.username_value = base::ASCIIToUTF16(username);
password_store->AddLogin(signin_form);
return true;
}
bool SavePassword() override {
BubbleObserver bubble_observer(WebContents());
if (bubble_observer.IsSavePromptAvailable()) {
bubble_observer.AcceptSavePrompt();
PasswordManagerBrowserTestBase::WaitForPasswordStore(browser());
// Hide the Save Password Prompt UI.
TabDialogs::FromWebContents(WebContents())->HideManagePasswordsBubble();
content::RunAllPendingInMessageLoop();
return true;
}
ADD_FAILURE() << "No Save Password prompt!";
return false;
}
bool UpdatePassword() override {
BubbleObserver bubble_observer(WebContents());
if (bubble_observer.IsUpdatePromptAvailable()) {
const autofill::PasswordForm& pending_credentials =
ManagePasswordsUIController::FromWebContents(WebContents())
->GetPendingPassword();
bubble_observer.AcceptUpdatePrompt(pending_credentials);
PasswordManagerBrowserTestBase::WaitForPasswordStore(browser());
// Hide the Update Password Prompt UI.
TabDialogs::FromWebContents(WebContents())->HideManagePasswordsBubble();
content::RunAllPendingInMessageLoop();
return true;
}
ADD_FAILURE() << "No Update Password prompt!";
return false;
}
bool HasChromeShownSavePasswordPrompt() override {
BubbleObserver bubble_observer(WebContents());
return bubble_observer.IsSavePromptShownAutomatically();
}
bool HasChromeStoredCredential(const std::string& origin,
const std::string& username,
const std::string& password) override {
scoped_refptr<password_manager::TestPasswordStore> password_store =
static_cast<password_manager::TestPasswordStore*>(
PasswordStoreFactory::GetForProfile(
browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
.get());
auto found = password_store->stored_passwords().find(origin);
if (password_store->stored_passwords().end() == found) {
return false;
}
const std::vector<autofill::PasswordForm>& passwords_vector = found->second;
for (std::vector<autofill::PasswordForm>::const_iterator it =
passwords_vector.begin();
it != passwords_vector.end(); ++it) {
if (base::ASCIIToUTF16(username) == it->username_value &&
base::ASCIIToUTF16(password) == it->password_value) {
return true;
}
}
return false;
}
protected:
CapturedSitesPasswordManagerBrowserTest() = default;
~CapturedSitesPasswordManagerBrowserTest() override = default;
// InProcessBrowserTest:
void SetUpOnMainThread() override {
PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab(
browser(), &web_contents_);
recipe_replayer_ =
std::make_unique<captured_sites_test_utils::TestRecipeReplayer>(
browser(), this);
recipe_replayer()->Setup();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpCommandLine(command_line);
captured_sites_test_utils::TestRecipeReplayer::SetUpCommandLine(
command_line);
}
void TearDownOnMainThread() override { recipe_replayer()->Cleanup(); }
captured_sites_test_utils::TestRecipeReplayer* recipe_replayer() {
return recipe_replayer_.get();
}
content::WebContents* WebContents() {
// return web_contents_;
return web_contents_;
}
private:
std::unique_ptr<captured_sites_test_utils::TestRecipeReplayer>
recipe_replayer_;
content::WebContents* web_contents_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(CapturedSitesPasswordManagerBrowserTest);
};
IN_PROC_BROWSER_TEST_P(CapturedSitesPasswordManagerBrowserTest, Recipe) {
// Craft the capture file path.
base::FilePath src_dir;
ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
base::FilePath capture_file_path =
GetReplayFilesDirectory().AppendASCII(GetParam().c_str());
// Craft the recipe file path.
base::FilePath recipe_file_path = GetReplayFilesDirectory().AppendASCII(
base::StringPrintf("%s.test", GetParam().c_str()));
ASSERT_TRUE(
recipe_replayer()->ReplayTest(capture_file_path, recipe_file_path));
}
INSTANTIATE_TEST_CASE_P(All,
CapturedSitesPasswordManagerBrowserTest,
testing::ValuesIn(GetCapturedSites()),
GetParamAsString());
} // namespace password_manager
......@@ -324,10 +324,8 @@ bool BubbleObserver::IsUpdatePromptShownAutomatically() const {
->was_prompt_automatically_shown();
}
void BubbleObserver::Dismiss() const {
void BubbleObserver::Hide() const {
passwords_ui_controller_->OnBubbleHidden();
ASSERT_EQ(password_manager::ui::INACTIVE_STATE,
passwords_ui_controller_->GetState());
}
void BubbleObserver::AcceptSavePrompt() const {
......@@ -384,15 +382,6 @@ PasswordManagerBrowserTestBase::PasswordManagerBrowserTestBase()
PasswordManagerBrowserTestBase::~PasswordManagerBrowserTestBase() = default;
void PasswordManagerBrowserTestBase::SetUpOnMainThread() {
// Use TestPasswordStore to remove a possible race. Normally the
// PasswordStore does its database manipulation on the DB thread, which
// creates a possible race during navigation. Specifically the
// PasswordManager will ignore any forms in a page if the load from the
// PasswordStore has not completed.
PasswordStoreFactory::GetInstance()->SetTestingFactory(
browser()->profile(),
password_manager::BuildPasswordStore<
content::BrowserContext, password_manager::TestPasswordStore>);
ASSERT_TRUE(embedded_test_server()->Start());
// Setup HTTPS server serving files from standard test directory.
......@@ -412,41 +401,65 @@ void PasswordManagerBrowserTestBase::SetUpOnMainThread() {
verify_result.verified_cert = cert;
mock_cert_verifier()->AddResultForCert(cert.get(), verify_result, net::OK);
SetUpOnMainThreadAndGetNewTab(browser(), &web_contents_);
}
void PasswordManagerBrowserTestBase::TearDownOnMainThread() {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
}
void PasswordManagerBrowserTestBase::TearDownInProcessBrowserTestFixture() {
ProfileIOData::SetCertVerifierForTesting(nullptr);
}
void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab(
Browser* browser,
content::WebContents** web_contents) {
// Use TestPasswordStore to remove a possible race. Normally the
// PasswordStore does its database manipulation on a background thread, which
// creates a possible race during navigation. Specifically the
// PasswordManager will ignore any forms in a page if the load from the
// PasswordStore has not completed.
PasswordStoreFactory::GetInstance()->SetTestingFactory(
browser->profile(),
password_manager::BuildPasswordStore<
content::BrowserContext, password_manager::TestPasswordStore>);
// Add a tab with a customized ManagePasswordsUIController. Thus, we can
// intercept useful UI events.
content::WebContents* tab =
browser()->tab_strip_model()->GetActiveWebContents();
browser->tab_strip_model()->GetActiveWebContents();
std::unique_ptr<content::WebContents> owned_web_contents =
content::WebContents::Create(
content::WebContents::CreateParams(tab->GetBrowserContext()));
web_contents_ = owned_web_contents.get();
ASSERT_TRUE(web_contents_);
*web_contents = owned_web_contents.get();
ASSERT_TRUE(*web_contents);
// ManagePasswordsUIController needs ChromePasswordManagerClient for logging.
autofill::ChromeAutofillClient::CreateForWebContents(web_contents_);
autofill::ChromeAutofillClient::CreateForWebContents(*web_contents);
ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
web_contents_,
autofill::ChromeAutofillClient::FromWebContents(web_contents_));
ASSERT_TRUE(ChromePasswordManagerClient::FromWebContents(web_contents_));
*web_contents,
autofill::ChromeAutofillClient::FromWebContents(*web_contents));
ASSERT_TRUE(ChromePasswordManagerClient::FromWebContents(*web_contents));
CustomManagePasswordsUIController* controller =
new CustomManagePasswordsUIController(web_contents_);
browser()->tab_strip_model()->AppendWebContents(std::move(owned_web_contents),
true);
browser()->tab_strip_model()->CloseWebContentsAt(0,
TabStripModel::CLOSE_NONE);
new CustomManagePasswordsUIController(*web_contents);
browser->tab_strip_model()->AppendWebContents(std::move(owned_web_contents),
true);
browser->tab_strip_model()->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
ASSERT_EQ(controller,
ManagePasswordsUIController::FromWebContents(web_contents_));
ASSERT_EQ(web_contents_,
browser()->tab_strip_model()->GetActiveWebContents());
ASSERT_FALSE(web_contents_->IsLoading());
ManagePasswordsUIController::FromWebContents(*web_contents));
ASSERT_EQ(*web_contents, browser->tab_strip_model()->GetActiveWebContents());
ASSERT_FALSE((*web_contents)->IsLoading());
}
void PasswordManagerBrowserTestBase::TearDownOnMainThread() {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
}
void PasswordManagerBrowserTestBase::TearDownInProcessBrowserTestFixture() {
ProfileIOData::SetCertVerifierForTesting(nullptr);
void PasswordManagerBrowserTestBase::WaitForPasswordStore(Browser* browser) {
scoped_refptr<password_manager::PasswordStore> password_store =
PasswordStoreFactory::GetForProfile(browser->profile(),
ServiceAccessType::IMPLICIT_ACCESS);
PasswordStoreResultsObserver syncer;
password_store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(
&syncer);
syncer.Wait();
}
content::WebContents* PasswordManagerBrowserTestBase::WebContents() const {
......@@ -583,13 +596,7 @@ void PasswordManagerBrowserTestBase::WaitForJsElementValue(
}
void PasswordManagerBrowserTestBase::WaitForPasswordStore() {
scoped_refptr<password_manager::PasswordStore> password_store =
PasswordStoreFactory::GetForProfile(browser()->profile(),
ServiceAccessType::IMPLICIT_ACCESS);
PasswordStoreResultsObserver syncer;
password_store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(
&syncer);
syncer.Wait();
WaitForPasswordStore(browser());
}
void PasswordManagerBrowserTestBase::CheckElementValue(
......
......@@ -85,9 +85,8 @@ class BubbleObserver {
// PasswordManagerBrowserTestBase.
bool IsUpdatePromptShownAutomatically() const;
// Dismisses the prompt currently open and moves the controller to the
// inactive state.
void Dismiss() const;
// Hide the currently open prompt.
void Hide() const;
// Expecting that the prompt is available, saves the password. At the end,
// checks that the prompt is no longer available afterwards.
......@@ -139,6 +138,18 @@ class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest {
void TearDownOnMainThread() override;
void TearDownInProcessBrowserTestFixture() override;
// Bring up a new Chrome tab set up with password manager test hooks.
// @param[in] browser the browser running the password manager test, upon
// which this function will perform the setup steps.
// @param[out] a new tab on the browser set up with password manager test
// hooks.
static void SetUpOnMainThreadAndGetNewTab(
Browser* browser,
content::WebContents** web_contents);
// Make sure that the password store associated with the given browser
// processed all the previous calls, calls executed on another thread.
static void WaitForPasswordStore(Browser* browser);
protected:
// Wrapper around ui_test_utils::NavigateToURL that waits until
// DidFinishLoad() fires. Normally this function returns after
......
......@@ -4844,6 +4844,7 @@ if (!is_android) {
ldflags = []
deps = [
":captured_sites_interactive_tests",
":test_support",
":test_support_ui",
"//chrome:packed_resources",
......@@ -5691,7 +5692,7 @@ if (!is_android && !is_fuchsia) {
}
# Tests autofill on captured websites
test("autofill_captured_sites_interactive_tests") {
test("captured_sites_interactive_tests") {
sources = [
"../browser/autofill/autofill_captured_sites_interactive_uitest.cc",
"../browser/autofill/autofill_uitest.cc",
......@@ -5700,6 +5701,9 @@ if (!is_android && !is_fuchsia) {
"../browser/autofill/autofill_uitest_util.h",
"../browser/autofill/captured_sites_test_utils.cc",
"../browser/autofill/captured_sites_test_utils.h",
"../browser/password_manager/password_manager_captured_sites_interactive_uitest.cc",
"../browser/password_manager/password_manager_test_base.cc",
"../browser/password_manager/password_manager_test_base.h",
"base/interactive_test_utils.cc",
"base/interactive_test_utils.h",
"base/interactive_test_utils_common_views.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment