// Copyright (c) 2012 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 #include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "base/time.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autocheckout_infobar_delegate.h" #include "chrome/browser/autofill/autocheckout_page_meta_data.h" #include "chrome/browser/autofill/autofill_cc_infobar_delegate.h" #include "chrome/browser/autofill/autofill_common_test.h" #include "chrome/browser/autofill/autofill_manager.h" #include "chrome/browser/autofill/autofill_manager_delegate.h" #include "chrome/browser/autofill/autofill_metrics.h" #include "chrome/browser/autofill/personal_data_manager.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/form_data.h" #include "chrome/common/form_field_data.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread.h" #include "googleurl/src/gurl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/rect.h" using content::BrowserThread; using ::testing::_; using ::testing::AnyNumber; using ::testing::Mock; using base::TimeTicks; using base::TimeDelta; namespace { class MockAutofillMetrics : public AutofillMetrics { public: MockAutofillMetrics() {} MOCK_CONST_METHOD1(LogCreditCardInfoBarMetric, void(InfoBarMetric metric)); MOCK_CONST_METHOD1(LogAutocheckoutInfoBarMetric, void(InfoBarMetric metric)); MOCK_CONST_METHOD1(LogDeveloperEngagementMetric, void(DeveloperEngagementMetric metric)); MOCK_CONST_METHOD3(LogHeuristicTypePrediction, void(FieldTypeQualityMetric metric, AutofillFieldType field_type, const std::string& experiment_id)); MOCK_CONST_METHOD3(LogOverallTypePrediction, void(FieldTypeQualityMetric metric, AutofillFieldType field_type, const std::string& experiment_id)); MOCK_CONST_METHOD3(LogServerTypePrediction, void(FieldTypeQualityMetric metric, AutofillFieldType field_type, const std::string& experiment_id)); MOCK_CONST_METHOD2(LogQualityMetric, void(QualityMetric metric, const std::string& experiment_id)); MOCK_CONST_METHOD1(LogServerQueryMetric, void(ServerQueryMetric metric)); MOCK_CONST_METHOD1(LogUserHappinessMetric, void(UserHappinessMetric metric)); MOCK_CONST_METHOD1(LogFormFillDurationFromLoadWithAutofill, void(const TimeDelta& duration)); MOCK_CONST_METHOD1(LogFormFillDurationFromLoadWithoutAutofill, void(const TimeDelta& duration)); MOCK_CONST_METHOD1(LogFormFillDurationFromInteractionWithAutofill, void(const TimeDelta& duration)); MOCK_CONST_METHOD1(LogFormFillDurationFromInteractionWithoutAutofill, void(const TimeDelta& duration)); MOCK_CONST_METHOD1(LogIsAutofillEnabledAtPageLoad, void(bool enabled)); MOCK_CONST_METHOD1(LogIsAutofillEnabledAtStartup, void(bool enabled)); MOCK_CONST_METHOD1(LogStoredProfileCount, void(size_t num_profiles)); MOCK_CONST_METHOD1(LogAddressSuggestionsCount, void(size_t num_suggestions)); MOCK_CONST_METHOD1(LogServerExperimentIdForQuery, void(const std::string& experiment_id)); MOCK_CONST_METHOD1(LogServerExperimentIdForUpload, void(const std::string& experiment_id)); private: DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics); }; class TestPersonalDataManager : public PersonalDataManager { public: TestPersonalDataManager() : autofill_enabled_(true) { set_metric_logger(new MockAutofillMetrics); CreateTestAutofillProfiles(&web_profiles_); } void SetBrowserContext(content::BrowserContext* context) { set_browser_context(context); } // Overridden to avoid a trip to the database. This should be a no-op except // for the side-effect of logging the profile count. virtual void LoadProfiles() OVERRIDE { std::vector profiles; web_profiles_.release(&profiles); WDResult > result(AUTOFILL_PROFILES_RESULT, profiles); ReceiveLoadedProfiles(0, &result); } // Overridden to avoid a trip to the database. virtual void LoadCreditCards() OVERRIDE {} const MockAutofillMetrics* metric_logger() const { return static_cast( PersonalDataManager::metric_logger()); } void set_autofill_enabled(bool autofill_enabled) { autofill_enabled_ = autofill_enabled; } virtual bool IsAutofillEnabled() const OVERRIDE { return autofill_enabled_; } MOCK_METHOD1(SaveImportedCreditCard, void(const CreditCard& imported_credit_card)); private: void CreateTestAutofillProfiles(ScopedVector* profiles) { AutofillProfile* profile = new AutofillProfile; autofill_test::SetProfileInfo(profile, "Elvis", "Aaron", "Presley", "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis", "Tennessee", "38116", "US", "12345678901"); profile->set_guid("00000000-0000-0000-0000-000000000001"); profiles->push_back(profile); profile = new AutofillProfile; autofill_test::SetProfileInfo(profile, "Charles", "Hardin", "Holley", "buddy@gmail.com", "Decca", "123 Apple St.", "unit 6", "Lubbock", "Texas", "79401", "US", "2345678901"); profile->set_guid("00000000-0000-0000-0000-000000000002"); profiles->push_back(profile); } bool autofill_enabled_; DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager); }; class TestFormStructure : public FormStructure { public: explicit TestFormStructure(const FormData& form) : FormStructure(form) {} virtual ~TestFormStructure() {} void SetFieldTypes(const std::vector& heuristic_types, const std::vector& server_types) { ASSERT_EQ(field_count(), heuristic_types.size()); ASSERT_EQ(field_count(), server_types.size()); for (size_t i = 0; i < field_count(); ++i) { AutofillField* form_field = field(i); ASSERT_TRUE(form_field); form_field->set_heuristic_type(heuristic_types[i]); form_field->set_server_type(server_types[i]); } UpdateAutofillCount(); } virtual std::string server_experiment_id() const OVERRIDE { return server_experiment_id_; } void set_server_experiment_id(const std::string& server_experiment_id) { server_experiment_id_ = server_experiment_id; } private: std::string server_experiment_id_; DISALLOW_COPY_AND_ASSIGN(TestFormStructure); }; class TestAutofillManager : public AutofillManager { public: TestAutofillManager(content::WebContents* web_contents, autofill::AutofillManagerDelegate* manager_delegate, TestPersonalDataManager* personal_manager) : AutofillManager(web_contents, manager_delegate, personal_manager), autofill_enabled_(true), did_finish_async_form_submit_(false), message_loop_is_running_(false) { set_metric_logger(new MockAutofillMetrics); } virtual bool IsAutofillEnabled() const { return autofill_enabled_; } void set_autofill_enabled(bool autofill_enabled) { autofill_enabled_ = autofill_enabled; } MockAutofillMetrics* metric_logger() { return static_cast(const_cast( AutofillManager::metric_logger())); } void AddSeenForm(const FormData& form, const std::vector& heuristic_types, const std::vector& server_types, const std::string& experiment_id) { FormData empty_form = form; for (size_t i = 0; i < empty_form.fields.size(); ++i) { empty_form.fields[i].value = string16(); } // |form_structure| will be owned by |form_structures()|. TestFormStructure* form_structure = new TestFormStructure(empty_form); form_structure->SetFieldTypes(heuristic_types, server_types); form_structure->set_server_experiment_id(experiment_id); form_structures()->push_back(form_structure); } void FormSubmitted(const FormData& form, const TimeTicks& timestamp) { if (!OnFormSubmitted(form, timestamp)) return; // Wait for the asynchronous FormSubmitted() call to complete. if (!did_finish_async_form_submit_) { // TODO(isherman): It seems silly to need this variable. Is there some // way I can just query the message loop's state? message_loop_is_running_ = true; MessageLoop::current()->Run(); } else { did_finish_async_form_submit_ = false; } } virtual void UploadFormDataAsyncCallback( const FormStructure* submitted_form, const base::TimeTicks& load_time, const base::TimeTicks& interaction_time, const base::TimeTicks& submission_time) OVERRIDE { if (message_loop_is_running_) { MessageLoop::current()->Quit(); message_loop_is_running_ = false; } else { did_finish_async_form_submit_ = true; } AutofillManager::UploadFormDataAsyncCallback(submitted_form, load_time, interaction_time, submission_time); } private: // AutofillManager is ref counted. virtual ~TestAutofillManager() {} bool autofill_enabled_; bool did_finish_async_form_submit_; bool message_loop_is_running_; DISALLOW_COPY_AND_ASSIGN(TestAutofillManager); }; class TestAutocheckoutManager : public AutocheckoutManager { public: explicit TestAutocheckoutManager(AutofillManager* autofill_manager) : AutocheckoutManager(autofill_manager) { } virtual void ShowAutocheckoutDialog( const GURL& frame_url, const content::SSLStatus& ssl_status) OVERRIDE { // no-op. Just used as callback from autocheckout_infobar_delegate. } virtual ~TestAutocheckoutManager() { } private: DISALLOW_COPY_AND_ASSIGN(TestAutocheckoutManager); }; } // namespace class AutofillMetricsTest : public ChromeRenderViewHostTestHarness { public: AutofillMetricsTest(); virtual ~AutofillMetricsTest(); virtual void SetUp() OVERRIDE; virtual void TearDown() OVERRIDE; protected: scoped_ptr CreateDelegate( MockAutofillMetrics* metric_logger, CreditCard** created_card); scoped_ptr CreateAutocheckoutDelegate( MockAutofillMetrics* metric_logger); content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; scoped_refptr autofill_manager_; TestAutocheckoutManager autocheckout_manager_; TestPersonalDataManager personal_data_; private: std::string default_gmock_verbosity_level_; DISALLOW_COPY_AND_ASSIGN(AutofillMetricsTest); }; AutofillMetricsTest::AutofillMetricsTest() : ChromeRenderViewHostTestHarness(), ui_thread_(BrowserThread::UI, &message_loop_), file_thread_(BrowserThread::FILE), autocheckout_manager_(NULL) { } AutofillMetricsTest::~AutofillMetricsTest() { // Order of destruction is important as AutofillManager relies on // PersonalDataManager to be around when it gets destroyed. autofill_manager_ = NULL; } void AutofillMetricsTest::SetUp() { Profile* profile = new TestingProfile(); browser_context_.reset(profile); PersonalDataManagerFactory::GetInstance()->SetTestingFactory(profile, NULL); ChromeRenderViewHostTestHarness::SetUp(); TabAutofillManagerDelegate::CreateForWebContents(web_contents()); personal_data_.SetBrowserContext(profile); autofill_manager_ = new TestAutofillManager( web_contents(), TabAutofillManagerDelegate::FromWebContents(web_contents()), &personal_data_); file_thread_.Start(); // Ignore any metrics that we haven't explicitly set expectations for. // If we don't override the verbosity level, we'll get lots of log spew from // mocked functions that aren't relevant to a test but happen to be called // during the test's execution. // CAUTION: This is a global variable. So as to not affect other tests, this // _must_ be restored to its original value at the end of the test. default_gmock_verbosity_level_ = ::testing::FLAGS_gmock_verbose; ::testing::FLAGS_gmock_verbose = "error"; } void AutofillMetricsTest::TearDown() { // Restore the global Gmock verbosity level to its default value. ::testing::FLAGS_gmock_verbose = default_gmock_verbosity_level_; // Order of destruction is important as AutofillManager relies on // PersonalDataManager to be around when it gets destroyed. Also, a real // AutofillManager is tied to the lifetime of the WebContents, so it must // be destroyed at the destruction of the WebContents. autofill_manager_ = NULL; file_thread_.Stop(); ChromeRenderViewHostTestHarness::TearDown(); } scoped_ptr AutofillMetricsTest::CreateDelegate( MockAutofillMetrics* metric_logger, CreditCard** created_card) { EXPECT_CALL(*metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_SHOWN)); // The delegate created below will take ownership of this object. CreditCard* credit_card = new CreditCard(); if (created_card) *created_card = credit_card; return AutofillCCInfoBarDelegate::Create(credit_card, &personal_data_, metric_logger); } scoped_ptr AutofillMetricsTest::CreateAutocheckoutDelegate( MockAutofillMetrics* metric_logger) { EXPECT_CALL(*metric_logger, LogAutocheckoutInfoBarMetric(AutofillMetrics::INFOBAR_SHOWN)); GURL url("www.google.com"); content::SSLStatus ssl_status; return AutocheckoutInfoBarDelegate::Create( *metric_logger, url, ssl_status, &autocheckout_manager_); } // Test that we log quality metrics appropriately. TEST_F(AutofillMetricsTest, QualityMetrics) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); form.method = ASCIIToUTF16("POST"); form.origin = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.user_submitted = true; std::vector heuristic_types, server_types; FormFieldData field; autofill_test::CreateTestFormField( "Autofilled", "autofilled", "Elvis Aaron Presley", "text", &field); field.is_autofilled = true; form.fields.push_back(field); heuristic_types.push_back(NAME_FULL); server_types.push_back(NAME_FIRST); autofill_test::CreateTestFormField( "Autofill Failed", "autofillfailed", "buddy@gmail.com", "text", &field); field.is_autofilled = false; form.fields.push_back(field); heuristic_types.push_back(PHONE_HOME_NUMBER); server_types.push_back(EMAIL_ADDRESS); autofill_test::CreateTestFormField( "Empty", "empty", "", "text", &field); field.is_autofilled = false; form.fields.push_back(field); heuristic_types.push_back(NAME_FULL); server_types.push_back(NAME_FIRST); autofill_test::CreateTestFormField( "Unknown", "unknown", "garbage", "text", &field); field.is_autofilled = false; form.fields.push_back(field); heuristic_types.push_back(PHONE_HOME_NUMBER); server_types.push_back(EMAIL_ADDRESS); autofill_test::CreateTestFormField( "Select", "select", "USA", "select-one", &field); field.is_autofilled = false; form.fields.push_back(field); heuristic_types.push_back(UNKNOWN_TYPE); server_types.push_back(NO_SERVER_DATA); autofill_test::CreateTestFormField( "Phone", "phone", "2345678901", "tel", &field); field.is_autofilled = true; form.fields.push_back(field); heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER); server_types.push_back(PHONE_HOME_WHOLE_NUMBER); // Simulate having seen this form on page load. autofill_manager_->AddSeenForm(form, heuristic_types, server_types, std::string()); // Establish our expectations. ::testing::InSequence dummy; EXPECT_CALL(*autofill_manager_->metric_logger(), LogServerExperimentIdForUpload(std::string())); // Autofilled field EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogHeuristicTypePrediction(AutofillMetrics::TYPE_MATCH, NAME_FULL, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogServerTypePrediction(AutofillMetrics::TYPE_MISMATCH, NAME_FULL, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogOverallTypePrediction(AutofillMetrics::TYPE_MISMATCH, NAME_FULL, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_AUTOFILLED, std::string())); // Non-autofilled field for which we had data EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogHeuristicTypePrediction(AutofillMetrics::TYPE_MISMATCH, EMAIL_ADDRESS, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogServerTypePrediction(AutofillMetrics::TYPE_MATCH, EMAIL_ADDRESS, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogOverallTypePrediction(AutofillMetrics::TYPE_MATCH, EMAIL_ADDRESS, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_NOT_AUTOFILLED, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric( AutofillMetrics::NOT_AUTOFILLED_HEURISTIC_TYPE_MISMATCH, std::string())); EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric( AutofillMetrics::NOT_AUTOFILLED_SERVER_TYPE_MATCH, std::string())); // Empty field EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, std::string())); // Unknown field EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, std::string())); // field EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, experiment_id)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN, ADDRESS_HOME_COUNTRY, experiment_id)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogServerTypePrediction(AutofillMetrics::TYPE_UNKNOWN, ADDRESS_HOME_COUNTRY, experiment_id)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogOverallTypePrediction(AutofillMetrics::TYPE_UNKNOWN, ADDRESS_HOME_COUNTRY, experiment_id)); // Simulate form submission. EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, TimeTicks::Now())); } // Test that the profile count is logged correctly. TEST_F(AutofillMetricsTest, StoredProfileCount) { // The metric should be logged when the profiles are first loaded. EXPECT_CALL(*personal_data_.metric_logger(), LogStoredProfileCount(2)).Times(1); personal_data_.LoadProfiles(); // The metric should only be logged once. EXPECT_CALL(*personal_data_.metric_logger(), LogStoredProfileCount(::testing::_)).Times(0); personal_data_.LoadProfiles(); } // Test that we correctly log whether Autofill is enabled. TEST_F(AutofillMetricsTest, AutofillIsEnabledAtStartup) { personal_data_.set_autofill_enabled(true); EXPECT_CALL(*personal_data_.metric_logger(), LogIsAutofillEnabledAtStartup(true)).Times(1); personal_data_.Init(profile()); personal_data_.Shutdown(); personal_data_.set_autofill_enabled(false); EXPECT_CALL(*personal_data_.metric_logger(), LogIsAutofillEnabledAtStartup(false)).Times(1); personal_data_.Init(profile()); } // Test that we log the number of Autofill suggestions when filling a form. TEST_F(AutofillMetricsTest, AddressSuggestionsCount) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); form.method = ASCIIToUTF16("POST"); form.origin = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.user_submitted = true; FormFieldData field; std::vector field_types; autofill_test::CreateTestFormField("Name", "name", "", "text", &field); form.fields.push_back(field); field_types.push_back(NAME_FULL); autofill_test::CreateTestFormField("Email", "email", "", "email", &field); form.fields.push_back(field); field_types.push_back(EMAIL_ADDRESS); autofill_test::CreateTestFormField("Phone", "phone", "", "tel", &field); form.fields.push_back(field); field_types.push_back(PHONE_HOME_NUMBER); // Simulate having seen this form on page load. // |form_structure| will be owned by |autofill_manager_|. autofill_manager_->AddSeenForm(form, field_types, field_types, std::string()); // Establish our expectations. ::testing::InSequence dummy; EXPECT_CALL(*autofill_manager_->metric_logger(), LogAddressSuggestionsCount(2)).Times(1); // Simulate activating the autofill popup for the phone field. autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::Rect(), false); // Simulate activating the autofill popup for the email field after typing. // No new metric should be logged, since we're still on the same page. autofill_test::CreateTestFormField("Email", "email", "b", "email", &field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::Rect(), false); // Reset the autofill manager state. autofill_manager_->Reset(); autofill_manager_->AddSeenForm(form, field_types, field_types, std::string()); // Establish our expectations. EXPECT_CALL(*autofill_manager_->metric_logger(), LogAddressSuggestionsCount(1)).Times(1); // Simulate activating the autofill popup for the email field after typing. autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::Rect(), false); // Reset the autofill manager state again. autofill_manager_->Reset(); autofill_manager_->AddSeenForm(form, field_types, field_types, std::string()); // Establish our expectations. EXPECT_CALL(*autofill_manager_->metric_logger(), LogAddressSuggestionsCount(::testing::_)).Times(0); // Simulate activating the autofill popup for the email field after typing. form.fields[0].is_autofilled = true; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::Rect(), false); } // Test that we log whether Autofill is enabled when filling a form. TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) { // Establish our expectations. ::testing::InSequence dummy; EXPECT_CALL(*autofill_manager_->metric_logger(), LogIsAutofillEnabledAtPageLoad(true)).Times(1); autofill_manager_->set_autofill_enabled(true); autofill_manager_->OnFormsSeen(std::vector(), TimeTicks()); // Reset the autofill manager state. autofill_manager_->Reset(); // Establish our expectations. EXPECT_CALL(*autofill_manager_->metric_logger(), LogIsAutofillEnabledAtPageLoad(false)).Times(1); autofill_manager_->set_autofill_enabled(false); autofill_manager_->OnFormsSeen(std::vector(), TimeTicks()); } // Test that credit card infobar metrics are logged correctly. TEST_F(AutofillMetricsTest, CreditCardInfoBar) { MockAutofillMetrics metric_logger; ::testing::InSequence dummy; // Accept the infobar. { CreditCard* credit_card; scoped_ptr infobar(CreateDelegate(&metric_logger, &credit_card)); ASSERT_TRUE(infobar); EXPECT_CALL(personal_data_, SaveImportedCreditCard(*credit_card)); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_ACCEPTED)).Times(1); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_IGNORED)).Times(0); EXPECT_TRUE(infobar->Accept()); } // Cancel the infobar. { scoped_ptr infobar(CreateDelegate(&metric_logger, NULL)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_DENIED)).Times(1); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_IGNORED)).Times(0); EXPECT_TRUE(infobar->Cancel()); } // Dismiss the infobar. { scoped_ptr infobar(CreateDelegate(&metric_logger, NULL)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_DENIED)).Times(1); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_IGNORED)).Times(0); infobar->InfoBarDismissed(); } // Ignore the infobar. { scoped_ptr infobar(CreateDelegate(&metric_logger, NULL)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_IGNORED)).Times(1); } } // Test that autofill flow infobar metrics are logged correctly. TEST_F(AutofillMetricsTest, AutocheckoutInfoBar) { MockAutofillMetrics metric_logger; ::testing::InSequence dummy; // Accept the infobar. { scoped_ptr infobar( CreateAutocheckoutDelegate(&metric_logger)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_ACCEPTED)).Times(1); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_IGNORED)).Times(0); EXPECT_TRUE(infobar->Accept()); } // Cancel the infobar. { scoped_ptr infobar( CreateAutocheckoutDelegate(&metric_logger)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_DENIED)).Times(1); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_IGNORED)).Times(0); EXPECT_TRUE(infobar->Cancel()); } // Dismiss the infobar. { scoped_ptr infobar( CreateAutocheckoutDelegate(&metric_logger)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_DENIED)).Times(1); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_IGNORED)).Times(0); infobar->InfoBarDismissed(); } // Ignore the infobar. { scoped_ptr infobar( CreateAutocheckoutDelegate(&metric_logger)); ASSERT_TRUE(infobar); EXPECT_CALL(metric_logger, LogAutocheckoutInfoBarMetric( AutofillMetrics::INFOBAR_IGNORED)).Times(1); } } // Test that server query response experiment id metrics are logged correctly. TEST_F(AutofillMetricsTest, ServerQueryExperimentIdForQuery) { MockAutofillMetrics metric_logger; ::testing::InSequence dummy; // No experiment specified. EXPECT_CALL(metric_logger, LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_RECEIVED)); EXPECT_CALL(metric_logger, LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED)); EXPECT_CALL(metric_logger, LogServerExperimentIdForQuery(std::string())); EXPECT_CALL(metric_logger, LogServerQueryMetric( AutofillMetrics::QUERY_RESPONSE_MATCHED_LOCAL_HEURISTICS)); autofill::AutocheckoutPageMetaData page_meta_data; FormStructure::ParseQueryResponse( "", std::vector(), &page_meta_data, metric_logger); // Experiment "ar1" specified. EXPECT_CALL(metric_logger, LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_RECEIVED)); EXPECT_CALL(metric_logger, LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED)); EXPECT_CALL(metric_logger, LogServerExperimentIdForQuery("ar1")); EXPECT_CALL(metric_logger, LogServerQueryMetric( AutofillMetrics::QUERY_RESPONSE_MATCHED_LOCAL_HEURISTICS)); FormStructure::ParseQueryResponse( "", std::vector(), &page_meta_data, metric_logger); } // Verify that we correctly log user happiness metrics dealing with form loading // and form submission. TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { // Start with a form with insufficiently many fields. FormData form; form.name = ASCIIToUTF16("TestForm"); form.method = ASCIIToUTF16("POST"); form.origin = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.user_submitted = true; FormFieldData field; autofill_test::CreateTestFormField("Name", "name", "", "text", &field); form.fields.push_back(field); autofill_test::CreateTestFormField("Email", "email", "", "text", &field); form.fields.push_back(field); std::vector forms(1, form); // Expect no notifications when the form is first seen. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED)).Times(0); autofill_manager_->OnFormsSeen(forms, TimeTicks()); } // Expect no notifications when the form is submitted. { EXPECT_CALL( *autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_ALL)).Times(0); EXPECT_CALL( *autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME)).Times(0); EXPECT_CALL( *autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_NONE)).Times(0); EXPECT_CALL( *autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)).Times(0); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Add more fields to the form. autofill_test::CreateTestFormField("Phone", "phone", "", "text", &field); form.fields.push_back(field); autofill_test::CreateTestFormField("Unknown", "unknown", "", "text", &field); form.fields.push_back(field); forms.front() = form; // Expect a notification when the form is first seen. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED)); autofill_manager_->OnFormsSeen(forms, TimeTicks()); } // Expect a notification when the form is submitted. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Fill in two of the fields. form.fields[0].value = ASCIIToUTF16("Elvis Aaron Presley"); form.fields[1].value = ASCIIToUTF16("theking@gmail.com"); forms.front() = form; // Expect a notification when the form is submitted. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Fill in the third field. form.fields[2].value = ASCIIToUTF16("12345678901"); forms.front() = form; // Expect notifications when the form is submitted. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_NONE)); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Mark one of the fields as autofilled. form.fields[1].is_autofilled = true; forms.front() = form; // Expect notifications when the form is submitted. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME)); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Mark all of the fillable fields as autofilled. form.fields[0].is_autofilled = true; form.fields[2].is_autofilled = true; forms.front() = form; // Expect notifications when the form is submitted. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_ALL)); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Clear out the third field's value. form.fields[2].value = string16(); forms.front() = form; // Expect notifications when the form is submitted. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)); autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } } // Verify that we correctly log user happiness metrics dealing with form // interaction. TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); form.method = ASCIIToUTF16("POST"); form.origin = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.user_submitted = true; FormFieldData field; autofill_test::CreateTestFormField("Name", "name", "", "text", &field); form.fields.push_back(field); autofill_test::CreateTestFormField("Email", "email", "", "text", &field); form.fields.push_back(field); autofill_test::CreateTestFormField("Phone", "phone", "", "text", &field); form.fields.push_back(field); std::vector forms(1, form); // Expect a notification when the form is first seen. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED)); autofill_manager_->OnFormsSeen(forms, TimeTicks()); } // Simulate typing. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE)); autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks()); } // Simulate suggestions shown twice for a single edit (i.e. multiple // keystrokes in a single field). { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUGGESTIONS_SHOWN)).Times(1); EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUGGESTIONS_SHOWN_ONCE)).Times(1); autofill_manager_->OnDidShowAutofillSuggestions(true); autofill_manager_->OnDidShowAutofillSuggestions(false); } // Simulate suggestions shown for a different field. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUGGESTIONS_SHOWN_ONCE)).Times(0); autofill_manager_->OnDidShowAutofillSuggestions(true); } // Simulate invoking autofill. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::USER_DID_AUTOFILL_ONCE)); autofill_manager_->OnDidFillAutofillFormData(TimeTicks()); } // Simulate editing an autofilled field. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE)); PersonalDataManager::GUIDPair guid( "00000000-0000-0000-0000-000000000001", 0); PersonalDataManager::GUIDPair empty(std::string(), 0); autofill_manager_->OnFillAutofillFormData( 0, form, form.fields.front(), autofill_manager_->PackGUIDs(empty, guid)); autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks()); // Simulate a second keystroke; make sure we don't log the metric twice. autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks()); } // Simulate invoking autofill again. EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL)); EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::USER_DID_AUTOFILL_ONCE)).Times(0); autofill_manager_->OnDidFillAutofillFormData(TimeTicks()); // Simulate editing another autofilled field. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD)); autofill_manager_->OnTextFieldDidChange(form, form.fields[1], TimeTicks()); } } // Verify that we correctly log metrics tracking the duration of form fill. TEST_F(AutofillMetricsTest, FormFillDuration) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); form.method = ASCIIToUTF16("POST"); form.origin = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.user_submitted = true; FormFieldData field; autofill_test::CreateTestFormField("Name", "name", "", "text", &field); form.fields.push_back(field); autofill_test::CreateTestFormField("Email", "email", "", "text", &field); form.fields.push_back(field); autofill_test::CreateTestFormField("Phone", "phone", "", "text", &field); form.fields.push_back(field); std::vector forms(1, form); // Fill the field values for form submission. form.fields[0].value = ASCIIToUTF16("Elvis Aaron Presley"); form.fields[1].value = ASCIIToUTF16("theking@gmail.com"); form.fields[2].value = ASCIIToUTF16("12345678901"); // Expect only form load metrics to be logged if the form is submitted without // user interaction. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithAutofill(_)).Times(0); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithoutAutofill( TimeDelta::FromInternalValue(16))); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithAutofill(_)).Times(0); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0); autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } // Expect metric to be logged if the user manually edited a form field. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithAutofill(_)).Times(0); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithoutAutofill( TimeDelta::FromInternalValue(16))); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithAutofill(_)).Times(0); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithoutAutofill( TimeDelta::FromInternalValue(14))); autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks::FromInternalValue(3)); autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } // Expect metric to be logged if the user autofilled the form. form.fields[0].is_autofilled = true; { EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithAutofill( TimeDelta::FromInternalValue(16))); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithoutAutofill(_)).Times(0); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithAutofill( TimeDelta::FromInternalValue(12))); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0); autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); autofill_manager_->OnDidFillAutofillFormData( TimeTicks::FromInternalValue(5)); autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } // Expect metric to be logged if the user both manually filled some fields // and autofilled others. Messages can arrive out of order, so make sure they // take precedence appropriately. { EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithAutofill( TimeDelta::FromInternalValue(16))); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromLoadWithoutAutofill(_)).Times(0); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithAutofill( TimeDelta::FromInternalValue(14))); EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0); autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); autofill_manager_->OnDidFillAutofillFormData( TimeTicks::FromInternalValue(5)); autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks::FromInternalValue(3)); autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } }