blob: 4d46ff79e7fa7674b9e5f216cffe0bd819cf7e2a [file] [log] [blame]
// Copyright 2015 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 "chrome/browser/password_manager/save_password_infobar_delegate_android.h"
#include <memory>
#include <string>
#include <utility>
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/fake_form_fetcher.h"
#include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/stub_form_saver.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/browser/web_contents.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
using password_manager::PasswordFormMetricsRecorder;
namespace {
class MockPasswordFormManager : public password_manager::PasswordFormManager {
public:
MOCK_METHOD0(PermanentlyBlacklist, void());
MockPasswordFormManager(
password_manager::PasswordManager* password_manager,
password_manager::PasswordManagerClient* client,
base::WeakPtr<password_manager::PasswordManagerDriver> driver,
const autofill::PasswordForm& form,
password_manager::FormFetcher* form_fetcher)
: PasswordFormManager(password_manager,
client,
driver,
form,
std::make_unique<password_manager::StubFormSaver>(),
form_fetcher) {}
~MockPasswordFormManager() override {}
private:
DISALLOW_COPY_AND_ASSIGN(MockPasswordFormManager);
};
class TestSavePasswordInfoBarDelegate : public SavePasswordInfoBarDelegate {
public:
TestSavePasswordInfoBarDelegate(
content::WebContents* web_contents,
std::unique_ptr<password_manager::PasswordFormManager> form_to_save,
bool is_smartlock_branding_enabled)
: SavePasswordInfoBarDelegate(web_contents,
std::move(form_to_save),
is_smartlock_branding_enabled) {}
~TestSavePasswordInfoBarDelegate() override = default;
};
} // namespace
class SavePasswordInfoBarDelegateTest : public ChromeRenderViewHostTestHarness {
public:
SavePasswordInfoBarDelegateTest();
~SavePasswordInfoBarDelegateTest() override {}
void SetUp() override;
void TearDown() override;
PrefService* prefs();
const autofill::PasswordForm& test_form() { return test_form_; }
std::unique_ptr<MockPasswordFormManager> CreateMockFormManager(
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder,
bool with_federation_origin);
protected:
std::unique_ptr<PasswordManagerInfoBarDelegate> CreateDelegate(
std::unique_ptr<password_manager::PasswordFormManager>
password_form_manager,
bool is_smartlock_branding_enabled);
password_manager::StubPasswordManagerClient client_;
password_manager::StubPasswordManagerDriver driver_;
password_manager::PasswordManager password_manager_;
autofill::PasswordForm test_form_;
private:
password_manager::FakeFormFetcher fetcher_;
DISALLOW_COPY_AND_ASSIGN(SavePasswordInfoBarDelegateTest);
};
SavePasswordInfoBarDelegateTest::SavePasswordInfoBarDelegateTest()
: password_manager_(&client_) {
test_form_.origin = GURL("https://example.com");
test_form_.username_value = base::ASCIIToUTF16("username");
test_form_.password_value = base::ASCIIToUTF16("12345");
}
PrefService* SavePasswordInfoBarDelegateTest::prefs() {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
return profile->GetPrefs();
}
std::unique_ptr<MockPasswordFormManager>
SavePasswordInfoBarDelegateTest::CreateMockFormManager(
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder,
bool with_federation_origin) {
auto password_form = test_form();
if (with_federation_origin) {
password_form.federation_origin =
url::Origin::Create(GURL("https://example.com"));
}
auto manager = std::make_unique<MockPasswordFormManager>(
&password_manager_, &client_, driver_.AsWeakPtr(), password_form,
&fetcher_);
manager->Init(metrics_recorder);
manager->ProvisionallySave(password_form);
return manager;
}
std::unique_ptr<PasswordManagerInfoBarDelegate>
SavePasswordInfoBarDelegateTest::CreateDelegate(
std::unique_ptr<password_manager::PasswordFormManager>
password_form_manager,
bool is_smartlock_branding_enabled) {
std::unique_ptr<PasswordManagerInfoBarDelegate> delegate(
new TestSavePasswordInfoBarDelegate(web_contents(),
std::move(password_form_manager),
is_smartlock_branding_enabled));
return delegate;
}
void SavePasswordInfoBarDelegateTest::SetUp() {
ChromeRenderViewHostTestHarness::SetUp();
}
void SavePasswordInfoBarDelegateTest::TearDown() {
ChromeRenderViewHostTestHarness::TearDown();
}
TEST_F(SavePasswordInfoBarDelegateTest, CancelTest) {
std::unique_ptr<MockPasswordFormManager> password_form_manager(
CreateMockFormManager(nullptr, false /* with_federation_origin */));
EXPECT_CALL(*password_form_manager.get(), PermanentlyBlacklist());
std::unique_ptr<ConfirmInfoBarDelegate> infobar(
CreateDelegate(std::move(password_form_manager),
true /* is_smartlock_branding_enabled */));
EXPECT_TRUE(infobar->Cancel());
}
TEST_F(SavePasswordInfoBarDelegateTest, HasDetailsMessageWhenSyncing) {
std::unique_ptr<MockPasswordFormManager> password_form_manager(
CreateMockFormManager(nullptr, false /* with_federation_origin */));
std::unique_ptr<PasswordManagerInfoBarDelegate> infobar(
CreateDelegate(std::move(password_form_manager),
true /* is_smartlock_branding_enabled */));
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD_FOOTER),
infobar->GetDetailsMessageText());
}
TEST_F(SavePasswordInfoBarDelegateTest, EmptyDetailsMessageWhenNotSyncing) {
std::unique_ptr<MockPasswordFormManager> password_form_manager(
CreateMockFormManager(nullptr, false /* with_federation_origin */));
std::unique_ptr<PasswordManagerInfoBarDelegate> infobar(
CreateDelegate(std::move(password_form_manager),
false /* is_smartlock_branding_enabled */));
EXPECT_TRUE(infobar->GetDetailsMessageText().empty());
}
TEST_F(SavePasswordInfoBarDelegateTest,
EmptyDetailsMessageForFederatedCredentialsWhenSyncing) {
std::unique_ptr<MockPasswordFormManager> password_form_manager(
CreateMockFormManager(nullptr, true /* with_federation_origin */));
NavigateAndCommit(GURL("https://example.com"));
std::unique_ptr<PasswordManagerInfoBarDelegate> infobar(
CreateDelegate(std::move(password_form_manager),
true /* is_smartlock_branding_enabled */));
EXPECT_TRUE(infobar->GetDetailsMessageText().empty());
}
TEST_F(SavePasswordInfoBarDelegateTest,
EmptyDetailsMessageForFederatedCredentialsWhenNotSyncing) {
std::unique_ptr<MockPasswordFormManager> password_form_manager(
CreateMockFormManager(nullptr, true /* with_federation_origin */));
NavigateAndCommit(GURL("https://example.com"));
std::unique_ptr<PasswordManagerInfoBarDelegate> infobar(
CreateDelegate(std::move(password_form_manager),
false /* is_smartlock_branding_enabled */));
EXPECT_TRUE(infobar->GetDetailsMessageText().empty());
}
class SavePasswordInfoBarDelegateTestForUKMs
: public SavePasswordInfoBarDelegateTest,
public ::testing::WithParamInterface<
PasswordFormMetricsRecorder::BubbleDismissalReason> {
public:
SavePasswordInfoBarDelegateTestForUKMs() = default;
~SavePasswordInfoBarDelegateTestForUKMs() = default;
};
// Verify that URL keyed metrics are recorded for showing and interacting with
// the password save prompt.
TEST_P(SavePasswordInfoBarDelegateTestForUKMs, VerifyUKMRecording) {
using BubbleTrigger = PasswordFormMetricsRecorder::BubbleTrigger;
using BubbleDismissalReason =
PasswordFormMetricsRecorder::BubbleDismissalReason;
using UkmEntry = ukm::builders::PasswordForm;
BubbleDismissalReason dismissal_reason = GetParam();
SCOPED_TRACE(::testing::Message() << "dismissal_reason = "
<< static_cast<int64_t>(dismissal_reason));
ukm::SourceId expected_source_id = ukm::UkmRecorder::GetNewSourceID();
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
// Setup metrics recorder
auto recorder = base::MakeRefCounted<PasswordFormMetricsRecorder>(
true /*is_main_frame_secure*/, expected_source_id);
// Exercise delegate.
std::unique_ptr<MockPasswordFormManager> password_form_manager(
CreateMockFormManager(recorder, false /* with_federation_origin */));
if (dismissal_reason == BubbleDismissalReason::kDeclined)
EXPECT_CALL(*password_form_manager.get(), PermanentlyBlacklist());
std::unique_ptr<ConfirmInfoBarDelegate> infobar(
CreateDelegate(std::move(password_form_manager),
true /* is_smartlock_branding_enabled */));
switch (dismissal_reason) {
case BubbleDismissalReason::kAccepted:
EXPECT_TRUE(infobar->Accept());
break;
case BubbleDismissalReason::kDeclined:
EXPECT_TRUE(infobar->Cancel());
break;
case BubbleDismissalReason::kIgnored:
// Do nothing.
break;
case BubbleDismissalReason::kUnknown:
NOTREACHED();
break;
}
}
// Verify metrics.
const auto& entries =
test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* entry : entries) {
EXPECT_EQ(expected_source_id, entry->source_id);
test_ukm_recorder.ExpectEntryMetric(entry,
UkmEntry::kSaving_Prompt_ShownName, 1);
test_ukm_recorder.ExpectEntryMetric(
entry, UkmEntry::kSaving_Prompt_TriggerName,
static_cast<int64_t>(
BubbleTrigger::kPasswordManagerSuggestionAutomatic));
test_ukm_recorder.ExpectEntryMetric(
entry, UkmEntry::kSaving_Prompt_InteractionName,
static_cast<int64_t>(dismissal_reason));
}
}
INSTANTIATE_TEST_SUITE_P(
/*no extra name*/,
SavePasswordInfoBarDelegateTestForUKMs,
::testing::Values(
PasswordFormMetricsRecorder::BubbleDismissalReason::kAccepted,
PasswordFormMetricsRecorder::BubbleDismissalReason::kDeclined,
PasswordFormMetricsRecorder::BubbleDismissalReason::kIgnored));