Commit 546fc2fa authored by Marc Treib's avatar Marc Treib Committed by Commit Bot

Add a first integration test involving both Sync and PasswordManager

The test sets up Sync-the-transport, has the user opt-in to the account
password storage, and makes sure that saves go to the correct store.

This requires a few changes to password_manager_test_base.h/cc:
- Most notably: The password manager tests used to set up a
  MockPasswordFeatureManager (in order to make IsGenerationEnabled()
  return true), but the new combined tests require a real
  PasswordFeatureManager. So this CL removes the mock (which also lets
  us remove CustomPasswordManagerClient), and instead sets up a
  TestSyncService which claims "everything is active" and so also makes
  IsGenerationEnabled() true.
- Some simple refactorings to avoid duplicating test setup code:
  - Split the "GetNewTab" part out of SetUpOnMainThreadAndGetNewTab(),
    into a new static helper.
  - Exposed PasswordStoreResultsObserver (it used to be fully defined
    in the .cc).
  - Exposed a version of CheckThatCredentialsStored() that takes a
    PasswordStore parameter.

Bug: 1058339
Change-Id: If9b040cbd56ee10ba6b6badd1b4b4d772603f13a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2089825
Commit-Queue: Marc Treib <treib@chromium.org>
Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarMohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749220}
parent 813090c4
...@@ -19,16 +19,17 @@ ...@@ -19,16 +19,17 @@
#include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/password_manager/password_store_factory.h" #include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/autofill/chrome_autofill_client.h" #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/password_manager/core/browser/password_feature_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h" #include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/test_password_store.h" #include "components/password_manager/core/browser/test_password_store.h"
#include "components/sync/driver/test_sync_service.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
...@@ -45,56 +46,10 @@ ...@@ -45,56 +46,10 @@
namespace { namespace {
// A helper class that synchronously waits until the password store handles a std::unique_ptr<KeyedService> BuildTestSyncService(
// GetLogins() request. content::BrowserContext* context) {
class PasswordStoreResultsObserver return std::make_unique<syncer::TestSyncService>();
: public password_manager::PasswordStoreConsumer { }
public:
PasswordStoreResultsObserver() = default;
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) override {
run_loop_.Quit();
}
void Wait() { run_loop_.Run(); }
private:
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(PasswordStoreResultsObserver);
};
// Custom class is required to enable password generation.
class CustomPasswordManagerClient : public ChromePasswordManagerClient {
public:
using ChromePasswordManagerClient::ChromePasswordManagerClient;
CustomPasswordManagerClient(content::WebContents* contents,
autofill::AutofillClient* autofill_client)
: ChromePasswordManagerClient(contents, autofill_client) {
ON_CALL(password_feature_manager_, IsGenerationEnabled())
.WillByDefault(testing::Return(true));
}
static void CreateForWebContentsWithAutofillClient(
content::WebContents* contents,
autofill::AutofillClient* autofill_client) {
ASSERT_FALSE(FromWebContents(contents));
contents->SetUserData(UserDataKey(),
std::make_unique<CustomPasswordManagerClient>(
contents, autofill_client));
}
// PasswordManagerClient:
password_manager::PasswordFeatureManager* GetPasswordFeatureManager()
override {
return &password_feature_manager_;
}
private:
testing::NiceMock<password_manager::MockPasswordFeatureManager>
password_feature_manager_;
};
// ManagePasswordsUIController subclass to capture the UI events. // ManagePasswordsUIController subclass to capture the UI events.
class CustomManagePasswordsUIController : public ManagePasswordsUIController { class CustomManagePasswordsUIController : public ManagePasswordsUIController {
...@@ -435,6 +390,21 @@ bool BubbleObserver::WaitForFallbackForSaving( ...@@ -435,6 +390,21 @@ bool BubbleObserver::WaitForFallbackForSaving(
return controller->WaitForFallbackForSaving(timeout); return controller->WaitForFallbackForSaving(timeout);
} }
PasswordStoreResultsObserver::PasswordStoreResultsObserver() = default;
PasswordStoreResultsObserver::~PasswordStoreResultsObserver() = default;
void PasswordStoreResultsObserver::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
results_ = std::move(results);
run_loop_.Quit();
}
std::vector<std::unique_ptr<autofill::PasswordForm>>
PasswordStoreResultsObserver::WaitForResults() {
run_loop_.Run();
return std::move(results_);
}
PasswordManagerBrowserTestBase::PasswordManagerBrowserTestBase() PasswordManagerBrowserTestBase::PasswordManagerBrowserTestBase()
: https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS), : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS),
web_contents_(nullptr) {} web_contents_(nullptr) {}
...@@ -468,6 +438,7 @@ void PasswordManagerBrowserTestBase::TearDownOnMainThread() { ...@@ -468,6 +438,7 @@ void PasswordManagerBrowserTestBase::TearDownOnMainThread() {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
} }
// static
void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab( void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab(
Browser* browser, Browser* browser,
content::WebContents** web_contents) { content::WebContents** web_contents) {
...@@ -482,19 +453,26 @@ void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab( ...@@ -482,19 +453,26 @@ void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab(
&password_manager::BuildPasswordStore< &password_manager::BuildPasswordStore<
content::BrowserContext, password_manager::TestPasswordStore>)); content::BrowserContext, password_manager::TestPasswordStore>));
GetNewTab(browser, web_contents);
}
// static
void PasswordManagerBrowserTestBase::GetNewTab(
Browser* browser,
content::WebContents** web_contents) {
// Add a tab with a customized ManagePasswordsUIController. Thus, we can // Add a tab with a customized ManagePasswordsUIController. Thus, we can
// intercept useful UI events. // intercept useful UI events.
content::WebContents* tab = content::WebContents* preexisting_tab =
browser->tab_strip_model()->GetActiveWebContents(); browser->tab_strip_model()->GetActiveWebContents();
std::unique_ptr<content::WebContents> owned_web_contents = std::unique_ptr<content::WebContents> owned_web_contents =
content::WebContents::Create( content::WebContents::Create(
content::WebContents::CreateParams(tab->GetBrowserContext())); content::WebContents::CreateParams(browser->profile()));
*web_contents = owned_web_contents.get(); *web_contents = owned_web_contents.get();
ASSERT_TRUE(*web_contents); ASSERT_TRUE(*web_contents);
// ManagePasswordsUIController needs ChromePasswordManagerClient for logging. // ManagePasswordsUIController needs ChromePasswordManagerClient for logging.
autofill::ChromeAutofillClient::CreateForWebContents(*web_contents); autofill::ChromeAutofillClient::CreateForWebContents(*web_contents);
CustomPasswordManagerClient::CreateForWebContentsWithAutofillClient( ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
*web_contents, *web_contents,
autofill::ChromeAutofillClient::FromWebContents(*web_contents)); autofill::ChromeAutofillClient::FromWebContents(*web_contents));
ASSERT_TRUE(ChromePasswordManagerClient::FromWebContents(*web_contents)); ASSERT_TRUE(ChromePasswordManagerClient::FromWebContents(*web_contents));
...@@ -502,20 +480,24 @@ void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab( ...@@ -502,20 +480,24 @@ void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab(
new CustomManagePasswordsUIController(*web_contents); new CustomManagePasswordsUIController(*web_contents);
browser->tab_strip_model()->AppendWebContents(std::move(owned_web_contents), browser->tab_strip_model()->AppendWebContents(std::move(owned_web_contents),
true); true);
browser->tab_strip_model()->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE); if (preexisting_tab) {
browser->tab_strip_model()->CloseWebContentsAt(0,
TabStripModel::CLOSE_NONE);
}
ASSERT_EQ(controller, ASSERT_EQ(controller,
ManagePasswordsUIController::FromWebContents(*web_contents)); ManagePasswordsUIController::FromWebContents(*web_contents));
ASSERT_EQ(*web_contents, browser->tab_strip_model()->GetActiveWebContents()); ASSERT_EQ(*web_contents, browser->tab_strip_model()->GetActiveWebContents());
ASSERT_FALSE((*web_contents)->IsLoading()); ASSERT_FALSE((*web_contents)->IsLoading());
} }
// static
void PasswordManagerBrowserTestBase::WaitForPasswordStore(Browser* browser) { void PasswordManagerBrowserTestBase::WaitForPasswordStore(Browser* browser) {
scoped_refptr<password_manager::PasswordStore> password_store = scoped_refptr<password_manager::PasswordStore> password_store =
PasswordStoreFactory::GetForProfile(browser->profile(), PasswordStoreFactory::GetForProfile(browser->profile(),
ServiceAccessType::IMPLICIT_ACCESS); ServiceAccessType::IMPLICIT_ACCESS);
PasswordStoreResultsObserver syncer; PasswordStoreResultsObserver syncer;
password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer); password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer);
syncer.Wait(); syncer.WaitForResults();
} }
content::WebContents* PasswordManagerBrowserTestBase::WebContents() const { content::WebContents* PasswordManagerBrowserTestBase::WebContents() const {
...@@ -681,6 +663,23 @@ void PasswordManagerBrowserTestBase::CheckElementValue( ...@@ -681,6 +663,23 @@ void PasswordManagerBrowserTestBase::CheckElementValue(
EXPECT_EQ(expected_value, return_value) << "element_id = " << element_id; EXPECT_EQ(expected_value, return_value) << "element_id = " << element_id;
} }
void PasswordManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() {
will_create_browser_context_services_subscription_ =
BrowserContextDependencyManager::GetInstance()
->RegisterWillCreateBrowserContextServicesCallbackForTesting(
base::BindRepeating(&PasswordManagerBrowserTestBase::
OnWillCreateBrowserContextServices));
}
// static
void PasswordManagerBrowserTestBase::OnWillCreateBrowserContextServices(
content::BrowserContext* context) {
// Set up a TestSyncService which will happily return "everything is active"
// so that password generation is considered enabled.
ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
context, base::BindRepeating(&BuildTestSyncService));
}
void PasswordManagerBrowserTestBase::AddHSTSHost(const std::string& host) { void PasswordManagerBrowserTestBase::AddHSTSHost(const std::string& host) {
network::mojom::NetworkContext* network_context = network::mojom::NetworkContext* network_context =
content::BrowserContext::GetDefaultStoragePartition(browser()->profile()) content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include "base/callback_list.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "chrome/browser/ssl/cert_verifier_browser_test.h" #include "chrome/browser/ssl/cert_verifier_browser_test.h"
...@@ -134,12 +135,34 @@ class BubbleObserver { ...@@ -134,12 +135,34 @@ class BubbleObserver {
DISALLOW_COPY_AND_ASSIGN(BubbleObserver); DISALLOW_COPY_AND_ASSIGN(BubbleObserver);
}; };
// A helper class that synchronously waits until the password store handles a
// GetLogins() request.
class PasswordStoreResultsObserver
: public password_manager::PasswordStoreConsumer {
public:
PasswordStoreResultsObserver();
~PasswordStoreResultsObserver() override;
// Waits for OnGetPasswordStoreResults() and returns the result.
std::vector<std::unique_ptr<autofill::PasswordForm>> WaitForResults();
private:
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
base::RunLoop run_loop_;
std::vector<std::unique_ptr<autofill::PasswordForm>> results_;
DISALLOW_COPY_AND_ASSIGN(PasswordStoreResultsObserver);
};
class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest { class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest {
public: public:
PasswordManagerBrowserTestBase(); PasswordManagerBrowserTestBase();
~PasswordManagerBrowserTestBase() override; ~PasswordManagerBrowserTestBase() override;
// InProcessBrowserTest: // InProcessBrowserTest:
void SetUpInProcessBrowserTestFixture() override;
void SetUpOnMainThread() override; void SetUpOnMainThread() override;
void TearDownOnMainThread() override; void TearDownOnMainThread() override;
...@@ -151,6 +174,11 @@ class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest { ...@@ -151,6 +174,11 @@ class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest {
static void SetUpOnMainThreadAndGetNewTab( static void SetUpOnMainThreadAndGetNewTab(
Browser* browser, Browser* browser,
content::WebContents** web_contents); content::WebContents** web_contents);
// Creates a new tab with all the password manager test hooks and returns it
// in |web_contents|.
static void GetNewTab(Browser* browser, content::WebContents** web_contents);
// Make sure that the password store associated with the given browser // Make sure that the password store associated with the given browser
// processed all the previous calls, calls executed on another thread. // processed all the previous calls, calls executed on another thread.
static void WaitForPasswordStore(Browser* browser); static void WaitForPasswordStore(Browser* browser);
...@@ -217,9 +245,17 @@ class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest { ...@@ -217,9 +245,17 @@ class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest {
net::EmbeddedTestServer& https_test_server() { return https_test_server_; } net::EmbeddedTestServer& https_test_server() { return https_test_server_; }
private: private:
static void OnWillCreateBrowserContextServices(
content::BrowserContext* context);
net::EmbeddedTestServer https_test_server_; net::EmbeddedTestServer https_test_server_;
// A tab with some hooks injected. // A tab with some hooks injected.
content::WebContents* web_contents_; content::WebContents* web_contents_;
std::unique_ptr<
base::CallbackList<void(content::BrowserContext*)>::Subscription>
will_create_browser_context_services_subscription_;
DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTestBase); DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTestBase);
}; };
......
// Copyright 2020 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 <memory>
#include <string>
#include "base/callback_list.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/password_manager/account_storage/account_password_store_factory.h"
#include "chrome/browser/password_manager/password_manager_test_base.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/sync/test/integration/passwords_helper.h"
#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/sync/driver/profile_sync_service.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "net/dns/mock_host_resolver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using testing::ElementsAre;
MATCHER_P2(MatchesLogin, username, password, "") {
return arg->username_value == base::UTF8ToUTF16(username) &&
arg->password_value == base::UTF8ToUTF16(password);
}
// Note: This helper applies to ChromeOS too, but is currently unused there. So
// define it out to prevent a compile error due to the unused function.
#if !defined(OS_CHROMEOS)
void GetNewTab(Browser* browser, content::WebContents** web_contents) {
PasswordManagerBrowserTestBase::GetNewTab(browser, web_contents);
}
#endif // !defined(OS_CHROMEOS)
class PasswordSyncActiveChecker : public SingleClientStatusChangeChecker {
public:
explicit PasswordSyncActiveChecker(syncer::ProfileSyncService* service)
: SingleClientStatusChangeChecker(service) {}
~PasswordSyncActiveChecker() override = default;
// SingleClientStatusChangeChecker.
bool IsExitConditionSatisfied(std::ostream* os) override {
return service()->GetActiveDataTypes().Has(syncer::PASSWORDS);
}
};
// This test fixture is similar to SingleClientPasswordsSyncTest, but it also
// sets up all the necessary test hooks etc for PasswordManager code (like
// PasswordManagerBrowserTestBase), to allow for integration tests covering
// both Sync and the PasswordManager.
class PasswordManagerSyncTest : public SyncTest {
public:
PasswordManagerSyncTest() : SyncTest(SINGLE_CLIENT) {
feature_list_.InitWithFeatures(
/*enabled_features=*/{switches::kSyncUSSPasswords,
password_manager::features::
kEnablePasswordsAccountStorage},
/*disabled_features=*/{});
}
~PasswordManagerSyncTest() override = default;
void SetUpInProcessBrowserTestFixture() override {
SyncTest::SetUpInProcessBrowserTestFixture();
test_signin_client_factory_ =
secondary_account_helper::SetUpSigninClient(&test_url_loader_factory_);
will_create_browser_context_services_subscription_ =
BrowserContextDependencyManager::GetInstance()
->RegisterWillCreateBrowserContextServicesCallbackForTesting(
base::BindRepeating(&PasswordManagerSyncTest::
OnWillCreateBrowserContextServices));
}
static void OnWillCreateBrowserContextServices(
content::BrowserContext* context) {
// 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.
// TODO(crbug.com/1058339): Investigate whether these test doubles are
// really required, or whether we can use the real stores and add some
// waiting logic.
PasswordStoreFactory::GetInstance()->SetTestingFactory(
context,
base::BindRepeating(&password_manager::BuildPasswordStoreWithArgs<
content::BrowserContext,
password_manager::TestPasswordStore, bool>,
/*is_account_store=*/false));
AccountPasswordStoreFactory::GetInstance()->SetTestingFactory(
context,
base::BindRepeating(&password_manager::BuildPasswordStoreWithArgs<
content::BrowserContext,
password_manager::TestPasswordStore, bool>,
/*is_account_store=*/true));
}
void SetUpOnMainThread() override {
SyncTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
host_resolver()->AddRule("*", "127.0.0.1");
}
void TearDownOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
SyncTest::TearDownOnMainThread();
}
// Synchronously reads all credentials from the profile password store and
// returns them.
std::vector<std::unique_ptr<autofill::PasswordForm>>
GetAllLoginsFromProfilePasswordStore() {
scoped_refptr<password_manager::PasswordStore> password_store =
passwords_helper::GetPasswordStore(0);
PasswordStoreResultsObserver syncer;
password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer);
return syncer.WaitForResults();
}
// Synchronously reads all credentials from the account password store and
// returns them.
std::vector<std::unique_ptr<autofill::PasswordForm>>
GetAllLoginsFromAccountPasswordStore() {
scoped_refptr<password_manager::PasswordStore> password_store =
passwords_helper::GetAccountPasswordStore(0);
PasswordStoreResultsObserver syncer;
password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer);
return syncer.WaitForResults();
}
void NavigateToFile(content::WebContents* web_contents,
const std::string& path) {
ASSERT_EQ(web_contents,
GetBrowser(0)->tab_strip_model()->GetActiveWebContents());
NavigationObserver observer(web_contents);
GURL url = embedded_test_server()->GetURL(path);
ui_test_utils::NavigateToURL(GetBrowser(0), url);
observer.Wait();
}
private:
base::test::ScopedFeatureList feature_list_;
secondary_account_helper::ScopedSigninClientFactory
test_signin_client_factory_;
std::unique_ptr<
base::CallbackList<void(content::BrowserContext*)>::Subscription>
will_create_browser_context_services_subscription_;
};
#if !defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, ChooseDestinationStore) {
ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
content::WebContents* web_contents = nullptr;
GetNewTab(GetBrowser(0), &web_contents);
// Setup Sync for a secondary account (i.e. in transport mode).
secondary_account_helper::SignInSecondaryAccount(
GetProfile(0), &test_url_loader_factory_, "user@email.com");
ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
// Let the user opt in to the passwords account storage, and wait for it to
// become active.
password_manager_util::SetAccountStorageOptIn(GetProfile(0)->GetPrefs(),
GetSyncService(0), true);
PasswordSyncActiveChecker(GetSyncService(0)).Wait();
ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS));
// Part 1: Save a password; it should go into the account store by default.
{
// Navigate to a page with a password form.
NavigateToFile(web_contents, "/password/password_form.html");
// Fill out and submit the password form.
NavigationObserver observer(web_contents);
std::string fill_and_submit =
"document.getElementById('username_field').value = 'accountuser';"
"document.getElementById('password_field').value = 'accountpass';"
"document.getElementById('input_submit_button').click()";
ASSERT_TRUE(content::ExecJs(web_contents, fill_and_submit));
observer.Wait();
// Save the password and check the store.
BubbleObserver bubble_observer(web_contents);
ASSERT_TRUE(bubble_observer.IsSavePromptShownAutomatically());
bubble_observer.AcceptSavePrompt();
std::vector<std::unique_ptr<autofill::PasswordForm>> account_credentials =
GetAllLoginsFromAccountPasswordStore();
EXPECT_THAT(account_credentials,
ElementsAre(MatchesLogin("accountuser", "accountpass")));
}
// Part 2: Mimic the user choosing to save locally; now a newly saved password
// should end up in the profile store.
password_manager_util::SetDefaultPasswordStore(
GetProfile(0)->GetPrefs(), GetSyncService(0),
autofill::PasswordForm::Store::kProfileStore);
{
// Navigate to a page with a password form.
// TODO(crbug.com/1058339): If we use the same URL as in part 1 here, then
// the test fails because the *account* data gets filled and submitted
// again. This is because the password manager is "smart" and prefers
// user-typed values (including autofilled-on-pageload ones) over
// script-provided values, see
// https://cs.chromium.org/chromium/src/components/autofill/content/renderer/form_autofill_util.cc?rcl=e38f0c99fe45ef81bd09d97f235c3dee64e2bd9f&l=1749
// and
// https://cs.chromium.org/chromium/src/components/autofill/content/renderer/password_autofill_agent.cc?rcl=63830d3f4b7f5fceec9609d83cf909d0cad04bb2&l=1855
// Some PasswordManager browser tests work around this by disabling
// autofill on pageload, see PasswordManagerBrowserTestWithAutofillDisabled.
// NavigateToFile(web_contents, "/password/password_form.html");
NavigateToFile(web_contents, "/password/simple_password.html");
// Fill out and submit the password form.
NavigationObserver observer(web_contents);
std::string fill_and_submit =
"document.getElementById('username_field').value = 'localuser';"
"document.getElementById('password_field').value = 'localpass';"
"document.getElementById('input_submit_button').click()";
ASSERT_TRUE(content::ExecJs(web_contents, fill_and_submit));
observer.Wait();
// Save the password and check the store.
BubbleObserver bubble_observer(web_contents);
ASSERT_TRUE(bubble_observer.IsSavePromptShownAutomatically());
bubble_observer.AcceptSavePrompt();
std::vector<std::unique_ptr<autofill::PasswordForm>> profile_credentials =
GetAllLoginsFromProfilePasswordStore();
EXPECT_THAT(profile_credentials,
ElementsAre(MatchesLogin("localuser", "localpass")));
}
}
#endif // !defined(OS_CHROMEOS)
} // namespace
...@@ -282,7 +282,8 @@ std::unique_ptr<views::Combobox> CreateDestinationCombobox( ...@@ -282,7 +282,8 @@ std::unique_ptr<views::Combobox> CreateDestinationCombobox(
else else
combobox->SetSelectedRow(1); combobox->SetSelectedRow(1);
// TODO(crbug.com/1044038): SetAccessibleName of the combobox. // TODO(crbug.com/1044038): Use an internationalized string instead.
combobox->SetAccessibleName(base::ASCIIToUTF16("Destination"));
return combobox; return combobox;
} }
......
...@@ -6282,6 +6282,7 @@ if (!is_fuchsia && !is_android) { ...@@ -6282,6 +6282,7 @@ if (!is_fuchsia && !is_android) {
"../browser/sync/test/integration/enable_disable_test.cc", "../browser/sync/test/integration/enable_disable_test.cc",
"../browser/sync/test/integration/local_sync_test.cc", "../browser/sync/test/integration/local_sync_test.cc",
"../browser/sync/test/integration/migration_test.cc", "../browser/sync/test/integration/migration_test.cc",
"../browser/sync/test/integration/password_manager_sync_test.cc",
"../browser/sync/test/integration/single_client_app_settings_sync_test.cc", "../browser/sync/test/integration/single_client_app_settings_sync_test.cc",
"../browser/sync/test/integration/single_client_apps_sync_test.cc", "../browser/sync/test/integration/single_client_apps_sync_test.cc",
"../browser/sync/test/integration/single_client_autofill_profile_sync_test.cc", "../browser/sync/test/integration/single_client_autofill_profile_sync_test.cc",
...@@ -6333,6 +6334,7 @@ if (!is_fuchsia && !is_android) { ...@@ -6333,6 +6334,7 @@ if (!is_fuchsia && !is_android) {
] ]
data = [ data = [
"//chrome/test/data/password/",
"//chrome/test/data/sync/", "//chrome/test/data/sync/",
"//net/tools/testserver/", "//net/tools/testserver/",
"//third_party/pywebsocket3/src/mod_pywebsocket/", "//third_party/pywebsocket3/src/mod_pywebsocket/",
......
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