diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/components/autofill | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/autofill')
243 files changed, 9243 insertions, 4088 deletions
diff --git a/chromium/components/autofill/OWNERS b/chromium/components/autofill/OWNERS index 04b0d2f9b7b..f1fa6a5c923 100644 --- a/chromium/components/autofill/OWNERS +++ b/chromium/components/autofill/OWNERS @@ -4,6 +4,5 @@ ftirelo@chromium.org mahmadi@chromium.org rogerm@chromium.org sebsg@chromium.org -vabr@chromium.org # COMPONENT: UI>Browser>Autofill diff --git a/chromium/components/autofill/android/autofill_provider_android.cc b/chromium/components/autofill/android/autofill_provider_android.cc index a930d663e0e..a08b4a3688f 100644 --- a/chromium/components/autofill/android/autofill_provider_android.cc +++ b/chromium/components/autofill/android/autofill_provider_android.cc @@ -174,8 +174,7 @@ void AutofillProviderAndroid::FireSuccessfulSubmission( void AutofillProviderAndroid::OnFormSubmitted(AutofillHandlerProxy* handler, const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) { + SubmissionSource source) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!IsCurrentlyLinkedHandler(handler) || !IsCurrentlyLinkedForm(form)) return; diff --git a/chromium/components/autofill/android/autofill_provider_android.h b/chromium/components/autofill/android/autofill_provider_android.h index 0cc29ac8c5a..457be941ebc 100644 --- a/chromium/components/autofill/android/autofill_provider_android.h +++ b/chromium/components/autofill/android/autofill_provider_android.h @@ -49,8 +49,7 @@ class AutofillProviderAndroid : public AutofillProvider { void OnFormSubmitted(AutofillHandlerProxy* handler, const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) override; + SubmissionSource source) override; void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override; void OnFocusOnFormField(AutofillHandlerProxy* handler, const FormData& form, diff --git a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml index b97c548e22d..c36837ee342 100644 --- a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml +++ b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml @@ -26,7 +26,7 @@ android:includeFontPadding="false" android:singleLine="true" android:textAlignment="viewStart" - android:textAppearance="@style/BlackHint2" /> + android:textAppearance="@style/TextAppearance.BlackHint2" /> <ImageView android:id="@+id/dropdown_icon" diff --git a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml index 93512e2012a..5b0c93116dd 100644 --- a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml +++ b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item.xml @@ -39,7 +39,7 @@ android:includeFontPadding="false" android:singleLine="true" android:textAlignment="viewStart" - android:textAppearance="@style/BlackTitle1" /> + android:textAppearance="@style/TextAppearance.BlackTitle1" /> <TextView android:id="@+id/dropdown_sublabel" @@ -51,7 +51,7 @@ android:includeFontPadding="false" android:singleLine="true" android:textAlignment="viewStart" - android:textAppearance="@style/BlackCaption" /> + android:textAppearance="@style/TextAppearance.BlackCaption" /> </LinearLayout> <ImageView diff --git a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml index 3760277d326..0c77e09b4b6 100644 --- a/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml +++ b/chromium/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml @@ -34,7 +34,7 @@ android:ellipsize="end" android:includeFontPadding="false" android:singleLine="true" - android:textAppearance="@style/BlackBodyDefault" /> + android:textAppearance="@style/TextAppearance.BlackBodyDefault" /> <TextView android:id="@+id/dropdown_sublabel" @@ -44,7 +44,7 @@ android:includeFontPadding="false" android:singleLine="true" android:textAlignment="viewStart" - android:textAppearance="@style/BlackCaption" /> + android:textAppearance="@style/TextAppearance.BlackCaption" /> </LinearLayout> <ImageView diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc index 7bde728205a..48bc282528a 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc @@ -182,19 +182,6 @@ gfx::RectF ContentAutofillDriver::TransformBoundingBoxToViewportCoordinates( bounding_box.width(), bounding_box.height()); } -void ContentAutofillDriver::DidInteractWithCreditCardForm() { - // If there is an autofill manager, notify its client about credit card - // inputs on non-secure pages. - if (!autofill_manager_) - return; - if (content::IsOriginSecure( - content::WebContents::FromRenderFrameHost(render_frame_host_) - ->GetVisibleURL())) { - return; - } - autofill_manager_->client()->DidInteractWithNonsecureCreditCardInput(); -} - void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms, base::TimeTicks timestamp) { autofill_handler_->OnFormsSeen(forms, timestamp); @@ -202,9 +189,8 @@ void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms, void ContentAutofillDriver::FormSubmitted(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) { - autofill_handler_->OnFormSubmitted(form, known_success, source, timestamp); + SubmissionSource source) { + autofill_handler_->OnFormSubmitted(form, known_success, source); } void ContentAutofillDriver::TextFieldDidChange(const FormData& form, diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h index 4668b0313df..bb605784fbb 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver.h +++ b/chromium/components/autofill/content/browser/content_autofill_driver.h @@ -71,15 +71,13 @@ class ContentAutofillDriver : public AutofillDriver, void PopupHidden() override; gfx::RectF TransformBoundingBoxToViewportCoordinates( const gfx::RectF& bounding_box) override; - void DidInteractWithCreditCardForm() override; // mojom::AutofillDriver: void FormsSeen(const std::vector<FormData>& forms, base::TimeTicks timestamp) override; void FormSubmitted(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) override; + SubmissionSource source) override; void TextFieldDidChange(const FormData& form, const FormFieldData& field, const gfx::RectF& bounding_box, diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc index 6825bcf6749..6c85d18ee0e 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc @@ -57,8 +57,8 @@ void ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( if (FromWebContents(contents)) return; - auto new_factory = base::WrapUnique(new ContentAutofillDriverFactory( - contents, client, app_locale, enable_download_manager, provider)); + auto new_factory = std::make_unique<ContentAutofillDriverFactory>( + contents, client, app_locale, enable_download_manager, provider); const std::vector<content::RenderFrameHost*> frames = contents->GetAllFrames(); for (content::RenderFrameHost* frame : frames) { diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h index 2ff9b3352ab..3d503f477c4 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h +++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h @@ -28,6 +28,13 @@ class ContentAutofillDriverFactory : public AutofillDriverFactory, public content::WebContentsObserver, public base::SupportsUserData::Data { public: + ContentAutofillDriverFactory( + content::WebContents* web_contents, + AutofillClient* client, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager, + AutofillProvider* provider); + ~ContentAutofillDriverFactory() override; static void CreateForWebContentsAndDelegate( @@ -63,13 +70,6 @@ class ContentAutofillDriverFactory : public AutofillDriverFactory, static const char kContentAutofillDriverFactoryWebContentsUserDataKey[]; private: - ContentAutofillDriverFactory( - content::WebContents* web_contents, - AutofillClient* client, - const std::string& app_locale, - AutofillManager::AutofillDownloadManagerState enable_download_manager, - AutofillProvider* provider); - std::string app_locale_; AutofillManager::AutofillDownloadManagerState enable_download_manager_; AutofillProvider* provider_; diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc index fd830d0ebf5..1a08f64bb43 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc @@ -21,12 +21,11 @@ #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/form_data_predictions.h" #include "content/public/browser/browser_context.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/navigation_handle.h" #include "content/public/browser/ssl_status.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/frame_navigate_params.h" +#include "content/public/test/mock_navigation_handle.h" #include "content/public/test/test_renderer_host.h" #include "mojo/public/cpp/bindings/associated_binding_set.h" #include "net/base/net_errors.h" @@ -252,7 +251,6 @@ class MockAutofillManager : public AutofillManager { class MockAutofillClient : public TestAutofillClient { public: MOCK_METHOD0(OnFirstUserGestureObserved, void()); - MOCK_METHOD0(DidInteractWithNonsecureCreditCardInput, void()); }; class TestContentAutofillDriver : public ContentAutofillDriver { @@ -305,10 +303,10 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness { } void Navigate(bool same_document) { - std::unique_ptr<content::NavigationHandle> navigation_handle = - content::NavigationHandle::CreateNavigationHandleForTesting( - GURL(), main_rfh(), /*committed=*/true, net::OK, same_document); - driver_->DidNavigateMainFrame(navigation_handle.get()); + content::MockNavigationHandle navigation_handle(GURL(), main_rfh()); + navigation_handle.set_has_committed(true); + navigation_handle.set_is_same_document(same_document); + driver_->DidNavigateMainFrame(&navigation_handle); } protected: @@ -458,36 +456,4 @@ TEST_F(ContentAutofillDriverTest, PreviewFieldWithValue) { EXPECT_EQ(input_value, output_value); } -// Tests that credit card form interactions trigger a call to the client's -// |DidInteractWithNonsecureCreditCardInput| function if the page is HTTP. -TEST_F(ContentAutofillDriverTest, CreditCardFormInteraction) { - GURL url("http://example.test"); - NavigateAndCommit(url); - content::NavigationEntry* entry = - web_contents()->GetController().GetVisibleEntry(); - ASSERT_TRUE(entry); - EXPECT_EQ(url, entry->GetURL()); - - EXPECT_CALL(*test_autofill_client_, - DidInteractWithNonsecureCreditCardInput()); - driver_->DidInteractWithCreditCardForm(); -} - -// Tests that credit card form interactions do NOT trigger a call to the -// client's |DidInteractWithNonsecureCreditCardInput| function if the page -// is HTTPS. -TEST_F(ContentAutofillDriverTest, CreditCardFormInteractionOnHTTPS) { - EXPECT_CALL(*test_autofill_client_, DidInteractWithNonsecureCreditCardInput()) - .Times(0); - - GURL url("https://example.test"); - NavigateAndCommit(url); - content::NavigationEntry* entry = - web_contents()->GetController().GetVisibleEntry(); - ASSERT_TRUE(entry); - EXPECT_EQ(url, entry->GetURL()); - - driver_->DidInteractWithCreditCardForm(); -} - } // namespace autofill diff --git a/chromium/components/autofill/content/common/BUILD.gn b/chromium/components/autofill/content/common/BUILD.gn index 04379f467a7..3fb742d14b8 100644 --- a/chromium/components/autofill/content/common/BUILD.gn +++ b/chromium/components/autofill/content/common/BUILD.gn @@ -53,6 +53,7 @@ source_set("unit_tests") { deps = [ "//base", + "//base/test:test_support", "//components/autofill/core/browser:test_support", "//components/password_manager/core/common", "//mojo/public/cpp/bindings", diff --git a/chromium/components/autofill/content/common/autofill_agent.mojom b/chromium/components/autofill/content/common/autofill_agent.mojom index 34995958f01..6138f4bf336 100644 --- a/chromium/components/autofill/content/common/autofill_agent.mojom +++ b/chromium/components/autofill/content/common/autofill_agent.mojom @@ -107,9 +107,9 @@ interface PasswordGenerationAgent { GeneratedPasswordAccepted(mojo_base.mojom.String16 generated_password); // Tells the renderer to find a focused element, and if it is a password field - // eligible for generation then to trigger generation by responding to the - // browser with the message |ShowPasswordGenerationPopup|. - UserTriggeredGeneratePassword(); + // eligible for generation then to trigger generation by returning + // non-empty PasswordGenerationUIData. + UserTriggeredGeneratePassword() => (PasswordGenerationUIData? data); // Tells the renderer that this password form is not blacklisted. A form can // be blacklisted if a user chooses "never save passwords for this site". @@ -117,5 +117,11 @@ interface PasswordGenerationAgent { // Sent when Autofill manager gets the query response from the Autofill server // and there are fields classified for password generation in the response. + // TODO(https://crbug.com/866444): Remove this when PasswordGenerationAgent + // refactoring is finished. FoundFormsEligibleForGeneration(array<PasswordFormGenerationData> forms); + + // Tells the renderer that a password can be generated on the fields + // identified by |form|. + FoundFormEligibleForGeneration(NewPasswordFormGenerationData form); }; diff --git a/chromium/components/autofill/content/common/autofill_driver.mojom b/chromium/components/autofill/content/common/autofill_driver.mojom index 34068b109cc..1235cd0b238 100644 --- a/chromium/components/autofill/content/common/autofill_driver.mojom +++ b/chromium/components/autofill/content/common/autofill_driver.mojom @@ -23,8 +23,7 @@ interface AutofillDriver { // succeeds if the form is removed. FormSubmitted(FormData form, bool known_success, - SubmissionSource source, - mojo_base.mojom.TimeTicks timestamp); + SubmissionSource source); // Notification that a form field's value has changed. TextFieldDidChange(FormData form, @@ -80,7 +79,7 @@ interface AutofillDriver { // There is one instance of this interface per web contents in the browser // process that handles all the frames. The motivation was to make the interface -// associated with PasswordManagerClient. +// associated with PasswordGenerationDriver. interface PasswordManagerDriver { // Notification that password forms have been seen that are candidates for // filling/submitting by the password manager. @@ -131,11 +130,18 @@ interface PasswordManagerDriver { // The focus changed to a different input in the same frame (e.g. tabbed from // email to password field). FocusedInputChanged(bool is_fillable, bool is_password_field); + + // Sends the success state of filling credentials into a form. This happens + // only if the form being filled has a renderer_id. |result| is an + // integer serialization of autofill::FillingResult. It is passed as an + // integer as no further interpretation of the value is necessary in the + // browser. + LogFirstFillingResult(uint32 form_renderer_id, int32 result); }; // There is one instance of this interface per web contents in the browser // process. -interface PasswordManagerClient { +interface PasswordGenerationDriver { // Instructs the browser that generation is available for this particular // form. This is used for UMA stats. GenerationAvailableForForm(PasswordForm password_form); @@ -145,14 +151,6 @@ interface PasswordManagerClient { AutomaticGenerationStatusChanged( bool available, PasswordGenerationUIData? password_generation_ui_data); - // Instructs the browser to show the password generation popup for manual - // generation and provides the data necessary to display it. - // TODO(crbug.com/845458): Replace this with a method called from the browser - // when user triggers generation manually which returns a boolean signaling - // whether the state for generation could be saved or not. - ShowManualPasswordGenerationPopup( - PasswordGenerationUIData password_generation_ui_data); - // Instructs the browser to show the popup for editing a generated password. // The location should be specified in the renderers coordinate system. Form // is the form associated with the password field. diff --git a/chromium/components/autofill/content/common/autofill_types.mojom b/chromium/components/autofill/content/common/autofill_types.mojom index 8e62015abef..2428dd1e4ea 100644 --- a/chromium/components/autofill/content/common/autofill_types.mojom +++ b/chromium/components/autofill/content/common/autofill_types.mojom @@ -102,6 +102,18 @@ enum FillingStatus { ERROR_NOT_ALLOWED, }; +// autofill::ButtonTitleType +enum ButtonTitleType { + NONE, + BUTTON_ELEMENT_SUBMIT_TYPE, + BUTTON_ELEMENT_BUTTON_TYPE, + INPUT_ELEMENT_SUBMIT_TYPE, + INPUT_ELEMENT_BUTTON_TYPE, + HYPERLINK, + DIV, + SPAN +}; + // autofill::FormFieldData struct FormFieldData { mojo_base.mojom.String16 label; @@ -136,12 +148,17 @@ struct FormFieldData { LabelSource label_source; }; +struct ButtonTitleInfo { + mojo_base.mojom.String16 title; + ButtonTitleType type; +}; + // autofill::FormData struct FormData { mojo_base.mojom.String16 id_attribute; mojo_base.mojom.String16 name_attribute; mojo_base.mojom.String16 name; - mojo_base.mojom.String16 button_title; + array<ButtonTitleInfo> button_titles; // TODO(crbug.com/788181): Either change type to Origin or rename to URL. url.mojom.Url origin; url.mojom.Url action; @@ -200,6 +217,12 @@ struct PasswordFormGenerationData { uint32 confirmation_field_signature; }; +// autofill::NewPasswordFormGenerationData +struct NewPasswordFormGenerationData { + uint32 new_password_renderer_id; + uint32 confirmation_password_renderer_id; +}; + // autofill::password_generation::PasswordGenerationUIData struct PasswordGenerationUIData { gfx.mojom.RectF bounds; @@ -251,7 +274,7 @@ struct PasswordForm { bool is_public_suffix_match; bool is_affiliation_based_match; SubmissionIndicatorEvent submission_event; - bool only_for_fallback_saving; + bool only_for_fallback; bool is_gaia_with_skip_save_password_form; }; diff --git a/chromium/components/autofill/content/common/autofill_types.typemap b/chromium/components/autofill/content/common/autofill_types.typemap index 8aab6a3bdcc..90333460722 100644 --- a/chromium/components/autofill/content/common/autofill_types.typemap +++ b/chromium/components/autofill/content/common/autofill_types.typemap @@ -37,6 +37,7 @@ type_mappings = [ "autofill.mojom.FormFieldDataPredictions=autofill::FormFieldDataPredictions", "autofill.mojom.FormsPredictionsMap=autofill::FormsPredictionsMap", "autofill.mojom.GenerationUploadStatus=autofill::PasswordForm::GenerationUploadStatus", + "autofill.mojom.NewPasswordFormGenerationData=autofill::NewPasswordFormGenerationData", "autofill.mojom.PasswordAndRealm=autofill::PasswordAndRealm", "autofill.mojom.PasswordForm=autofill::PasswordForm", "autofill.mojom.PasswordFormFieldPredictionMap=autofill::PasswordFormFieldPredictionMap", diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc index 5f762c736be..bd2c31e1f01 100644 --- a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc +++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc @@ -527,6 +527,66 @@ bool EnumTraits<autofill::mojom::FillingStatus, autofill::FillingStatus>:: } // static +autofill::mojom::ButtonTitleType EnumTraits< + autofill::mojom::ButtonTitleType, + autofill::ButtonTitleType>::ToMojom(autofill::ButtonTitleType input) { + switch (input) { + case autofill::ButtonTitleType::NONE: + return autofill::mojom::ButtonTitleType::NONE; + case autofill::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE: + return autofill::mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE; + case autofill::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE: + return autofill::mojom::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE; + case autofill::ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE: + return autofill::mojom::ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE; + case autofill::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE: + return autofill::mojom::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE; + case autofill::ButtonTitleType::HYPERLINK: + return autofill::mojom::ButtonTitleType::HYPERLINK; + case autofill::ButtonTitleType::DIV: + return autofill::mojom::ButtonTitleType::DIV; + case autofill::ButtonTitleType::SPAN: + return autofill::mojom::ButtonTitleType::SPAN; + } + NOTREACHED(); + return autofill::mojom::ButtonTitleType::NONE; +} + +// static +bool EnumTraits<autofill::mojom::ButtonTitleType, autofill::ButtonTitleType>:: + FromMojom(autofill::mojom::ButtonTitleType input, + autofill::ButtonTitleType* output) { + switch (input) { + case autofill::mojom::ButtonTitleType::NONE: + *output = autofill::ButtonTitleType::NONE; + return true; + case autofill::mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE: + *output = autofill::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE; + return true; + case autofill::mojom::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE: + *output = autofill::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE; + return true; + case autofill::mojom::ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE: + *output = autofill::ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE; + return true; + case autofill::mojom::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE: + *output = autofill::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE; + return true; + case autofill::mojom::ButtonTitleType::HYPERLINK: + *output = autofill::ButtonTitleType::HYPERLINK; + return true; + case autofill::mojom::ButtonTitleType::DIV: + *output = autofill::ButtonTitleType::DIV; + return true; + case autofill::mojom::ButtonTitleType::SPAN: + *output = autofill::ButtonTitleType::SPAN; + return true; + } + NOTREACHED(); + return false; +} + +// static bool StructTraits< autofill::mojom::FormFieldDataDataView, autofill::FormFieldData>::Read(autofill::mojom::FormFieldDataDataView data, @@ -581,7 +641,7 @@ bool StructTraits< out->is_enabled = data.is_enabled(); out->is_readonly = data.is_readonly(); - if (!data.ReadValue(&out->typed_value)) + if (!data.ReadTypedValue(&out->typed_value)) return false; if (!data.ReadOptionValues(&out->option_values)) @@ -596,6 +656,14 @@ bool StructTraits< } // static +bool StructTraits<autofill::mojom::ButtonTitleInfoDataView, + autofill::ButtonTitleInfo>:: + Read(autofill::mojom::ButtonTitleInfoDataView data, + autofill::ButtonTitleInfo* out) { + return data.ReadTitle(&out->first) && data.ReadType(&out->second); +} + +// static bool StructTraits<autofill::mojom::FormDataDataView, autofill::FormData>::Read( autofill::mojom::FormDataDataView data, autofill::FormData* out) { @@ -605,7 +673,7 @@ bool StructTraits<autofill::mojom::FormDataDataView, autofill::FormData>::Read( return false; if (!data.ReadName(&out->name)) return false; - if (!data.ReadButtonTitle(&out->button_title)) + if (!data.ReadButtonTitles(&out->button_titles)) return false; if (!data.ReadOrigin(&out->origin)) return false; @@ -719,6 +787,17 @@ bool StructTraits<autofill::mojom::PasswordFormGenerationDataDataView, } // static +bool StructTraits<autofill::mojom::NewPasswordFormGenerationDataDataView, + autofill::NewPasswordFormGenerationData>:: + Read(autofill::mojom::NewPasswordFormGenerationDataDataView data, + autofill::NewPasswordFormGenerationData* out) { + out->new_password_renderer_id = data.new_password_renderer_id(); + out->confirmation_password_renderer_id = + data.confirmation_password_renderer_id(); + return true; +} + +// static bool StructTraits<autofill::mojom::PasswordGenerationUIDataDataView, autofill::password_generation::PasswordGenerationUIData>:: Read(autofill::mojom::PasswordGenerationUIDataDataView data, @@ -798,7 +877,7 @@ bool StructTraits< data.was_parsed_using_autofill_predictions(); out->is_public_suffix_match = data.is_public_suffix_match(); out->is_affiliation_based_match = data.is_affiliation_based_match(); - out->only_for_fallback_saving = data.only_for_fallback_saving(); + out->only_for_fallback = data.only_for_fallback(); out->is_gaia_with_skip_save_password_form = data.is_gaia_with_skip_save_password_form(); diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.h b/chromium/components/autofill/content/common/autofill_types_struct_traits.h index 97c683e443a..957bc222b97 100644 --- a/chromium/components/autofill/content/common/autofill_types_struct_traits.h +++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.h @@ -119,6 +119,14 @@ struct EnumTraits<autofill::mojom::FillingStatus, autofill::FillingStatus> { }; template <> +struct EnumTraits<autofill::mojom::ButtonTitleType, autofill::ButtonTitleType> { + static autofill::mojom::ButtonTitleType ToMojom( + autofill::ButtonTitleType input); + static bool FromMojom(autofill::mojom::ButtonTitleType input, + autofill::ButtonTitleType* output); +}; + +template <> struct StructTraits<autofill::mojom::FormFieldDataDataView, autofill::FormFieldData> { static const base::string16& label(const autofill::FormFieldData& r) { @@ -244,6 +252,22 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView, }; template <> +struct StructTraits<autofill::mojom::ButtonTitleInfoDataView, + autofill::ButtonTitleInfo> { + static const base::string16& title(const autofill::ButtonTitleInfo& r) { + return r.first; + } + + static const autofill::ButtonTitleType& type( + const autofill::ButtonTitleInfo& r) { + return r.second; + } + + static bool Read(autofill::mojom::ButtonTitleInfoDataView data, + autofill::ButtonTitleInfo* out); +}; + +template <> struct StructTraits<autofill::mojom::FormDataDataView, autofill::FormData> { static const base::string16& id_attribute(const autofill::FormData& r) { return r.id_attribute; @@ -257,8 +281,9 @@ struct StructTraits<autofill::mojom::FormDataDataView, autofill::FormData> { return r.name; } - static const base::string16& button_title(const autofill::FormData& r) { - return r.button_title; + static const autofill::ButtonTitleList& button_titles( + const autofill::FormData& r) { + return r.button_titles; } static const GURL& origin(const autofill::FormData& r) { return r.origin; } @@ -456,6 +481,23 @@ struct StructTraits<autofill::mojom::PasswordFormGenerationDataDataView, }; template <> +struct StructTraits<autofill::mojom::NewPasswordFormGenerationDataDataView, + autofill::NewPasswordFormGenerationData> { + static uint32_t new_password_renderer_id( + const autofill::NewPasswordFormGenerationData& r) { + return r.new_password_renderer_id; + } + + static uint32_t confirmation_password_renderer_id( + const autofill::NewPasswordFormGenerationData& r) { + return r.confirmation_password_renderer_id; + } + + static bool Read(autofill::mojom::NewPasswordFormGenerationDataDataView data, + autofill::NewPasswordFormGenerationData* out); +}; + +template <> struct StructTraits<autofill::mojom::PasswordGenerationUIDataDataView, autofill::password_generation::PasswordGenerationUIData> { static const gfx::RectF& bounds( @@ -637,8 +679,8 @@ struct StructTraits<autofill::mojom::PasswordFormDataView, return r.submission_event; } - static bool only_for_fallback_saving(const autofill::PasswordForm& r) { - return r.only_for_fallback_saving; + static bool only_for_fallback(const autofill::PasswordForm& r) { + return r.only_for_fallback; } static bool is_gaia_with_skip_save_password_form( diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc index df9c8152d49..2d2534c264f 100644 --- a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc +++ b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc @@ -4,11 +4,12 @@ #include <utility> -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" #include "components/autofill/content/common/test_autofill_types.mojom.h" #include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/common/button_title_type.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/password_generation_util.h" @@ -244,6 +245,12 @@ class AutofillTypeTraitsTestImpl : public testing::Test, std::move(callback).Run(s); } + void PassNewPasswordFormGenerationData( + const NewPasswordFormGenerationData& s, + PassNewPasswordFormGenerationDataCallback callback) override { + std::move(callback).Run(s); + } + void PassPasswordGenerationUIData( const password_generation::PasswordGenerationUIData& s, PassPasswordGenerationUIDataCallback callback) override { @@ -262,7 +269,7 @@ class AutofillTypeTraitsTestImpl : public testing::Test, } private: - base::MessageLoop loop_; + base::test::ScopedTaskEnvironment task_environment_; mojo::BindingSet<TypeTraitsTest> bindings_; }; @@ -271,6 +278,8 @@ void ExpectFormFieldData(const FormFieldData& expected, const base::Closure& closure, const FormFieldData& passed) { EXPECT_EQ(expected, passed); + EXPECT_EQ(expected.value, passed.value); + EXPECT_EQ(expected.typed_value, passed.typed_value); closure.Run(); } @@ -310,6 +319,16 @@ void ExpectPasswordFormGenerationData( closure.Run(); } +void ExpectNewPasswordFormGenerationData( + const NewPasswordFormGenerationData& expected, + const base::Closure& closure, + const NewPasswordFormGenerationData& passed) { + EXPECT_EQ(expected.new_password_renderer_id, passed.new_password_renderer_id); + EXPECT_EQ(expected.confirmation_password_renderer_id, + passed.confirmation_password_renderer_id); + closure.Run(); +} + void ExpectPasswordGenerationUIData( const password_generation::PasswordGenerationUIData& expected, base::OnceClosure closure, @@ -351,6 +370,7 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) { input.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION; input.text_direction = base::i18n::RIGHT_TO_LEFT; input.properties_mask = FieldPropertiesFlags::HAD_FOCUS; + input.typed_value = base::ASCIIToUTF16("TestTypedValue"); base::RunLoop loop; mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); @@ -363,6 +383,9 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormData) { FormData input; test::CreateTestAddressFormData(&input); input.username_predictions = {1, 13, 2}; + input.button_titles.push_back( + std::make_pair(base::ASCIIToUTF16("Sign-up"), + autofill::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)); base::RunLoop loop; mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); @@ -433,6 +456,19 @@ TEST_F(AutofillTypeTraitsTestImpl, PassPasswordFormGenerationData) { loop.Run(); } +TEST_F(AutofillTypeTraitsTestImpl, NewPasswordFormGenerationData) { + NewPasswordFormGenerationData input = { + .new_password_renderer_id = 1234u, + .confirmation_password_renderer_id = 5789u}; + + base::RunLoop loop; + mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); + proxy->PassNewPasswordFormGenerationData( + input, base::BindOnce(&ExpectNewPasswordFormGenerationData, input, + loop.QuitClosure())); + loop.Run(); +} + TEST_F(AutofillTypeTraitsTestImpl, PassPasswordGenerationUIData) { password_generation::PasswordGenerationUIData input; CreatePasswordGenerationUIData(&input); diff --git a/chromium/components/autofill/content/common/test_autofill_types.mojom b/chromium/components/autofill/content/common/test_autofill_types.mojom index a0a0234d217..c24e36bcc7e 100644 --- a/chromium/components/autofill/content/common/test_autofill_types.mojom +++ b/chromium/components/autofill/content/common/test_autofill_types.mojom @@ -15,5 +15,6 @@ interface TypeTraitsTest { PassPasswordFormFillData(PasswordFormFillData s) => (PasswordFormFillData passed); PassFormsPredictionsMap(FormsPredictionsMap s) => (FormsPredictionsMap passed); PassPasswordFormGenerationData(PasswordFormGenerationData s) => (PasswordFormGenerationData passed); + PassNewPasswordFormGenerationData(NewPasswordFormGenerationData s) => (NewPasswordFormGenerationData passed); PassPasswordGenerationUIData(PasswordGenerationUIData s) => (PasswordGenerationUIData passed); }; diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn index f0b3b85b830..6849329db91 100644 --- a/chromium/components/autofill/content/renderer/BUILD.gn +++ b/chromium/components/autofill/content/renderer/BUILD.gn @@ -30,6 +30,8 @@ jumbo_static_library("renderer") { "password_form_conversion_utils.h", "password_generation_agent.cc", "password_generation_agent.h", + "prefilled_values_detector.cc", + "prefilled_values_detector.h", "provisionally_saved_password_form.cc", "provisionally_saved_password_form.h", "renderer_save_password_progress_logger.cc", @@ -92,6 +94,7 @@ source_set("unit_tests") { testonly = true sources = [ "form_cache_unittest.cc", + "prefilled_values_detector_unittest.cc", "renderer_save_password_progress_logger_unittest.cc", ] diff --git a/chromium/components/autofill/content/renderer/OWNERS b/chromium/components/autofill/content/renderer/OWNERS index d1737e7f0e1..15f8279c885 100644 --- a/chromium/components/autofill/content/renderer/OWNERS +++ b/chromium/components/autofill/content/renderer/OWNERS @@ -1,9 +1,7 @@ per-file *password*=dvadym@chromium.org per-file *password*=kolos@chromium.org -per-file *password*=vabr@chromium.org per-file *password*=vasilii@chromium.org per-file *username*=dvadym@chromium.org per-file *username*=kolos@chromium.org -per-file *username*=vabr@chromium.org per-file *username*=vasilii@chromium.org diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc index f5bed4ccbc6..1e4ee613d2a 100644 --- a/chromium/components/autofill/content/renderer/autofill_agent.cc +++ b/chromium/components/autofill/content/renderer/autofill_agent.cc @@ -87,12 +87,6 @@ namespace { // upon, instead of multiple in close succession (debounce time). size_t kWaitTimeForSelectOptionsChangesMs = 50; -// Whether the "single click" autofill feature is enabled, through command-line -// or field trial. -bool IsSingleClickEnabled() { - return base::FeatureList::IsEnabled(features::kSingleClickAutofill); -} - // Gets all the data list values (with corresponding label) for the given // element. void GetDataListSuggestions(const WebInputElement& element, @@ -301,8 +295,7 @@ void AutofillAgent::FireHostSubmitEvents(const FormData& form_data, if (!submitted_forms_.insert(form_data).second) return; - GetAutofillDriver()->FormSubmitted(form_data, known_success, source, - base::TimeTicks::Now()); + GetAutofillDriver()->FormSubmitted(form_data, known_success, source); } void AutofillAgent::Shutdown() { @@ -660,7 +653,14 @@ void AutofillAgent::ShowSuggestions(const WebFormControlElement& element, // Password field elements should only have suggestions shown by the password // autofill agent. - if (input_element && input_element->IsPasswordFieldForAutofill() && + // The /*disable presubmit*/ comment below is used to disable a presubmit + // script that ensures that only IsPasswordFieldForAutofill() is used in this + // code (it has to appear between the function name and the parentesis to not + // match a regex). In this specific case we are actually interested in whether + // the field is currently a password field, not whether it has ever been a + // password field. + if (input_element && + input_element->IsPasswordField /*disable presubmit*/ () && !query_password_suggestion_) { return; } @@ -926,10 +926,6 @@ void AutofillAgent::FormControlElementClicked( // Show full suggestions when clicking on an already-focused form field. options.show_full_suggestion_list = element.IsAutofilled() || was_focused; - if (!IsSingleClickEnabled()) { - // On the initial click (not focused yet), only show password suggestions. - options.show_password_suggestions_only = !was_focused; - } ShowSuggestions(element, options); } diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc index ee74da2318f..c446763ff7a 100644 --- a/chromium/components/autofill/content/renderer/form_autofill_util.cc +++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc @@ -9,6 +9,7 @@ #include <map> #include <memory> #include <set> +#include <string> #include <utility> #include <vector> @@ -29,6 +30,7 @@ #include "components/autofill/core/common/autofill_regexes.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" +#include "components/autofill/core/common/button_title_type.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "third_party/blink/public/platform/url_conversion.h" @@ -69,6 +71,18 @@ const size_t kMaxParseableFields = 200; namespace { +// Maximal length of a button's title. +const int kMaxLengthForSingleButtonTitle = 30; +// Maximal length of all button titles. +const int kMaxLengthForAllButtonTitles = 200; + +// Text features to detect form submission buttons. Features are selected based +// on analysis of real forms and their buttons. +// TODO(crbug.com/910546): Consider to add more features (e.g. non-English +// features). +const char* const kButtonFeatures[] = {"button", "btn", "submit", + "boton" /* "button" in Spanish */}; + // A bit field mask for FillForm functions to not fill some fields. enum FieldFilterMask { FILTER_NONE = 0, @@ -118,7 +132,8 @@ bool IsElementInControlElementSet( return base::ContainsValue(control_elements, form_control_element); } -bool IsElementInsideFormOrFieldSet(const WebElement& element) { +bool IsElementInsideFormOrFieldSet(const WebElement& element, + bool consider_fieldset_tags) { for (WebNode parent_node = element.ParentNode(); !parent_node.IsNull(); parent_node = parent_node.ParentNode()) { if (!parent_node.IsElementNode()) @@ -126,7 +141,7 @@ bool IsElementInsideFormOrFieldSet(const WebElement& element) { WebElement cur_element = parent_node.To<WebElement>(); if (cur_element.HasHTMLTagName("form") || - cur_element.HasHTMLTagName("fieldset")) { + (consider_fieldset_tags && cur_element.HasHTMLTagName("fieldset"))) { return true; } } @@ -357,6 +372,68 @@ bool InferLabelFromSibling(const WebFormControlElement& element, return false; } +// Helper function to add a button's |title| to the |list|. +void AddButtonTitleToList(base::string16 title, + ButtonTitleType button_type, + ButtonTitleList* list) { + title = base::CollapseWhitespace(std::move(title), false); + if (title.empty()) + return; + TruncateString(&title, kMaxLengthForSingleButtonTitle); + list->push_back(std::make_pair(std::move(title), button_type)); +} + +// Returns true iff |attribute| contains one of |kButtonFeatures|. +bool AttributeHasButtonFeature(const WebString& attribute) { + if (attribute.IsNull()) + return false; + std::string value = attribute.Utf8(); + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + for (const char* const button_feature : kButtonFeatures) { + if (value.find(button_feature, 0) != std::string::npos) + return true; + } + return false; +} + +// Returns true if |element|'s id, name or css class contain |kButtonFeatures|. +bool ElementAttributesHasButtonFeature(const WebElement& element) { + return AttributeHasButtonFeature(element.GetAttribute("id")) || + AttributeHasButtonFeature(element.GetAttribute("name")) || + AttributeHasButtonFeature(element.GetAttribute("class")); +} + +// Finds elements from |elements| that contains |kButtonFeatures|, adds them to +// |list| and updates the |total_length| of the |list|'s items. +// If |extract_value_attribute|, the "value" attribute is extracted as a button +// title. Otherwise, |WebElement::TextContent| (aka innerText in Javascript) is +// extracted as a title. +void FindElementsWithButtonFeatures(const WebElementCollection& elements, + bool only_formless_elements, + ButtonTitleType button_type, + bool extract_value_attribute, + ButtonTitleList* list) { + static base::NoDestructor<WebString> kValue("value"); + for (WebElement item = elements.FirstItem(); !item.IsNull(); + item = elements.NextItem()) { + if (!ElementAttributesHasButtonFeature(item)) + continue; + if (only_formless_elements && + IsElementInsideFormOrFieldSet(item, + false /* consider_fieldset_tags */)) { + continue; + } + base::string16 title = + extract_value_attribute + ? (item.HasAttribute(*kValue) ? item.GetAttribute(*kValue).Utf16() + : base::string16()) + : item.TextContent().Utf16(); + if (extract_value_attribute && title.empty()) + title = item.TextContent().Utf16(); + AddButtonTitleToList(std::move(title), button_type, list); + } +} + // Helper for |InferLabelForElement()| that infers a label, if possible, from // a previous sibling of |element|, // e.g. Some Text <input ...> @@ -780,40 +857,107 @@ bool InferLabelForElement(const WebFormControlElement& element, return false; } -base::string16 InferButtonTitleForForm(const WebFormElement& form_element) { - static base::NoDestructor<WebString> kSubmit("submit"); +// Removes the duplicate titles and limits totals length. The order of the list +// is preserved as first elements are more reliable features than following +// ones. +void RemoveDuplicatesAndLimitTotalLength(ButtonTitleList* result) { + std::set<ButtonTitleInfo> already_added; + ButtonTitleList unique_titles; + int total_length = 0; + for (auto title : *result) { + if (already_added.find(title) != already_added.end()) + continue; + already_added.insert(title); + + total_length += title.first.length(); + if (total_length > kMaxLengthForAllButtonTitles) { + int new_length = + title.first.length() - (total_length - kMaxLengthForAllButtonTitles); + TruncateString(&title.first, new_length); + } + unique_titles.push_back(std::move(title)); + + if (total_length >= kMaxLengthForAllButtonTitles) + break; + } + *result = std::move(unique_titles); +} + +// Infer button titles enclosed by |root_element|. |root_element| may be a +// <form> or a <body> if there are <input>s that are not enclosed in a <form> +// element. +ButtonTitleList InferButtonTitlesForForm(const WebElement& root_element) { + static base::NoDestructor<WebString> kA("a"); static base::NoDestructor<WebString> kButton("button"); + static base::NoDestructor<WebString> kDiv("div"); + static base::NoDestructor<WebString> kForm("form"); + static base::NoDestructor<WebString> kInput("input"); + static base::NoDestructor<WebString> kSpan("span"); + static base::NoDestructor<WebString> kSubmit("submit"); - base::string16 title; - WebVector<WebFormControlElement> control_elements; - form_element.GetFormControlElements(control_elements); - for (const WebFormControlElement& control_element : control_elements) { + // If the |root_element| is not a <form>, ignore the elements inclosed in a + // <form>. + bool only_formless_elements = !root_element.HasHTMLTagName(*kForm); + + ButtonTitleList result; + WebElementCollection input_elements = + root_element.GetElementsByHTMLTagName(*kInput); + int total_length = 0; + for (WebElement item = input_elements.FirstItem(); + !item.IsNull() && total_length < kMaxLengthForAllButtonTitles; + item = input_elements.NextItem()) { + DCHECK(item.IsFormControlElement()); + WebFormControlElement control_element = + item.ToConst<WebFormControlElement>(); + if (only_formless_elements && !control_element.Form().IsNull()) + continue; bool is_submit_input = control_element.FormControlTypeForAutofill() == *kSubmit; bool is_button_input = control_element.FormControlTypeForAutofill() == *kButton; if (!is_submit_input && !is_button_input) continue; - if (!control_element.Value().IsEmpty()) - title = control_element.Value().Utf16() + - base::ASCIIToUTF16(is_submit_input ? "$" : "#") + title; - if (title.length() >= kMaxDataLength) - break; + base::string16 title = control_element.Value().Utf16(); + AddButtonTitleToList(std::move(title), + is_submit_input + ? ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE + : ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE, + &result); } WebElementCollection buttons = - form_element.GetElementsByHTMLTagName(*kButton); - for (WebElement item = buttons.FirstItem(); - !item.IsNull() && title.length() <= kMaxDataLength; + root_element.GetElementsByHTMLTagName(*kButton); + for (WebElement item = buttons.FirstItem(); !item.IsNull(); item = buttons.NextItem()) { - if (!item.TextContent().IsEmpty()) { - bool is_submit_button = - item.HasAttribute("type") && item.GetAttribute("type") == *kSubmit; - title = item.TextContent().Utf16() + - base::ASCIIToUTF16(is_submit_button ? "&" : "%") + title; + WebString type_attribute = item.GetAttribute("type"); + if (!type_attribute.IsNull() && type_attribute != *kButton && + type_attribute != *kSubmit) { + // Neither type='submit' nor type='button'. Skip this button. + continue; } - } - TruncateString(&title, kMaxDataLength); - return title; + if (only_formless_elements && + IsElementInsideFormOrFieldSet(item, + false /* consider_fieldset_tags */)) { + continue; + } + bool is_submit_type = type_attribute.IsNull() || type_attribute == *kSubmit; + base::string16 title = item.TextContent().Utf16(); + AddButtonTitleToList(std::move(title), + is_submit_type + ? ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE + : ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE, + &result); + } + FindElementsWithButtonFeatures( + root_element.GetElementsByHTMLTagName(*kA), only_formless_elements, + ButtonTitleType::HYPERLINK, true /* extract_value_attribute */, &result); + FindElementsWithButtonFeatures(root_element.GetElementsByHTMLTagName(*kDiv), + only_formless_elements, ButtonTitleType::DIV, + false /* extract_value_attribute */, &result); + FindElementsWithButtonFeatures(root_element.GetElementsByHTMLTagName(*kSpan), + only_formless_elements, ButtonTitleType::SPAN, + false /* extract_value_attribute */, &result); + RemoveDuplicatesAndLimitTotalLength(&result); + return result; } // Fills |option_strings| with the values of the <option> elements present in @@ -1647,7 +1791,6 @@ bool WebFormElementToFormData( form->unique_renderer_id = form_element.UniqueRendererFormId(); form->origin = GetCanonicalOriginForDocument(frame->GetDocument()); form->action = GetCanonicalActionForForm(form_element); - form->button_title = InferButtonTitleForForm(form_element); if (frame->Top()) { form->main_frame_origin = frame->Top()->GetSecurityOrigin(); } else { @@ -1681,7 +1824,8 @@ std::vector<WebFormControlElement> GetUnownedFormFieldElements( } if (fieldsets && element.HasHTMLTagName("fieldset") && - !IsElementInsideFormOrFieldSet(element)) { + !IsElementInsideFormOrFieldSet(element, + true /* consider_fieldset_tags */)) { fieldsets->push_back(element); } } @@ -2017,8 +2161,8 @@ bool InferLabelForElementForTesting(const WebFormControlElement& element, return InferLabelForElement(element, stop_words, label, label_source); } -base::string16 InferButtonTitleForTesting(const WebFormElement& form_element) { - return InferButtonTitleForForm(form_element); +ButtonTitleList InferButtonTitlesForTesting(const WebElement& form_element) { + return InferButtonTitlesForForm(form_element); } WebFormElement FindFormByUniqueRendererId(WebDocument doc, @@ -2033,6 +2177,23 @@ WebFormElement FindFormByUniqueRendererId(WebDocument doc, return WebFormElement(); } +WebFormControlElement FindFormControlElementsByUniqueRendererId( + WebDocument doc, + uint32_t form_control_renderer_id) { + WebElementCollection elements = doc.All(); + + for (WebElement element = elements.FirstItem(); !element.IsNull(); + element = elements.NextItem()) { + if (!element.IsFormControlElement()) + continue; + WebFormControlElement control = element.To<WebFormControlElement>(); + if (form_control_renderer_id == control.UniqueRendererFormControlId()) + return control; + } + + return WebFormControlElement(); +} + std::vector<WebFormControlElement> FindFormControlElementsByUniqueRendererId( WebDocument doc, const std::vector<uint32_t>& form_control_renderer_ids) { diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h index 3cfb4186c7b..bb64fb7fe73 100644 --- a/chromium/components/autofill/content/renderer/form_autofill_util.h +++ b/chromium/components/autofill/content/renderer/form_autofill_util.h @@ -278,14 +278,20 @@ bool InferLabelForElementForTesting(const blink::WebFormControlElement& element, const std::vector<base::char16>& stop_words, base::string16* label, FormFieldData::LabelSource* label_source); -base::string16 InferButtonTitleForTesting( - const blink::WebFormElement& form_element); +ButtonTitleList InferButtonTitlesForTesting( + const blink::WebElement& form_element); // Returns form by unique renderer id. Return null element if there is no form // with given form renderer id. blink::WebFormElement FindFormByUniqueRendererId(blink::WebDocument doc, uint32_t form_renderer_id); +// Returns form control element by unique renderer id. Return null element if +// there is no element with given renderer id. +blink::WebFormControlElement FindFormControlElementsByUniqueRendererId( + blink::WebDocument doc, + uint32_t form_control_renderer_id); + // Note: The vector-based API of the following two functions is a tax for limiting // the frequency and duration of retrieving a lot of DOM elements. Alternative // solutions have been discussed on https://crrev.com/c/1108201. diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc index 136bb92ab41..48ce8bb59a6 100644 --- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc +++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc @@ -4,6 +4,8 @@ #include "components/autofill/content/renderer/form_autofill_util.h" +#include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "content/public/test/render_view_test.h" #include "testing/gtest/include/gtest/gtest.h" @@ -267,31 +269,107 @@ TEST_F(FormAutofillUtilsTest, InferLabelSourceTest) { } TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest) { - static const AutofillFieldUtilCase test_cases[] = { - {"<button>", "<form id='target'><button>Sign Up</button></form>", - "Sign Up%"}, - {"<input type='submit'>", - "<form id='target'><input type='submit' value='Sign In'></form>", - "Sign In$"}, - {"several labels", - "<form id='target'><button type='button'>Show " - "password</button><button type='submit'>Register</button></form>", - "Register&Show password%"}}; - for (const auto& test_case : test_cases) { - SCOPED_TRACE(test_case.description); - LoadHTML(test_case.html); - WebLocalFrame* web_frame = GetMainFrame(); - ASSERT_NE(nullptr, web_frame); - const WebElement& target = - web_frame->GetDocument().GetElementById("target"); - ASSERT_FALSE(target.IsNull()); - const WebFormElement& form_target = target.ToConst<WebFormElement>(); - ASSERT_FALSE(form_target.IsNull()); + const char kHtml[] = + "<form id='target'>" + " <input type='button' value='Clear field'>" + " <input type='button' value='Clear field'>" + " <input type='button' value='Clear field'>" + " <input type='button' value='\n Show\t password '>" + " <button>Sign Up</button>" + " <button type='button'>Register</button>" + " <a id='Submit' value='Create account'>" + " <div name='BTN'> Join </div>" + " <span class='button'> Start </span>" + " <a class='empty button' value=' \t \n'>" + "</form>"; + + LoadHTML(kHtml); + WebLocalFrame* web_frame = GetMainFrame(); + ASSERT_NE(nullptr, web_frame); + const WebElement& target = web_frame->GetDocument().GetElementById("target"); + ASSERT_FALSE(target.IsNull()); + const WebFormElement& form_target = target.ToConst<WebFormElement>(); + ASSERT_FALSE(form_target.IsNull()); + + autofill::ButtonTitleList actual = + autofill::form_util::InferButtonTitlesForTesting(form_target); + autofill::ButtonTitleList expected = { + {base::UTF8ToUTF16("Clear field"), + autofill::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE}, + {base::UTF8ToUTF16("Show password"), + autofill::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE}, + {base::UTF8ToUTF16("Sign Up"), + autofill::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE}, + {base::UTF8ToUTF16("Register"), + autofill::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE}, + {base::UTF8ToUTF16("Create account"), + autofill::ButtonTitleType::HYPERLINK}, + {base::UTF8ToUTF16("Join"), autofill::ButtonTitleType::DIV}, + {base::UTF8ToUTF16("Start"), autofill::ButtonTitleType::SPAN}}; + EXPECT_EQ(expected, actual); +} - base::string16 button_title = - autofill::form_util::InferButtonTitleForTesting(form_target); - EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label), button_title); +TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest_TooLongTitle) { + std::string title; + for (int i = 0; i < 300; ++i) + title += "a"; + std::string kFormHtml = "<form id='target'>"; + for (int i = 0; i < 10; i++) { + std::string kFieldHtml = + "<input type='button' value='" + base::IntToString(i) + title + "'>"; + kFormHtml += kFieldHtml; } + kFormHtml += "</form>"; + + LoadHTML(kFormHtml.c_str()); + WebLocalFrame* web_frame = GetMainFrame(); + ASSERT_NE(nullptr, web_frame); + const WebElement& target = web_frame->GetDocument().GetElementById("target"); + ASSERT_FALSE(target.IsNull()); + const WebFormElement& form_target = target.ToConst<WebFormElement>(); + ASSERT_FALSE(form_target.IsNull()); + + autofill::ButtonTitleList actual = + autofill::form_util::InferButtonTitlesForTesting(form_target); + + int total_length = 0; + for (auto title : actual) { + EXPECT_GE(30u, title.first.length()); + total_length += title.first.length(); + } + EXPECT_EQ(200, total_length); +} + +TEST_F(FormAutofillUtilsTest, InferButtonTitle_Formless) { + const char kNoFormHtml[] = + "<div class='reg-form'>" + " <input type='button' value='\n Show\t password '>" + " <button>Sign Up</button>" + " <button type='button'>Register</button>" + "</div>" + "<form id='ignored-form'>" + " <input type='button' value='Ignore this'>" + " <button>Ignore this</button>" + " <a id='Submit' value='Ignore this'>" + " <div name='BTN'>Ignore this</div>" + "</form>"; + + LoadHTML(kNoFormHtml); + WebLocalFrame* web_frame = GetMainFrame(); + ASSERT_NE(nullptr, web_frame); + const WebElement& body = web_frame->GetDocument().Body(); + ASSERT_FALSE(body.IsNull()); + + autofill::ButtonTitleList actual = + autofill::form_util::InferButtonTitlesForTesting(body); + autofill::ButtonTitleList expected = { + {base::UTF8ToUTF16("Show password"), + autofill::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE}, + {base::UTF8ToUTF16("Sign Up"), + autofill::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE}, + {base::UTF8ToUTF16("Register"), + autofill::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE}}; + EXPECT_EQ(expected, actual); } TEST_F(FormAutofillUtilsTest, IsEnabled) { @@ -324,7 +402,7 @@ TEST_F(FormAutofillUtilsTest, IsEnabled) { } kExpectedFields[] = { {"name1", true}, {"name2", false}, {"name3", true}, {"name4", false}, }; - const size_t number_of_cases = arraysize(kExpectedFields); + const size_t number_of_cases = base::size(kExpectedFields); ASSERT_EQ(number_of_cases, target.fields.size()); for (size_t i = 0; i < number_of_cases; ++i) { EXPECT_EQ(base::UTF8ToUTF16(kExpectedFields[i].name), @@ -363,7 +441,7 @@ TEST_F(FormAutofillUtilsTest, IsReadonly) { } kExpectedFields[] = { {"name1", false}, {"name2", true}, {"name3", false}, {"name4", true}, }; - const size_t number_of_cases = arraysize(kExpectedFields); + const size_t number_of_cases = base::size(kExpectedFields); ASSERT_EQ(number_of_cases, target.fields.size()); for (size_t i = 0; i < number_of_cases; ++i) { EXPECT_EQ(base::UTF8ToUTF16(kExpectedFields[i].name), @@ -423,6 +501,23 @@ TEST_F(FormAutofillUtilsTest, FindFormByUniqueId) { .IsNull()); } +TEST_F(FormAutofillUtilsTest, FindFormControlByUniqueId) { + LoadHTML( + "<body><form id='form1'><input id='i1'></form><input id='i2'></body>"); + WebDocument doc = GetMainFrame()->GetDocument(); + auto input1 = doc.GetElementById("i1").To<WebInputElement>(); + auto input2 = doc.GetElementById("i2").To<WebInputElement>(); + uint32_t non_existing_id = input2.UniqueRendererFormControlId() + 1000; + using autofill::form_util::FindFormControlElementsByUniqueRendererId; + + EXPECT_EQ(input1, FindFormControlElementsByUniqueRendererId( + doc, input1.UniqueRendererFormControlId())); + EXPECT_EQ(input2, FindFormControlElementsByUniqueRendererId( + doc, input2.UniqueRendererFormControlId())); + EXPECT_TRUE( + FindFormControlElementsByUniqueRendererId(doc, non_existing_id).IsNull()); +} + TEST_F(FormAutofillUtilsTest, FindFormControlElementsByUniqueIdNoForm) { LoadHTML("<body><input id='i1'><input id='i2'><input id='i3'></body>"); WebDocument doc = GetMainFrame()->GetDocument(); diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc index cdb343ce5d9..982cf44b0e1 100644 --- a/chromium/components/autofill/content/renderer/form_cache.cc +++ b/chromium/components/autofill/content/renderer/form_cache.cc @@ -164,7 +164,7 @@ void LogDeprecationMessages(const WebFormControlElement& element) { std::string msg = std::string("autocomplete='") + str + "' is deprecated and will soon be ignored. See http://goo.gl/YjeSsW"; WebConsoleMessage console_message = WebConsoleMessage( - WebConsoleMessage::kLevelWarning, WebString::FromASCII(msg)); + blink::mojom::ConsoleMessageLevel::kWarning, WebString::FromASCII(msg)); element.GetDocument().GetFrame()->AddMessageToConsole(console_message); } } diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector_vocabulary.cc b/chromium/components/autofill/content/renderer/html_based_username_detector_vocabulary.cc index abf4e4bf888..58b653dbc11 100644 --- a/chromium/components/autofill/content/renderer/html_based_username_detector_vocabulary.cc +++ b/chromium/components/autofill/content/renderer/html_based_username_detector_vocabulary.cc @@ -4,7 +4,7 @@ #include "components/autofill/content/renderer/html_based_username_detector_vocabulary.h" -#include "base/macros.h" +#include "base/stl_util.h" namespace autofill { @@ -23,7 +23,7 @@ const char* const kNegativeLatin[] = { "second", "passwort", "middlename", "paroladordine", "codice", "pasvorto", "familyname", "inomboloyokuvula", "modpas", "salasana", "motdepasse", "numeraeleiloaesesi"}; -const int kNegativeLatinSize = arraysize(kNegativeLatin); +const int kNegativeLatinSize = base::size(kNegativeLatin); const char* const kNegativeNonLatin[] = {"fjalëkalim", "የይለፍቃል", @@ -74,7 +74,7 @@ const char* const kNegativeNonLatin[] = {"fjalëkalim", "mậtkhẩu", "פּאַראָל", "ọrọigbaniwọle"}; -const int kNegativeNonLatinSize = arraysize(kNegativeNonLatin); +const int kNegativeNonLatinSize = base::size(kNegativeNonLatin); const char* const kUsernameLatin[] = { "gatti", "uzantonomo", "solonanarana", "nombredeusuario", @@ -86,7 +86,7 @@ const char* const kUsernameLatin[] = { "mosebedisi", "kasutajanimi", "ainmcleachdaidh", "igamalomsebenzisi", "nomdusuari", "lomsebenzisi", "jenengpanganggo", "ingoakaiwhakamahi", "nomeutente", "namapengguna"}; -const int kUsernameLatinSize = arraysize(kUsernameLatin); +const int kUsernameLatinSize = base::size(kUsernameLatin); const char* const kUsernameNonLatin[] = {"用户名", "کاتيجونالو", @@ -146,7 +146,7 @@ const char* const kUsernameNonLatin[] = {"用户名", "ব্যবহারকারীরনাম", "užívateľskémeno", "ឈ្មោះអ្នកប្រើប្រាស់"}; -const int kUsernameNonLatinSize = arraysize(kUsernameNonLatin); +const int kUsernameNonLatinSize = base::size(kUsernameNonLatin); const char* const kUserLatin[] = { "user", "wosuta", "gebruiker", "utilizator", @@ -159,7 +159,7 @@ const char* const kUserLatin[] = { "usuari", "kasutaja", "defnyddiwr", "kaiwhakamahi", "utente", "korisnik", "mosebedisi", "foydalanuvchi", "uzanto", "pengguna", "mushandisi"}; -const int kUserLatinSize = arraysize(kUserLatin); +const int kUserLatinSize = base::size(kUserLatin); const char* const kUserNonLatin[] = {"用户", "użytkownik", @@ -218,7 +218,7 @@ const char* const kUserNonLatin[] = {"用户", "пайдаланушы", "အသုံးပြုသူကို", "käyttäjä"}; -const int kUserNonLatinSize = arraysize(kUserNonLatin); +const int kUserNonLatinSize = base::size(kUserNonLatin); const char* const kTechnicalWords[] = { "uid", "newtel", "uaccount", "regaccount", "ureg", @@ -226,9 +226,9 @@ const char* const kTechnicalWords[] = { "loginname", "membername", "uname", "ucreate", "loginmail", "accountname", "umail", "loginreg", "accountid", "loginaccount", "ulogin", "regemail", "newmobile", "accountlogin"}; -const int kTechnicalWordsSize = arraysize(kTechnicalWords); +const int kTechnicalWordsSize = base::size(kTechnicalWords); const char* const kWeakWords[] = {"id", "login", "mail"}; -const int kWeakWordsSize = arraysize(kWeakWords); +const int kWeakWordsSize = base::size(kWeakWords); } // namespace autofill diff --git a/chromium/components/autofill/content/renderer/page_form_analyser_logger.h b/chromium/components/autofill/content/renderer/page_form_analyser_logger.h index 8b9ee53c050..eade038f446 100644 --- a/chromium/components/autofill/content/renderer/page_form_analyser_logger.h +++ b/chromium/components/autofill/content/renderer/page_form_analyser_logger.h @@ -14,7 +14,7 @@ namespace autofill { -using ConsoleLevel = blink::WebConsoleMessage::Level; +using ConsoleLevel = blink::mojom::ConsoleMessageLevel; // ConsoleLogger provides a convenient interface for logging messages to the // DevTools console, both in terms of wrapping and formatting console messages @@ -22,9 +22,11 @@ using ConsoleLevel = blink::WebConsoleMessage::Level; // warnings are displayed first. class PageFormAnalyserLogger { public: - static const ConsoleLevel kError = blink::WebConsoleMessage::kLevelError; - static const ConsoleLevel kWarning = blink::WebConsoleMessage::kLevelWarning; - static const ConsoleLevel kVerbose = blink::WebConsoleMessage::kLevelVerbose; + static const ConsoleLevel kError = blink::mojom::ConsoleMessageLevel::kError; + static const ConsoleLevel kWarning = + blink::mojom::ConsoleMessageLevel::kWarning; + static const ConsoleLevel kVerbose = + blink::mojom::ConsoleMessageLevel::kVerbose; explicit PageFormAnalyserLogger(blink::WebLocalFrame* frame); ~PageFormAnalyserLogger(); diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc index 76068b40eb5..ed933f790ea 100644 --- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc +++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc @@ -13,11 +13,10 @@ #include <vector> #include "base/bind.h" -#include "base/containers/flat_set.h" #include "base/i18n/case_conversion.h" -#include "base/memory/linked_ptr.h" #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" +#include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -26,6 +25,7 @@ #include "components/autofill/content/renderer/form_autofill_util.h" #include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/content/renderer/password_generation_agent.h" +#include "components/autofill/content/renderer/prefilled_values_detector.h" #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_util.h" @@ -99,66 +99,6 @@ bool FillDataContainsFillableUsername(const PasswordFormFillData& fill_data) { !fill_data.username_field.value.empty()); } -// Checks if the prefilled value of the username element is one of the known -// values possibly used as placeholders. The list of possible placeholder -// values comes from popular sites exhibiting this issue. -// TODO(crbug.com/832622): Remove this once a stable solution is in place. -bool PossiblePrefilledUsernameValue(const std::string& username_value) { - // Explicitly create a |StringFlatSet| when constructing - // kPrefilledUsernameValues to work around GCC bug 84849, which causes the - // initializer list not to be properly forwarded to base::flat_set's - // constructor. - using StringFlatSet = base::flat_set<std::string, std::less<>>; - static base::NoDestructor<StringFlatSet> kPrefilledUsernameValues( - StringFlatSet({"3~15个字符,中文字符7个以内", - "Benutzername", - "Digite seu CPF ou e-mail", - "DS Logon Username", - "Email Address", - "email address", - "Email masih kosong", - "Email/手機號碼", - "Enter User Name", - "Identifiant", - "Kullanıcı Adı", - "Kunden-ID", - "Nick", - "Nom Utilisateur", - "Rut", - "Siret", - "this is usually your email address", - "UID/用戶名/Email", - "User Id", - "User Name", - "Username", - "username", - "username or email", - "Username or email:", - "Username/Email", - "Usuario", - "Your email address", - "Имя", - "Логин", - "Логин...", - "כתובת דוא''ל", - "اسم العضو", - "اسم المستخدم", - "الاسم", - "نام کاربری", - "メールアドレス", - "用户名", - "用户名/Email", - "請輸入身份證字號", - "请用微博帐号登录", - "请输入手机号或邮箱", - "请输入邮箱或手机号", - "邮箱/手机/展位号"})); - - return kPrefilledUsernameValues->find( - base::TrimWhitespaceASCII(username_value, base::TRIM_ALL)) != - kPrefilledUsernameValues->end(); -} - // Returns true if password form has username and password fields with either // same or no name and id attributes supplied. bool DoesFormContainAmbiguousOrEmptyNames( @@ -628,6 +568,11 @@ WebInputElement ConvertToWebInput(const WebFormControlElement& element) { return input ? *input : WebInputElement(); } +void LogSendPasswordForm(SendPasswordFormToBrowserProcess value) { + UMA_HISTOGRAM_ENUMERATION("PasswordManager.SendPasswordFormToBrowserProcess", + value); +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -644,6 +589,7 @@ PasswordAutofillAgent::PasswordAutofillAgent( sent_request_to_store_(false), checked_safe_browsing_reputation_(false), focus_state_notifier_(this), + password_generation_agent_(nullptr), binding_(this) { registry->AddInterface( base::Bind(&PasswordAutofillAgent::BindRequest, base::Unretained(this))); @@ -1200,6 +1146,11 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { FormStructureInfo form_structure_info = ExtractFormStructureInfo(password_form->form_data); if (only_visible || WasFormStructureChanged(form_structure_info)) { + if (only_visible) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByOnlyVisible); + } + forms_structure_cache_[form_structure_info.unique_renderer_id] = std::move(form_structure_info); @@ -1207,6 +1158,9 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { continue; } + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormWasNotSent); + WebVector<WebFormControlElement> control_elements_vector; form.GetFormControlElements(control_elements_vector); @@ -1242,7 +1196,10 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { logger->LogPasswordForm(Logger::STRING_FORM_IS_PASSWORD, *password_form); } + password_forms.push_back(std::move(*password_form)); + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByNoFormTag); } } @@ -1267,6 +1224,9 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { form_util::GetCanonicalOriginForDocument(frame->GetDocument()); password_forms.back().signon_realm = GetSignOnRealm(password_forms.back().origin); + password_forms.back().form_data.origin = password_forms.back().origin; + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByNoFormTag); } if (!password_forms.empty()) { sent_request_to_store_ = true; @@ -1304,6 +1264,7 @@ void PasswordAutofillAgent::DidCommitProvisionalLoad( ui::PageTransition transition) { if (!is_same_document_navigation) { checked_safe_browsing_reputation_ = false; + recorded_first_filling_result_ = false; } } @@ -1454,11 +1415,27 @@ void PasswordAutofillAgent::FillUsingRendererIDs( FindUsernamePasswordElements(form_data); if (password_element.IsNull()) { MaybeStoreFallbackData(form_data); + if (form_data.password_field.unique_renderer_id == + FormFieldData::kNotSetFormControlRendererId) { + // If the password_field.unique_renderer_id was not set, this was never + // meant as an honest attempt to fill the form. Therefore, don't log it as + // such. + return; + } + LogFirstFillingResult(form_data, FillingResult::kNoPasswordElement); return; } StoreDataForFillOnAccountSelect(form_data, username_element, password_element); + + // If wait_for_username is true, we don't want to initially fill the form + // until the user types in a valid username. + if (form_data.wait_for_username) { + LogFirstFillingResult(form_data, FillingResult::kWaitForUsername); + return; + } + FillFormOnPasswordReceived(form_data, username_element, password_element, &field_data_manager_, logger.get()); } @@ -1482,8 +1459,13 @@ void PasswordAutofillAgent::FillPasswordForm( // If wait_for_username is true, we don't want to initially fill the form // until the user types in a valid username. - if (form_data.wait_for_username) + if (form_data.wait_for_username) { + LogFirstFillingResult(form_data, FillingResult::kWaitForUsername); return; + } + + if (elements.empty()) + LogFirstFillingResult(form_data, FillingResult::kNoFillableElementsFound); for (auto element : elements) { WebInputElement username_element = !element.IsPasswordFieldForAutofill() @@ -1755,8 +1737,15 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( logger->LogMessage(Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD); // Don't fill username if password can't be set. - if (!IsElementAutocompletable(*password_element)) + if (!IsElementAutocompletable(*password_element)) { + if (logger) { + logger->LogMessage( + Logger::STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT); + } + LogFirstFillingResult(fill_data, + FillingResult::kPasswordElementIsNotAutocompleteable); return false; + } // |current_username| is the username for credentials that are going to be // autofilled. It is selected according to the algorithm: @@ -1775,9 +1764,15 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( bool prefilled_placeholder_username = false; if (!username_element->IsNull()) { + // This is a heuristic guess. If the credential is stored for + // www.example.com, the username may be prefilled with "@example.com". + std::string possible_email_domain = + GetRegistryControlledDomain(fill_data.origin); + prefilled_placeholder_username = !username_element->Value().IsEmpty() && - (PossiblePrefilledUsernameValue(username_element->Value().Utf8()) || + (PossiblePrefilledUsernameValue(username_element->Value().Utf8(), + possible_email_domain) || username_may_use_prefilled_placeholder); if (!username_element->Value().IsEmpty() && !prefilled_placeholder_username) { @@ -1802,7 +1797,18 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( !prefilled_placeholder_username) { LogPrefilledUsernameFillOutcome( PrefilledUsernameFillOutcome::kPrefilledUsernameNotOverridden); + if (logger) + logger->LogMessage(Logger::STRING_FAILED_TO_FILL_PREFILLED_USERNAME); + LogFirstFillingResult( + fill_data, FillingResult::kUsernamePrefilledWithIncompatibleValue); + return false; + } + if (logger) { + logger->LogMessage( + Logger::STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME); } + LogFirstFillingResult(fill_data, + FillingResult::kFoundNoPasswordForUsername); return false; } @@ -1840,8 +1846,6 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( field_data_manager->UpdateFieldDataMap( *password_element, password, FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD); - ProvisionallySavePassword(password_element->Form(), *password_element, - RESTRICTION_NONE); gatekeeper_.RegisterElement(password_element); password_element->SetAutofillState(WebAutofillState::kAutofilled); @@ -1856,6 +1860,7 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( autofilled_elements_cache_.emplace( password_element->UniqueRendererFormControlId(), WebString::FromUTF16(password)); + LogFirstFillingResult(fill_data, FillingResult::kSuccess); return true; } @@ -1885,13 +1890,24 @@ bool PasswordAutofillAgent::FillFormOnPasswordReceived( cur_frame = cur_frame->Parent(); if (!IsPublicSuffixDomainMatch( bottom_frame_origin.Utf8(), - cur_frame->GetSecurityOrigin().ToString().Utf8())) + cur_frame->GetSecurityOrigin().ToString().Utf8())) { + if (logger) + logger->LogMessage(Logger::STRING_FAILED_TO_FILL_INTO_IFRAME); + LogFirstFillingResult(fill_data, FillingResult::kBlockedByFrameHierarchy); return false; + } } // If we can't modify the password, don't try to set the username - if (!IsElementAutocompletable(password_element)) + if (!IsElementAutocompletable(password_element)) { + if (logger) { + logger->LogMessage( + Logger::STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT); + } + LogFirstFillingResult(fill_data, + FillingResult::kPasswordElementIsNotAutocompleteable); return false; + } bool exact_username_match = username_element.IsNull() || IsElementEditable(username_element); @@ -2046,6 +2062,20 @@ void PasswordAutofillAgent::MaybeStoreFallbackData( last_supplied_password_info_iter_ = web_input_to_password_info_.begin(); } +void PasswordAutofillAgent::LogFirstFillingResult( + const PasswordFormFillData& form_data, + FillingResult result) { + if (recorded_first_filling_result_) + return; + UMA_HISTOGRAM_ENUMERATION("PasswordManager.FirstRendererFillingResult", + result); + if (form_data.has_renderer_ids) { + GetPasswordManagerDriver()->LogFirstFillingResult( + form_data.form_renderer_id, base::strict_cast<int32_t>(result)); + } + recorded_first_filling_result_ = true; +} + PasswordAutofillAgent::FormStructureInfo PasswordAutofillAgent::ExtractFormStructureInfo(const FormData& form_data) { FormStructureInfo result; @@ -2067,33 +2097,53 @@ PasswordAutofillAgent::ExtractFormStructureInfo(const FormData& form_data) { bool PasswordAutofillAgent::WasFormStructureChanged( const FormStructureInfo& form_info) const { - if (form_info.unique_renderer_id == FormData::kNotSetFormRendererId) + if (form_info.unique_renderer_id == FormData::kNotSetFormRendererId) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormWithoutId); return true; + } auto cached_form = forms_structure_cache_.find(form_info.unique_renderer_id); - if (cached_form == forms_structure_cache_.end()) + if (cached_form == forms_structure_cache_.end()) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentAsNewlyAdded); return true; + } const FormStructureInfo& cached_form_info = cached_form->second; - if (form_info.fields.size() != cached_form_info.fields.size()) + if (form_info.fields.size() != cached_form_info.fields.size()) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange); return true; + } for (size_t i = 0; i < form_info.fields.size(); ++i) { const FormFieldInfo& form_field = form_info.fields[i]; const FormFieldInfo& cached_form_field = cached_form_info.fields[i]; - if (form_field.unique_renderer_id != cached_form_field.unique_renderer_id) + if (form_field.unique_renderer_id != cached_form_field.unique_renderer_id) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange); return true; + } - if (form_field.form_control_type != cached_form_field.form_control_type) + if (form_field.form_control_type != cached_form_field.form_control_type) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange); return true; + } if (form_field.autocomplete_attribute != - cached_form_field.autocomplete_attribute) + cached_form_field.autocomplete_attribute) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange); return true; + } if (form_field.is_focusable != cached_form_field.is_focusable) { + LogSendPasswordForm( + SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange); return true; } } diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h index f4f300a90d7..01cc65b4e55 100644 --- a/chromium/components/autofill/content/renderer/password_autofill_agent.h +++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h @@ -60,6 +60,61 @@ enum class PrefilledUsernameFillOutcome { kMaxValue = kPrefilledUsernameNotOverridden, }; +// Used in UMA histograms, please do NOT reorder. +// Metric: "PasswordManager.SendPasswordFormToBrowserProcess". +// This metrics is relevant for PasswordAutofillAgent::SendPasswordForms method. +enum class SendPasswordFormToBrowserProcess { + // Password form wasn't sent to the browser process. + kPasswordFormWasNotSent = 0, + // Password form was sent, because only_visible == true. + kPasswordFormSentByOnlyVisible = 1, + // Password form was sent, because it's newly added form. + kPasswordFormSentAsNewlyAdded = 2, + // Password form was sent, because the form structure was changed. + kPasswordFormSentByStructureChange = 3, + // Password form was sent, because there is no form-tag. + kPasswordFormSentByNoFormTag = 4, + // Password form was sent, because there is no id. this should never happen; + // this enum value exists only for checking. + kPasswordFormWithoutId = 5, + kMaxValue = kPasswordFormWithoutId, +}; + +// Used in UMA histogram, please do NOT reorder. +// Metric: "PasswordManager.FirstRendererFillingResult". +// This metric records whether the PasswordAutofillAgent succeeded in filling +// credentials after being instructed to do so by the browser process. +enum class FillingResult { + kSuccess = 0, + // The password element to be filled has not been found. + kNoPasswordElement = 1, + // Filling only happens in iframes, if all parent frames PSL match the + // security origin of the iframe containing the password field. + kBlockedByFrameHierarchy = 2, + // Passwords are not filled into fields that are not editable. + kPasswordElementIsNotAutocompleteable = 3, + // The username field contains a string that does not match the username of + // any available credential. + kUsernamePrefilledWithIncompatibleValue = 4, + // No credential was filled due to mismatches with the username. This can + // happen in a number of cases: In case the username field is empty and + // readonly. In case of a username-first-flow where a user's credentials do + // contain a username but the form contains only a password field and no + // username field. In case of change password forms that contain no username + // field. In case the user name is given on a page but only PSL matched + // credentials exist for this username. There may be further cases. + kFoundNoPasswordForUsername = 5, + // Renderer was instructed to wait until user has manually picked a + // credential. This happens for example if the session is an incognito + // session, the credendial's URL matches the mainframe only via the PSL, the + // site is on HTTP, or the form has no current password field. + // PasswordManager.FirstWaitForUsernameReason records the root causes. + kWaitForUsername = 6, + // No fillable elements were found, only possible for old form parser. + kNoFillableElementsFound = 7, + kMaxValue = kNoFillableElementsFound, +}; + // Names of HTML attributes to show form and field signatures for debugging. extern const char kDebugAttributeForFormSignature[]; extern const char kDebugAttributeForFieldSignature[]; @@ -407,6 +462,13 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, // |form_data|. void MaybeStoreFallbackData(const PasswordFormFillData& form_data); + // Records whether filling succeeded for the first attempt to fill on a site. + // The logging is a bit conservative: It is possible that user-perceived + // navigations (via dynamic HTML sites) not trigger any actual navigations + // and therefore, the |recorded_first_filling_result_| never gets reset. + void LogFirstFillingResult(const PasswordFormFillData& form_data, + FillingResult result); + // Extracts information about form structure. static FormStructureInfo ExtractFormStructureInfo(const FormData& form_data); // Checks whether the form structure (amount of elements, element types etc) @@ -494,6 +556,12 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, // structure. Replace FormData with a smaller structure. std::map<unsigned /*unique renderer element id*/, FormStructureInfo> forms_structure_cache_; + + // Flag to prevent that multiple PasswordManager.FirstRendererFillingResult + // UMA metrics are recorded per page load. This is reset on + // DidCommitProvisionalLoad() but only for non-same-document-navigations. + bool recorded_first_filling_result_ = false; + DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent); }; diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc index ae0bd7edc5d..ad4e5dda58f 100644 --- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc +++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc @@ -660,8 +660,8 @@ bool GetPasswordForm( // attributes) the passwords list is empty, build list based on user input (if // there is any non-empty password field) and the type of a field. Also mark // that the form should be available only for fallback saving (automatic - // bubble will not pop up). - password_form->only_for_fallback_saving = plausible_passwords.empty(); + // bubble will not pop up) and filling. + password_form->only_for_fallback = plausible_passwords.empty(); if (plausible_passwords.empty()) { plausible_passwords = std::move(passwords_without_heuristics); preceding_text_input_for_plausible_password = diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc index d2875aeb3f8..70e756afe3d 100644 --- a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc +++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc @@ -5,7 +5,7 @@ #include <stddef.h> #include <memory> -#include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -187,19 +187,10 @@ class PasswordFormBuilder { DISALLOW_COPY_AND_ASSIGN(PasswordFormBuilder); }; -// RenderViewTest-based tests crash on Android -// http://crbug.com/187500 -#if defined(OS_ANDROID) -#define MAYBE_PasswordFormConversionUtilsTest \ - DISABLED_PasswordFormConversionUtilsTest -#else -#define MAYBE_PasswordFormConversionUtilsTest PasswordFormConversionUtilsTest -#endif // defined(OS_ANDROID) - -class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest { +class PasswordFormConversionUtilsTest : public content::RenderViewTest { public: - MAYBE_PasswordFormConversionUtilsTest() {} - ~MAYBE_PasswordFormConversionUtilsTest() override {} + PasswordFormConversionUtilsTest() = default; + ~PasswordFormConversionUtilsTest() override = default; protected: // Loads the given |html|, retrieves the sole WebFormElement from it, and then @@ -296,12 +287,12 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest { UsernameDetectorCache username_detector_cache_; private: - DISALLOW_COPY_AND_ASSIGN(MAYBE_PasswordFormConversionUtilsTest); + DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest); }; } // namespace -TEST_F(MAYBE_PasswordFormConversionUtilsTest, BasicFormAttributes) { +TEST_F(PasswordFormConversionUtilsTest, BasicFormAttributes) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username", "johnsmith", nullptr); builder.AddSubmitButton("inactive_submit"); @@ -314,7 +305,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, BasicFormAttributes) { LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ("data:", password_form->signon_realm); EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); @@ -327,7 +318,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, BasicFormAttributes) { EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) { +TEST_F(PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username", "johnsmith", nullptr); builder.AddDisabledUsernameField(); @@ -339,7 +330,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); @@ -350,7 +341,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) { // be not null. It must contain only minimal information, so that it is not used // for fill on load, for example. It must contain the full FormData, so that the // new parser can be run as well. -TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyDisabledFields) { +TEST_F(PasswordFormConversionUtilsTest, OnlyDisabledFields) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddDisabledUsernameField(); builder.AddDisabledPasswordField(); @@ -366,8 +357,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyDisabledFields) { EXPECT_EQ(2u, password_form->form_data.fields.size()); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - HTMLDetector_DeveloperGroupAttributes) { +TEST_F(PasswordFormConversionUtilsTest, HTMLDetector_DeveloperGroupAttributes) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( password_manager::features::kHtmlBasedUsernameDetector); @@ -454,7 +444,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, "id", "123"}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i); PasswordFormBuilder builder(kTestFormActionURL); @@ -489,7 +479,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, HTMLDetector_SeveralDetections) { +TEST_F(PasswordFormConversionUtilsTest, HTMLDetector_SeveralDetections) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( password_manager::features::kHtmlBasedUsernameDetector); @@ -522,8 +512,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, HTMLDetector_SeveralDetections) { username_detector_cache_.begin()->second[0].NameForAutofill().Utf8()); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - HTMLDetector_UserGroupAttributes) { +TEST_F(PasswordFormConversionUtilsTest, HTMLDetector_UserGroupAttributes) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( password_manager::features::kHtmlBasedUsernameDetector); @@ -606,7 +595,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, "name1", "johnsmith"}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i); PasswordFormBuilder builder(kTestFormActionURL); @@ -643,7 +632,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, HTMLDetectorCache) { +TEST_F(PasswordFormConversionUtilsTest, HTMLDetectorCache) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( password_manager::features::kHtmlBasedUsernameDetector); @@ -719,8 +708,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, HTMLDetectorCache) { base::Bucket(UsernameDetectionMethod::HTML_BASED_CLASSIFIER, 2))); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - HTMLDetectorCache_SkipSomePredictions) { +TEST_F(PasswordFormConversionUtilsTest, HTMLDetectorCache_SkipSomePredictions) { // The cache of HTML based username detector may contain several predictions // (in the order of decreasing reliability) for the given form, but the // detector should consider only |possible_usernames| passed to @@ -764,7 +752,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, EXPECT_EQ(base::UTF8ToUTF16("id"), password_form->username_element); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, IdentifyingUsernameFieldsWithBaseHeuristic) { // Each test case consists of a set of parameters to be plugged into the // PasswordFormBuilder below, plus the corresponding expectations. @@ -839,7 +827,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, "John", "William+usrname2, Smith+usrname3"}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { for (size_t nonempty_username_fields = 0; nonempty_username_fields < 2; ++nonempty_username_fields) { SCOPED_TRACE(testing::Message() @@ -870,7 +858,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element), password_form->username_element); @@ -892,7 +880,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) { +TEST_F(PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) { // Each test case consists of a set of parameters to be plugged into the // PasswordFormBuilder below, plus the corresponding expectations. struct TestCase { @@ -916,7 +904,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) { {{"", "beta"}, "password1", "", "password2", "beta", ""}, {{"alpha", "beta"}, "password1", "alpha", "password2", "beta", ""}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i); PasswordFormBuilder builder(kTestFormActionURL); @@ -931,7 +919,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) { LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value), @@ -953,7 +941,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) { } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) { +TEST_F(PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) { // Each test case consists of a set of parameters to be plugged into the // PasswordFormBuilder below, plus the corresponding expectations. struct TestCase { @@ -985,7 +973,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) { // them the same for now to keep our abstract interpretation less flaky. {{"", "", ""}, "password1", "", "password2", "", "password3"}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i); PasswordFormBuilder builder(kTestFormActionURL); @@ -1001,7 +989,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) { LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value), @@ -1023,7 +1011,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) { } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, IdentifyingPasswordFieldsWithAutocompleteAttributes) { // Each test case consists of a set of parameters to be plugged into the // PasswordFormBuilder below, plus the corresponding expectations. @@ -1348,7 +1336,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, "usrname2", "Smith"}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i); PasswordFormBuilder builder(kTestFormActionURL); @@ -1366,7 +1354,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); // In the absence of username autocomplete attributes, the username should // be the text input field just before 'current-password' or before // 'new-password', if there is no 'current-password'. @@ -1398,7 +1386,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, UsernameDetection_AutocompleteAttribute) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username", "JohnSmith", "username"); @@ -1418,7 +1406,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, UsernameDetectionMethod::AUTOCOMPLETE_ATTRIBUTE, 1); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisibledTextFields) { +TEST_F(PasswordFormConversionUtilsTest, IgnoreInvisibledTextFields) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddNonDisplayedTextField("nondisplayed1", "nodispalyed_value1"); @@ -1434,7 +1422,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisibledTextFields) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16(""), password_form->password_element); @@ -1442,7 +1430,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisibledTextFields) { EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->new_password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisiblLoginPairs) { +TEST_F(PasswordFormConversionUtilsTest, IgnoreInvisiblLoginPairs) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddNonDisplayedTextField("nondisplayed1", "nodispalyed_value1"); @@ -1462,7 +1450,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisiblLoginPairs) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16(""), password_form->password_element); @@ -1470,7 +1458,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisiblLoginPairs) { EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->new_password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) { +TEST_F(PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddNonDisplayedTextField("username", "William"); @@ -1481,7 +1469,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("William"), @@ -1492,7 +1480,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) { password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonVisibleLoginPair) { +TEST_F(PasswordFormConversionUtilsTest, OnlyNonVisibleLoginPair) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddNonVisibleTextField("username", "William"); @@ -1503,15 +1491,14 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonVisibleLoginPair) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - VisiblePasswordAndInvisibleUsername) { +TEST_F(PasswordFormConversionUtilsTest, VisiblePasswordAndInvisibleUsername) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddNonDisplayedTextField("username", "William"); @@ -1522,14 +1509,14 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, InvisiblePassword_LatestUsernameIsVisible) { PasswordFormBuilder builder(kTestFormActionURL); @@ -1542,14 +1529,14 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, InvisiblePassword_LatestUsernameIsInvisible) { PasswordFormBuilder builder(kTestFormActionURL); @@ -1562,7 +1549,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); @@ -1571,7 +1558,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, // Checks that username/password fields are detected based on user input even if // visibility heuristics disagree. -TEST_F(MAYBE_PasswordFormConversionUtilsTest, UserInput) { +TEST_F(PasswordFormConversionUtilsTest, UserInput) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddNonVisibleTextField("nonvisible_text", "actual_username"); @@ -1602,7 +1589,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, UserInput) { form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("nonvisible_text"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("actual_username"), @@ -1615,8 +1602,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, UserInput) { EXPECT_EQ(base::UTF8ToUTF16(""), password_form->new_password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - TypedPasswordAndUsernameCachedOnPage) { +TEST_F(PasswordFormConversionUtilsTest, TypedPasswordAndUsernameCachedOnPage) { PasswordFormBuilder builder(kTestFormActionURL); // The heuristics should consider only password field with user input (i.e. // password_with_user_input?) and visible username fields (i.e. nickname, @@ -1660,7 +1646,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("visible_text"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("cached_username"), @@ -1675,8 +1661,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, password_form->new_password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - TypedPasswordAndInvisibleUsername) { +TEST_F(PasswordFormConversionUtilsTest, TypedPasswordAndInvisibleUsername) { PasswordFormBuilder builder(kTestFormActionURL); // The heuristics should consider only password field with user input (i.e. // password_with_user_input?) and invisible username fields since all username @@ -1718,7 +1703,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, form, &field_data_manager, nullptr, nullptr); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("this_is_username"), password_form->username_element); @@ -1734,7 +1719,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, password_form->new_password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) { +TEST_F(PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) { PasswordFormBuilder builder("invalid_target"); builder.AddTextField("username", "JohnSmith", nullptr); builder.AddSubmitButton("submit"); @@ -1746,8 +1731,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) { EXPECT_FALSE(password_form); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - InvalidFormDueToNoPasswordFields) { +TEST_F(PasswordFormConversionUtilsTest, InvalidFormDueToNoPasswordFields) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username1", "John", nullptr); builder.AddTextField("username2", "Smith", nullptr); @@ -1759,7 +1743,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, EXPECT_FALSE(password_form); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, ConfusingPasswordFields) { +TEST_F(PasswordFormConversionUtilsTest, ConfusingPasswordFields) { // Each test case consists of a set of parameters to be plugged into the // PasswordFormBuilder below. const char* cases[][3] = { @@ -1772,7 +1756,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, ConfusingPasswordFields) { {"alpha", "alpha", "alpha"}, {"alpha", "beta", "alpha"}}; - for (size_t i = 0; i < arraysize(cases); ++i) { + for (size_t i = 0; i < base::size(cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i); PasswordFormBuilder builder(kTestFormActionURL); @@ -1786,7 +1770,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, ConfusingPasswordFields) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("John"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password1"), password_form->password_element); @@ -1794,7 +1778,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, ConfusingPasswordFields) { } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, ManyPasswordFieldsWithoutAutocompleteAttributes) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username1", "John", nullptr); @@ -1808,14 +1792,14 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("John"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password1"), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16("alpha"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, SetOtherPossiblePasswords) { +TEST_F(PasswordFormConversionUtilsTest, SetOtherPossiblePasswords) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username1", "John", nullptr); builder.AddPasswordField("password1", "alpha1", nullptr); @@ -1849,7 +1833,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, SetOtherPossiblePasswords) { ValueElementVectorToString(password_form->all_possible_passwords)); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, AllPossiblePasswordsIncludeAutofilledValue) { for (bool autofilled_value_was_modified_by_user : {false, true}) { PasswordFormBuilder builder(kTestFormActionURL); @@ -1881,8 +1865,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, - CreditCardNumberWithTypePasswordForm) { +TEST_F(PasswordFormConversionUtilsTest, CreditCardNumberWithTypePasswordForm) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("Credit-card-owner-name", "John Smith", nullptr); builder.AddPasswordField("Credit-card-number", "0000 0000 0000 0000", @@ -1900,7 +1883,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, &predictions, false); EXPECT_TRUE(password_form); - EXPECT_TRUE(password_form->only_for_fallback_saving); + EXPECT_TRUE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("Credit-card-owner-name"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("John Smith"), password_form->username_value); @@ -1910,7 +1893,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, UsernamePredictionFromServer) { +TEST_F(PasswordFormConversionUtilsTest, UsernamePredictionFromServer) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username", "JohnSmith", nullptr); // 'autocomplete' attribute cannot override server's prediction. @@ -1935,7 +1918,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, UsernamePredictionFromServer) { UsernameDetectionMethod::SERVER_SIDE_PREDICTION, 1); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, UsernamePredictionFromServerToEmptyField) { // Tests that if a form has user input and the username prediction by the // server points to an empty field, then the prediction is ignored. @@ -1969,7 +1952,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, EXPECT_EQ(base::UTF8ToUTF16("JohnSmith"), password_form->username_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, CreditCardVerificationNumberWithTypePasswordForm) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("Credit-card-owner-name", "John Smith", nullptr); @@ -1987,7 +1970,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, &predictions, false); EXPECT_TRUE(password_form); - EXPECT_TRUE(password_form->only_for_fallback_saving); + EXPECT_TRUE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("Credit-card-number"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("0000 0000 0000 0000"), @@ -1996,7 +1979,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, EXPECT_EQ(base::UTF8ToUTF16("000"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, CreditCardNumberWithTypePasswordFormWithAutocomplete) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("Credit-card-owner-name", "John Smith", nullptr); @@ -2015,7 +1998,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, &predictions, false); EXPECT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("Credit-card-owner-name"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("John Smith"), password_form->username_value); @@ -2025,7 +2008,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, CreditCardVerificationNumberWithTypePasswordFormWithAutocomplete) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("Credit-card-owner-name", "John Smith", nullptr); @@ -2043,7 +2026,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, &predictions, false); ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("Credit-card-number"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("0000 0000 0000 0000"), @@ -2054,7 +2037,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, EXPECT_EQ(base::UTF8ToUTF16("000"), password_form->new_password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, IsGaiaReauthFormIgnored) { +TEST_F(PasswordFormConversionUtilsTest, IsGaiaReauthFormIgnored) { struct TestCase { const char* origin; struct KeyValue { @@ -2151,7 +2134,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IsGaiaReauthFormIgnored) { } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, IsGaiaWithSkipSavePasswordForm) { +TEST_F(PasswordFormConversionUtilsTest, IsGaiaWithSkipSavePasswordForm) { struct TestCase { const char* origin; bool expected_form_has_skip_save_password; @@ -2185,7 +2168,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IsGaiaWithSkipSavePasswordForm) { } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, IdentifyingFieldsWithoutNameOrIdAttributes) { const char* kEmpty = nullptr; const struct { @@ -2206,7 +2189,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, "anonymous_new_password"}, }; - for (size_t i = 0; i < arraysize(test_cases); ++i) { + for (size_t i = 0; i < base::size(test_cases); ++i) { SCOPED_TRACE(testing::Message() << "Iteration " << i << ", expected_username " << test_cases[i].expected_username_element @@ -2240,7 +2223,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, LoadHTMLAndConvertForm(html, nullptr, false); EXPECT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16(test_cases[i].expected_username_element), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16(test_cases[i].expected_password_element), @@ -2250,7 +2233,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, } } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, TooManyFieldsToParseForm) { +TEST_F(PasswordFormConversionUtilsTest, TooManyFieldsToParseForm) { PasswordFormBuilder builder(kTestFormActionURL); for (size_t i = 0; i < form_util::kMaxParseableFields + 1; ++i) builder.AddTextField("id", "value", "autocomplete"); @@ -2259,7 +2242,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, TooManyFieldsToParseForm) { EXPECT_FALSE(password_form); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyCreditCardFields) { +TEST_F(PasswordFormConversionUtilsTest, OnlyCreditCardFields) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("ccname", "johnsmith", "cc-name"); builder.AddPasswordField("cc_security_code", "0123456789", "cc-csc"); @@ -2269,7 +2252,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyCreditCardFields) { std::unique_ptr<PasswordForm> password_form = LoadHTMLAndConvertForm(html, nullptr, false); EXPECT_TRUE(password_form); - EXPECT_TRUE(password_form->only_for_fallback_saving); + EXPECT_TRUE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("ccname"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("cc_security_code"), @@ -2277,7 +2260,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyCreditCardFields) { EXPECT_EQ(base::UTF8ToUTF16("0123456789"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, +TEST_F(PasswordFormConversionUtilsTest, FieldsWithAndWithoutCreditCardAttributes) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username", "johnsmith", nullptr); @@ -2292,14 +2275,14 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, ASSERT_TRUE(password_form); - EXPECT_FALSE(password_form->only_for_fallback_saving); + EXPECT_FALSE(password_form->only_for_fallback); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, ResetPasswordForm) { +TEST_F(PasswordFormConversionUtilsTest, ResetPasswordForm) { // GetPassword (including HTML classifier) should process correctly forms // without any text fields. base::test::ScopedFeatureList feature_list; @@ -2325,7 +2308,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, ResetPasswordForm) { UsernameDetectionMethod::NO_USERNAME_DETECTED, 1); } -TEST_F(MAYBE_PasswordFormConversionUtilsTest, StickyPasswordType) { +TEST_F(PasswordFormConversionUtilsTest, StickyPasswordType) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("username", "johnsmith", nullptr); builder.AddPasswordField("password", "secret", nullptr); @@ -2362,7 +2345,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, StickyPasswordType) { // Check that Chrome remembers the value typed by the user in cases when it gets // overridden by the page. -TEST_F(MAYBE_PasswordFormConversionUtilsTest, TypedValuePreserved) { +TEST_F(PasswordFormConversionUtilsTest, TypedValuePreserved) { PasswordFormBuilder builder(kTestFormActionURL); builder.AddTextField("fine", "", "username"); builder.AddPasswordField("mangled", "", "current-password"); @@ -2420,7 +2403,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, TypedValuePreserved) { } // Check that non-text fields are ignored. -TEST_F(MAYBE_PasswordFormConversionUtilsTest, NonTextFields) { +TEST_F(PasswordFormConversionUtilsTest, NonTextFields) { PasswordFormBuilder builder(kTestFormActionURL); // Avoid calling the text fields anything related to "username" to prevent the // local HTML classifier from influencing the test result. diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc index 841364a4350..deaa4959b13 100644 --- a/chromium/components/autofill/content/renderer/password_generation_agent.cc +++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc @@ -36,9 +36,10 @@ #include "ui/gfx/geometry/rect.h" using blink::WebAutofillState; -using blink::WebInputElement; +using blink::WebDocument; using blink::WebFormControlElement; using blink::WebFormElement; +using blink::WebInputElement; using blink::WebLocalFrame; namespace autofill { @@ -83,6 +84,28 @@ bool GetAccountCreationPasswordFields( return !passwords->empty(); } +// Returns the renderer id of the next password field in |control_elements| +// after |new_password|. This field is likely to be the confirmation field. +// Returns FormFieldData::kNotSetFormControlRendererId if there is no such +// field. +uint32_t FindConfirmationPasswordFieldId( + const std::vector<WebFormControlElement>& control_elements, + const WebFormControlElement& new_password) { + auto iter = + std::find(control_elements.begin(), control_elements.end(), new_password); + + if (iter == control_elements.end()) + return FormFieldData::kNotSetFormControlRendererId; + + ++iter; + for (; iter != control_elements.end(); ++iter) { + const WebInputElement* input_element = ToWebInputElement(&(*iter)); + if (input_element && input_element->IsPasswordFieldForAutofill()) + return input_element->UniqueRendererFormControlId(); + } + return FormFieldData::kNotSetFormControlRendererId; +} + bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) { return base::ContainsValue(urls, url); } @@ -308,6 +331,7 @@ void PasswordGenerationAgent::DidCommitProvisionalLoad( automatic_generation_element_.Reset(); current_generation_item_.reset(); last_focused_password_element_.Reset(); + generation_enabled_fields_.clear(); } void PasswordGenerationAgent::DidFinishDocumentLoad() { @@ -442,7 +466,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted( std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave()); if (presaved_form) { DCHECK_NE(base::string16(), presaved_form->password_value); - GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form); + GetPasswordGenerationDriver()->PresaveGeneratedPassword(*presaved_form); } // Call UpdateStateForTextChange after the corresponding PasswordFormManager @@ -486,7 +510,27 @@ void PasswordGenerationAgent::FoundFormsEligibleForGeneration( DetermineGenerationElement(); } -void PasswordGenerationAgent::UserTriggeredGeneratePassword() { +void PasswordGenerationAgent::FoundFormEligibleForGeneration( + const NewPasswordFormGenerationData& form) { + generation_enabled_fields_[form.new_password_renderer_id] = form; + + if (mark_generation_element_) { + // Mark the input element with renderer id |form.new_password_renderer_id|. + if (!render_frame()) + return; + WebDocument doc = render_frame()->GetWebFrame()->GetDocument(); + if (doc.IsNull()) + return; + WebFormControlElement new_password_input = + form_util::FindFormControlElementsByUniqueRendererId( + doc, form.new_password_renderer_id); + if (!new_password_input.IsNull()) + new_password_input.SetAttribute("password_creation_field", "1"); + } +} + +void PasswordGenerationAgent::UserTriggeredGeneratePassword( + UserTriggeredGeneratePasswordCallback callback) { if (SetUpUserTriggeredGeneration()) { LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP); autofill::password_generation::PasswordGenerationUIData @@ -499,11 +543,10 @@ void PasswordGenerationAgent::UserTriggeredGeneratePassword() { GetTextDirectionForElement( current_generation_item_->generation_element_), current_generation_item_->form_); - // TODO(crbug.com/845458): remove it. The renderer should never invoke the - // prompt directly. - GetPasswordManagerClient()->ShowManualPasswordGenerationPopup( - password_generation_ui_data); + std::move(callback).Run(std::move(password_generation_ui_data)); current_generation_item_->generation_popup_shown_ = true; + } else { + std::move(callback).Run(base::nullopt); } } @@ -575,7 +618,7 @@ void PasswordGenerationAgent::DetermineGenerationElement() { current_generation_item_.reset(new GenerationItemInfo( *automatic_generation_form_data_, automatic_generation_element_)); } - GetPasswordManagerClient()->GenerationAvailableForForm( + GetPasswordGenerationDriver()->GenerationAvailableForForm( automatic_generation_form_data_->form); return; } @@ -585,46 +628,58 @@ bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() { if (last_focused_password_element_.IsNull() || !render_frame()) return false; - WebFormElement form = last_focused_password_element_.Form(); - std::unique_ptr<PasswordForm> password_form; - std::vector<WebFormControlElement> control_elements; - if (!form.IsNull()) { - password_form = password_agent_->GetPasswordFormFromWebForm(form); - control_elements = form_util::ExtractAutofillableElementsInForm(form); + uint32_t last_focused_password_element_id = + last_focused_password_element_.UniqueRendererFormControlId(); + + bool is_automatic_generation_available = base::ContainsKey( + generation_enabled_fields_, last_focused_password_element_id); + + if (!is_automatic_generation_available) { + WebFormElement form = last_focused_password_element_.Form(); + std::vector<WebFormControlElement> control_elements; + if (!form.IsNull()) { + control_elements = form_util::ExtractAutofillableElementsInForm(form); + } else { + const WebLocalFrame& frame = *render_frame()->GetWebFrame(); + blink::WebDocument doc = frame.GetDocument(); + if (doc.IsNull()) + return false; + control_elements = + form_util::GetUnownedFormFieldElements(doc.All(), nullptr); + } + + MaybeCreateCurrentGenerationItem( + last_focused_password_element_, + FindConfirmationPasswordFieldId(control_elements, + last_focused_password_element_)); } else { - const WebLocalFrame& frame = *render_frame()->GetWebFrame(); - blink::WebDocument doc = frame.GetDocument(); - if (doc.IsNull()) - return false; - password_form = password_agent_->GetPasswordFormFromUnownedInputElements(); - control_elements = - form_util::GetUnownedFormFieldElements(doc.All(), nullptr); + auto it = generation_enabled_fields_.find(last_focused_password_element_id); + MaybeCreateCurrentGenerationItem( + last_focused_password_element_, + it->second.confirmation_password_renderer_id); } - if (!password_form) + if (!current_generation_item_) return false; - std::vector<WebInputElement> password_elements; - GetAccountCreationPasswordFields(control_elements, &password_elements); - password_elements = FindPasswordElementsForGeneration( - password_elements, - PasswordFormGenerationData( - 0, /* form_signature */ - CalculateFieldSignatureByNameAndType( - last_focused_password_element_.NameForAutofill().Utf16(), - last_focused_password_element_.FormControlTypeForAutofill() - .Utf8()))); - // TODO(crbug/866444): remove this once it's impossible that currently focused - // password field isn't found by FindPasswordElementsForGeneration. - if (!std::count(password_elements.begin(), password_elements.end(), - last_focused_password_element_)) + if (current_generation_item_->generation_element_ != + last_focused_password_element_) { return false; - current_generation_item_.reset(new GenerationItemInfo( - last_focused_password_element_, std::move(*password_form), - std::move(password_elements))); - // |automatic_generation_element_| should always generate the UI. + } + + // Automatic generation depends on whether the new parser is on because the + // new parser sends now information to the renderer about fields for + // generation. In case when the new old parser is used the old path for + // automatic generation is used. So detecting which automatic generation + // depends on which parser is used. + // TODO(https://crbug.com/831123): Remove this variable when the old parser is + // gone. + bool automatic_generation_available_with_the_old_parser = + last_focused_password_element_ == automatic_generation_element_; + current_generation_item_->is_manually_triggered_ = - (last_focused_password_element_ != automatic_generation_element_); + !is_automatic_generation_available && + !automatic_generation_available_with_the_old_parser; return true; } @@ -641,10 +696,20 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged( } const WebInputElement* element = ToWebInputElement(&web_element); - if (element && element->IsPasswordFieldForAutofill()) + if (!element) + return false; + + if (element->IsPasswordFieldForAutofill()) last_focused_password_element_ = *element; - if (!element || !current_generation_item_ || + auto it = + generation_enabled_fields_.find(element->UniqueRendererFormControlId()); + if (it != generation_enabled_fields_.end()) { + MaybeCreateCurrentGenerationItem( + *element, it->second.confirmation_password_renderer_id); + } + + if (!current_generation_item_ || *element != current_generation_item_->generation_element_) { return false; } @@ -699,7 +764,7 @@ bool PasswordGenerationAgent::TextDidChangeInTextField( std::unique_ptr<PasswordForm> presaved_form( CreatePasswordFormToPresave()); if (presaved_form) - GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form); + GetPasswordGenerationDriver()->PresaveGeneratedPassword(*presaved_form); } return false; } @@ -737,7 +802,7 @@ bool PasswordGenerationAgent::TextDidChangeInTextField( std::unique_ptr<PasswordForm> presaved_form( CreatePasswordFormToPresave()); if (presaved_form) { - GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form); + GetPasswordGenerationDriver()->PresaveGeneratedPassword(*presaved_form); } } } @@ -770,19 +835,19 @@ void PasswordGenerationAgent::AutomaticGenerationStatusChanged(bool available) { current_generation_item_->generation_element_), current_generation_item_->form_); current_generation_item_->generation_popup_shown_ = true; - GetPasswordManagerClient()->AutomaticGenerationStatusChanged( + GetPasswordGenerationDriver()->AutomaticGenerationStatusChanged( true, password_generation_ui_data); } else { // Hide the generation popup. - GetPasswordManagerClient()->AutomaticGenerationStatusChanged(false, - base::nullopt); + GetPasswordGenerationDriver()->AutomaticGenerationStatusChanged( + false, base::nullopt); } } void PasswordGenerationAgent::ShowEditingPopup() { if (!render_frame()) return; - GetPasswordManagerClient()->ShowPasswordEditingPopup( + GetPasswordGenerationDriver()->ShowPasswordEditingPopup( render_frame()->GetRenderView()->ElementBoundsInWindow( current_generation_item_->generation_element_), *CreatePasswordFormToPresave()); @@ -790,7 +855,7 @@ void PasswordGenerationAgent::ShowEditingPopup() { } void PasswordGenerationAgent::GenerationRejectedByTyping() { - GetPasswordManagerClient()->PasswordGenerationRejectedByTyping(); + GetPasswordGenerationDriver()->PasswordGenerationRejectedByTyping(); } void PasswordGenerationAgent::PasswordNoLongerGenerated() { @@ -813,7 +878,41 @@ void PasswordGenerationAgent::PasswordNoLongerGenerated() { } std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave()); if (presaved_form) - GetPasswordManagerClient()->PasswordNoLongerGenerated(*presaved_form); + GetPasswordGenerationDriver()->PasswordNoLongerGenerated(*presaved_form); +} + +void PasswordGenerationAgent::MaybeCreateCurrentGenerationItem( + WebInputElement element, + uint32_t confirmation_password_renderer_id) { + // Do not create |current_generation_item_| if it already is created for + // |element| or the user accepted generated password. So if the user accepted + // the generated password, generation is not offered on any other field. + if (current_generation_item_ && + (current_generation_item_->generation_element_ == element || + current_generation_item_->password_is_generated_)) + return; + + std::unique_ptr<PasswordForm> password_form = + element.Form().IsNull() + ? password_agent_->GetPasswordFormFromUnownedInputElements() + : password_agent_->GetPasswordFormFromWebForm(element.Form()); + + std::vector<blink::WebInputElement> passwords = {element}; + + WebFormControlElement confirmation_password = + form_util::FindFormControlElementsByUniqueRendererId( + element.GetDocument(), confirmation_password_renderer_id); + + if (!confirmation_password.IsNull()) { + WebInputElement* input = ToWebInputElement(&confirmation_password); + if (input) + passwords.push_back(*input); + } + + current_generation_item_.reset(new GenerationItemInfo( + element, std::move(*password_form), std::move(passwords))); + + element.SetAttribute("aria-autocomplete", "list"); } const mojom::PasswordManagerDriverAssociatedPtr& @@ -822,14 +921,14 @@ PasswordGenerationAgent::GetPasswordManagerDriver() { return password_agent_->GetPasswordManagerDriver(); } -const mojom::PasswordManagerClientAssociatedPtr& -PasswordGenerationAgent::GetPasswordManagerClient() { - if (!password_manager_client_) { +const mojom::PasswordGenerationDriverAssociatedPtr& +PasswordGenerationAgent::GetPasswordGenerationDriver() { + if (!password_generation_client_) { render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( - &password_manager_client_); + &password_generation_client_); } - return password_manager_client_; + return password_generation_client_; } void PasswordGenerationAgent::LogMessage(Logger::StringID message_id) { diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h index 653e8349845..40915c52e06 100644 --- a/chromium/components/autofill/content/renderer/password_generation_agent.h +++ b/chromium/components/autofill/content/renderer/password_generation_agent.h @@ -55,9 +55,12 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, void GeneratedPasswordAccepted(const base::string16& password) override; void FoundFormsEligibleForGeneration( const std::vector<PasswordFormGenerationData>& forms) override; - // Sets |generation_element_| to the focused password field and shows a - // generation popup at this field. - void UserTriggeredGeneratePassword() override; + void FoundFormEligibleForGeneration( + const NewPasswordFormGenerationData& form) override; + // Sets |generation_element_| to the focused password field and responds back + // if the generation was triggered successfully. + void UserTriggeredGeneratePassword( + UserTriggeredGeneratePasswordCallback callback) override; // Returns true if the field being changed is one where a generated password // is being offered. Updates the state of the popup if necessary. @@ -86,7 +89,9 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, #if defined(UNIT_TEST) // This method requests the autofill::mojom::PasswordManagerClient which binds // requests the binding if it wasn't bound yet. - void RequestPasswordManagerClientForTesting() { GetPasswordManagerClient(); } + void RequestPasswordManagerClientForTesting() { + GetPasswordGenerationDriver(); + } #endif protected: @@ -115,7 +120,8 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, const mojom::PasswordManagerDriverAssociatedPtr& GetPasswordManagerDriver(); - const mojom::PasswordManagerClientAssociatedPtr& GetPasswordManagerClient(); + const mojom::PasswordGenerationDriverAssociatedPtr& + GetPasswordGenerationDriver(); // Helper function that will try and populate |password_elements_| and // |possible_account_creation_form_|. @@ -154,6 +160,13 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, // Stops treating a password as generated. void PasswordNoLongerGenerated(); + // Creates |current_generation_item_| for |element| if |element| is a + // generation enabled element. If |current_generation_item_| is already + // created for |element| it is not recreated. + void MaybeCreateCurrentGenerationItem( + blink::WebInputElement element, + uint32_t confirmation_password_renderer_id); + // Runs HTML parsing based classifier and saves its outcome to proto. // TODO(crbug.com/621442): Remove client-side form classifier when server-side // classifier is ready. @@ -200,6 +213,10 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, // the last focused password element. blink::WebInputElement last_focused_password_element_; + // Contains correspondence between generaiton enabled element and data for + // generation. + std::map<uint32_t, NewPasswordFormGenerationData> generation_enabled_fields_; + // If this feature is enabled. Controlled by Finch. bool enabled_; @@ -211,7 +228,7 @@ class PasswordGenerationAgent : public content::RenderFrameObserver, // in password fields are updated. PasswordAutofillAgent* password_agent_; - mojom::PasswordManagerClientAssociatedPtr password_manager_client_; + mojom::PasswordGenerationDriverAssociatedPtr password_generation_client_; mojo::AssociatedBinding<mojom::PasswordGenerationAgent> binding_; diff --git a/chromium/components/autofill/content/renderer/prefilled_values_detector.cc b/chromium/components/autofill/content/renderer/prefilled_values_detector.cc new file mode 100644 index 00000000000..c20059cf053 --- /dev/null +++ b/chromium/components/autofill/content/renderer/prefilled_values_detector.cc @@ -0,0 +1,107 @@ +// Copyright 2019 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 "components/autofill/content/renderer/prefilled_values_detector.h" + +#include "base/no_destructor.h" +#include "base/strings/string_util.h" + +namespace autofill { + +const base::flat_set<std::string, std::less<>>& KnownUsernamePlaceholders() { + // Explicitly create a |StringFlatSet| when constructing + // kPrefilledUsernameValues to work around GCC bug 84849, which causes the + // initializer list not to be properly forwarded to base::flat_set's + // constructor. + using StringFlatSet = base::flat_set<std::string, std::less<>>; + static base::NoDestructor<StringFlatSet> kPrefilledUsernameValues( + StringFlatSet({"___.___.___-__", + "+1", + "3~15个字符,中文字符7个以内", + "benutzername", + "client id", + "codice titolare" + "digite seu cpf ou e-mail", + "ds logon username", + "email", + "email address", + "email masih kosong", + "email/手機號碼", + "e-mail/username", + "e-mail address", + "enter username", + "enter user name", + "identifiant", + "kullanıcı adı", + "kunden-id", + "login", + "nick", + "nom d'usuari", + "nom utilisateur", + "rut", + "siret", + "this is usually your email address", + "tu dni", + "uid/用戶名/email", + "uporabnik...", + "user/codice", + "user id", + "user name", + "username", + "username or email", + "username or email:", + "username/email", + "usuario", + "your email address", + "ååååmmddxxxx", + "아이디 or @이하 모두 입력", + "Имя", + "Имя (логин)" + "Логин", + "Логин...", + "Логин (e-mail)", + "שם משתמש", + "כתובת דוא''ל", + "اسم العضو", + "اسم المستخدم", + "الاسم", + "نام کاربری", + "メールアドレス", + "อีเมล", + "用户名", + "用户名/email", + "邮箱/手机", + "帳號", + "請輸入身份證字號", + "请用微博帐号登录", + "请输入手机号或邮箱", + "请输入邮箱或手机号", + "邮箱/手机/展位号"})); + return *kPrefilledUsernameValues; +} + +bool PossiblePrefilledUsernameValue(const std::string& username_value, + const std::string& possible_email_domain) { + const auto& placeholders = KnownUsernamePlaceholders(); + + std::string normalized_username_value = base::ToLowerASCII( + base::TrimWhitespaceASCII(username_value, base::TRIM_ALL)); + + if (normalized_username_value.empty()) + return true; + + // Check whether the prefilled value looks like "@example.com", + // "@mail.example.com" or other strings matching the regex + // "^@.*possible_email_domain$" where the string possible_email_domain is + // replaced with the value of |possible_email_domain|. + if (normalized_username_value[0] == '@' && !possible_email_domain.empty() && + base::EndsWith(normalized_username_value, possible_email_domain, + base::CompareCase::SENSITIVE)) { + return true; + } + + return placeholders.find(normalized_username_value) != placeholders.end(); +} + +} // namespace autofill diff --git a/chromium/components/autofill/content/renderer/prefilled_values_detector.h b/chromium/components/autofill/content/renderer/prefilled_values_detector.h new file mode 100644 index 00000000000..8c4c732dc26 --- /dev/null +++ b/chromium/components/autofill/content/renderer/prefilled_values_detector.h @@ -0,0 +1,37 @@ +// Copyright 2019 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. + +#ifndef COMPONENTS_AUTOFILL_CONTENT_RENDERER_PREFILLED_VALUES_DETECTOR_H_ +#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_PREFILLED_VALUES_DETECTOR_H_ + +#include <string> + +#include "base/containers/flat_set.h" + +namespace autofill { + +// Returns a set of known username placeholders, all guaranteed to be lower +// case. +// This is only exposed for testing. +const base::flat_set<std::string, std::less<>>& KnownUsernamePlaceholders(); + +// Checks if the prefilled value of the username element is one of the known +// values possibly used as placeholders. The list of possible placeholder +// values comes from popular sites exhibiting this issue. +// +// If |username_value| is in KnownUsernamePlaceholder(), the password manager +// takes the liberty to override the contents of the username field. +// +// The |possible_email_domain| is supposed to be the eTLD+1 for which the +// credential was saved. So if the credential was saved for +// https://www.example.com, there is a chance that the website prefills +// the username field with "@example.com". +// +// TODO(crbug.com/832622): Remove this once a stable solution is in place. +bool PossiblePrefilledUsernameValue(const std::string& username_value, + const std::string& possible_email_domain); + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CONTENT_RENDERER_PREFILLED_VALUES_DETECTOR_H_ diff --git a/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc b/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc new file mode 100644 index 00000000000..6c3250665e3 --- /dev/null +++ b/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc @@ -0,0 +1,37 @@ +// Copyright 2019 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 "components/autofill/content/renderer/prefilled_values_detector.h" + +#include "base/strings/string_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +// Ensure that all entries in KnownUsernamePlaceholders() are lowercase because +// the lowercase string of the website is tested against this set. +TEST(PossiblePrefilledUsernameValue, AllLowerCase) { + for (const auto& entry : KnownUsernamePlaceholders()) + EXPECT_EQ(entry, base::ToLowerASCII(entry)); +} + +TEST(PossiblePrefilledUsernameValue, Whitespace) { + EXPECT_TRUE(PossiblePrefilledUsernameValue(" ", "")); +} + +TEST(PossiblePrefilledUsernameValue, EmailAddress) { + EXPECT_TRUE(PossiblePrefilledUsernameValue("@example.com", "example.com")); + EXPECT_TRUE(PossiblePrefilledUsernameValue("@EXAMPLE.COM", "example.com")); + EXPECT_TRUE(PossiblePrefilledUsernameValue(" @example.com", "example.com")); + EXPECT_TRUE( + PossiblePrefilledUsernameValue("@mail.example.com", "example.com")); + EXPECT_FALSE( + PossiblePrefilledUsernameValue("user@example.com", "example.com")); + EXPECT_FALSE(PossiblePrefilledUsernameValue("@example.com", "foo.com")); + EXPECT_FALSE(PossiblePrefilledUsernameValue("@example.com", "")); + EXPECT_FALSE(PossiblePrefilledUsernameValue("@", "foo.com")); + EXPECT_FALSE(PossiblePrefilledUsernameValue("@", "")); +} + +} // namespace autofill diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc index a6fd8da6d89..582915ac830 100644 --- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc +++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc @@ -4,9 +4,9 @@ #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h" -#include "base/message_loop/message_loop.h" #include "base/optional.h" #include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" #include "components/autofill/content/common/autofill_driver.mojom.h" #include "mojo/public/cpp/bindings/binding.h" #include "testing/gtest/include/gtest/gtest.h" @@ -74,6 +74,8 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver { const GURL& frame_url) override {} void FocusedInputChanged(bool is_fillable, bool is_password_field) override {} + void LogFirstFillingResult(uint32_t form_renderer_id, + int32_t result) override {} // Records whether RecordSavePasswordProgress() gets called. bool called_record_save_; @@ -94,7 +96,7 @@ class TestLogger : public RendererSavePasswordProgressLogger { } // namespace TEST(RendererSavePasswordProgressLoggerTest, SendLog) { - base::MessageLoop loop; + base::test::ScopedTaskEnvironment task_environment; FakeContentPasswordManagerDriver fake_driver; mojom::PasswordManagerDriverPtr driver_ptr = fake_driver.CreateInterfacePtrAndBind(); diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn index 5d4a8b08b0c..46afe629e70 100644 --- a/chromium/components/autofill/core/browser/BUILD.gn +++ b/chromium/components/autofill/core/browser/BUILD.gn @@ -4,6 +4,7 @@ import("//build/config/chrome_build.gni") import("//build/config/jumbo.gni") +import("//build/util/version.gni") import("//testing/libfuzzer/fuzzer_test.gni") jumbo_static_library("browser") { @@ -64,6 +65,8 @@ jumbo_static_library("browser") { "autofill_metadata.h", "autofill_metrics.cc", "autofill_metrics.h", + "autofill_observer.cc", + "autofill_observer.h", "autofill_popup_delegate.h", "autofill_profile.cc", "autofill_profile.h", @@ -79,6 +82,8 @@ jumbo_static_library("browser") { "autofill_provider.h", "autofill_scanner.cc", "autofill_scanner.h", + "autofill_subject.cc", + "autofill_subject.h", "autofill_type.cc", "autofill_type.h", "autofill_wallet_data_type_controller.cc", @@ -126,6 +131,8 @@ jumbo_static_library("browser") { "legal_message_line.h", "local_card_migration_manager.cc", "local_card_migration_manager.h", + "local_card_migration_strike_database.cc", + "local_card_migration_strike_database.h", "name_field.cc", "name_field.h", "password_requirements_spec_fetcher.h", @@ -170,6 +177,8 @@ jumbo_static_library("browser") { "state_names.h", "strike_database.cc", "strike_database.h", + "strike_database_integrator_base.cc", + "strike_database_integrator_base.h", "subkey_requester.cc", "subkey_requester.h", "suggestion.cc", @@ -177,6 +186,8 @@ jumbo_static_library("browser") { "suggestion_selection.cc", "suggestion_selection.h", "sync_utils.h", + "test_data_creator.cc", + "test_data_creator.h", "ui/card_unmask_prompt_controller.h", "ui/card_unmask_prompt_controller_impl.cc", "ui/card_unmask_prompt_controller_impl.h", @@ -265,6 +276,8 @@ jumbo_static_library("browser") { ] } + defines = [ "CHROME_VERSION_MAJOR=" + chrome_version_major ] + configs += [ "//build/config:precompiled_headers" ] public_deps = [ @@ -332,11 +345,15 @@ jumbo_static_library("test_support") { "autofill_test_utils.h", "data_driven_test.cc", "data_driven_test.h", + "mock_autocomplete_history_manager.cc", + "mock_autocomplete_history_manager.h", "payments/test_payments_client.cc", "payments/test_payments_client.h", "suggestion_test_helpers.h", "test_address_normalizer.cc", "test_address_normalizer.h", + "test_autofill_async_observer.cc", + "test_autofill_async_observer.h", "test_autofill_client.cc", "test_autofill_client.h", "test_autofill_clock.cc", @@ -366,6 +383,8 @@ jumbo_static_library("test_support") { "test_legacy_strike_database.h", "test_local_card_migration_manager.cc", "test_local_card_migration_manager.h", + "test_local_card_migration_strike_database.cc", + "test_local_card_migration_strike_database.h", "test_personal_data_manager.cc", "test_personal_data_manager.h", "test_region_data_loader.cc", @@ -483,6 +502,7 @@ source_set("unit_tests") { "autofill_profile_unittest.cc", "autofill_profile_validation_util_unittest.cc", "autofill_profile_validator_unittest.cc", + "autofill_subject_unittest.cc", "autofill_type_unittest.cc", "autofill_wallet_data_type_controller_unittest.cc", "contact_info_unittest.cc", @@ -500,6 +520,7 @@ source_set("unit_tests") { "legacy_strike_database_unittest.cc", "legal_message_line_unittest.cc", "local_card_migration_manager_unittest.cc", + "local_card_migration_strike_database_unittest.cc", "name_field_unittest.cc", "password_generator_fips181_unittest.cc", "password_generator_unittest.cc", @@ -547,6 +568,8 @@ source_set("unit_tests") { ] } + defines = [ "CHROME_VERSION_MAJOR=" + chrome_version_major ] + deps = [ ":browser", ":password_generator", diff --git a/chromium/components/autofill/core/browser/DEPS b/chromium/components/autofill/core/browser/DEPS index 889d6437e66..35cb68b74d4 100644 --- a/chromium/components/autofill/core/browser/DEPS +++ b/chromium/components/autofill/core/browser/DEPS @@ -9,6 +9,13 @@ include_rules = [ "+components/policy", "+components/security_state", "+components/signin/core/browser", + # Use identity_manager.h instead of the below files; + # see https://groups.google.com/a/chromium.org/d/msg/chromium-dev/dgFLuxqZt1o/iEqkyoQQBwAJ for help and info. + "-components/signin/core/browser/fake_profile_oauth2_token_service.h", + "-components/signin/core/browser/profile_oauth2_token_service.h", + "-components/signin/core/browser/fake_signin_manager.h", + "-components/signin/core/browser/signin_manager.h", + "-components/signin/core/browser/signin_manager_base.h", "+components/sync", "+components/variations", "+components/version_info", diff --git a/chromium/components/autofill/core/browser/OWNERS b/chromium/components/autofill/core/browser/OWNERS deleted file mode 100644 index fa37e3a038b..00000000000 --- a/chromium/components/autofill/core/browser/OWNERS +++ /dev/null @@ -1 +0,0 @@ -per-file *password*=vabr@chromium.org diff --git a/chromium/components/autofill/core/browser/address_field_unittest.cc b/chromium/components/autofill/core/browser/address_field_unittest.cc index 4791ab09125..78549dfb657 100644 --- a/chromium/components/autofill/core/browser/address_field_unittest.cc +++ b/chromium/components/autofill/core/browser/address_field_unittest.cc @@ -32,7 +32,8 @@ class AddressFieldTest : public testing::Test { // Downcast for tests. static std::unique_ptr<AddressField> Parse(AutofillScanner* scanner) { std::unique_ptr<FormField> field = AddressField::Parse(scanner); - return base::WrapUnique(static_cast<AddressField*>(field.release())); + return std::unique_ptr<AddressField>( + static_cast<AddressField*>(field.release())); } private: diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl.cc b/chromium/components/autofill/core/browser/address_normalizer_impl.cc index ca78af9d58a..8c2e4f4dfca 100644 --- a/chromium/components/autofill/core/browser/address_normalizer_impl.cc +++ b/chromium/components/autofill/core/browser/address_normalizer_impl.cc @@ -77,9 +77,9 @@ std::unique_ptr<AddressValidator> CreateAddressValidator( std::unique_ptr<Source> source, DeleteOnTaskRunnerStorageUniquePtr storage, LoadRulesListener* load_rules_listener) { - return std::make_unique<AddressValidator>(std::move(source), - base::WrapUnique(storage.release()), - load_rules_listener); + return std::make_unique<AddressValidator>( + std::move(source), std::unique_ptr<Storage>(storage.release()), + load_rules_listener); } } // namespace diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc index f68b96cb66a..d15eb19251a 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc @@ -4,19 +4,27 @@ #include "components/autofill/core/browser/autocomplete_history_manager.h" +#include <unordered_map> +#include <utility> #include <vector> +#include "base/memory/weak_ptr.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/autofill_experiments.h" -#include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/browser/validation.h" +#include "components/autofill/core/browser/webdata/autofill_entry.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "components/prefs/pref_service.h" +#include "components/version_info/version_info.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; namespace autofill { namespace { @@ -69,52 +77,108 @@ void AutocompleteHistoryManager::UMARecorder::OnWebDataServiceRequestDone( AutofillMetrics::LogAutocompleteSuggestions(has_suggestion); } -AutocompleteHistoryManager::AutocompleteHistoryManager( - AutofillDriver* driver, - AutofillClient* autofill_client) - : driver_(driver), - database_(autofill_client->GetDatabase()), - pending_query_handle_(0), - query_id_(0), - external_delegate_(nullptr), - autofill_client_(autofill_client) { - DCHECK(autofill_client_); -} +AutocompleteHistoryManager::QueryHandler::QueryHandler( + int client_query_id, + bool autoselect_first_suggestion, + base::string16 prefix, + base::WeakPtr<SuggestionsHandler> handler) + : client_query_id_(client_query_id), + autoselect_first_suggestion_(autoselect_first_suggestion), + prefix_(prefix), + handler_(std::move(handler)) {} + +AutocompleteHistoryManager::QueryHandler::QueryHandler( + const QueryHandler& original) = default; + +AutocompleteHistoryManager::QueryHandler::~QueryHandler() = default; + +AutocompleteHistoryManager::AutocompleteHistoryManager() + // It is safe to base::Unretained a raw pointer to the current instance, + // as it is already being owned elsewhere and will be cleaned-up properly. + // Also, the map of callbacks will be deleted when this instance is + // destroyed, which means we won't attempt to run one of these callbacks + // beyond the life of this instance. + : request_callbacks_( + {{AUTOFILL_VALUE_RESULT, + base::BindRepeating( + &AutocompleteHistoryManager::OnAutofillValuesReturned, + base::Unretained(this))}, + {AUTOFILL_CLEANUP_RESULT, + base::BindRepeating( + &AutocompleteHistoryManager::OnAutofillCleanupReturned, + base::Unretained(this))}}), + weak_ptr_factory_(this) {} AutocompleteHistoryManager::~AutocompleteHistoryManager() { - CancelPendingQuery(); + CancelAllPendingQueries(); +} + +void AutocompleteHistoryManager::Init( + scoped_refptr<AutofillWebDataService> profile_database, + PrefService* pref_service, + bool is_off_the_record) { + profile_database_ = profile_database; + pref_service_ = pref_service; + is_off_the_record_ = is_off_the_record; + + // No need to run the retention policy in OTR. + if (!is_off_the_record_ && + base::FeatureList::IsEnabled( + autofill::features::kAutocompleteRetentionPolicyEnabled)) { + // Upon successful cleanup, the last cleaned-up major version is being + // stored in this pref. + int last_cleaned_version = pref_service_->GetInteger( + prefs::kAutocompleteLastVersionRetentionPolicy); + if (CHROME_VERSION_MAJOR > last_cleaned_version) { + // Trigger the cleanup. + profile_database_->RemoveExpiredAutocompleteEntries(this); + } + } +} + +base::WeakPtr<AutocompleteHistoryManager> +AutocompleteHistoryManager::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); } void AutocompleteHistoryManager::OnGetAutocompleteSuggestions( int query_id, + bool is_autocomplete_enabled, + bool autoselect_first_suggestion, const base::string16& name, const base::string16& prefix, - const std::string& form_control_type) { - CancelPendingQuery(); + const std::string& form_control_type, + base::WeakPtr<SuggestionsHandler> handler) { + CancelPendingQueries(handler.get()); - query_id_ = query_id; - if (!autofill_client_->IsAutocompleteEnabled() || - form_control_type == "textarea" || + if (!is_autocomplete_enabled || form_control_type == "textarea" || IsInAutofillSuggestionsDisabledExperiment()) { - SendSuggestions(nullptr); + SendSuggestions({}, QueryHandler(query_id, autoselect_first_suggestion, + prefix, handler)); uma_recorder_.OnGetAutocompleteSuggestions(name, 0 /* pending_query_handle */); return; } - if (database_) { - pending_query_handle_ = database_->GetFormValuesForElementName( + if (profile_database_) { + auto query_handle = profile_database_->GetFormValuesForElementName( name, prefix, kMaxAutocompleteMenuItems, this); - uma_recorder_.OnGetAutocompleteSuggestions(name, pending_query_handle_); + uma_recorder_.OnGetAutocompleteSuggestions(name, query_handle); + + // We can simply insert, since |query_handle| is always unique. + pending_queries_.insert( + {query_handle, + QueryHandler(query_id, autoselect_first_suggestion, prefix, handler)}); } } -void AutocompleteHistoryManager::OnWillSubmitForm(const FormData& form) { - if (!autofill_client_->IsAutocompleteEnabled()) - return; - - if (driver_->IsIncognito()) +void AutocompleteHistoryManager::OnWillSubmitForm( + const FormData& form, + bool is_autocomplete_enabled) { + if (!is_autocomplete_enabled || is_off_the_record_) { + Notify(NotificationType::AutocompleteFormSkipped); return; + } // We put the following restriction on stored FormFields: // - non-empty name @@ -137,67 +201,166 @@ void AutocompleteHistoryManager::OnWillSubmitForm(const FormData& form) { } } - if (!values.empty() && database_.get()) - database_->AddFormFields(values); + if (!values.empty() && profile_database_.get()) { + profile_database_->AddFormFields(values); + + Notify(NotificationType::AutocompleteFormSubmitted); + } } void AutocompleteHistoryManager::OnRemoveAutocompleteEntry( const base::string16& name, const base::string16& value) { - if (database_) - database_->RemoveFormValueForElementName(name, value); + if (profile_database_) + profile_database_->RemoveFormValueForElementName(name, value); } -void AutocompleteHistoryManager::SetExternalDelegate( - AutofillExternalDelegate* delegate) { - external_delegate_ = delegate; +void AutocompleteHistoryManager::OnAutocompleteEntrySelected( + const base::string16& value) { + // Try to find the AutofillEntry associated with the given suggestion. + auto last_entries_iter = last_entries_.find(value); + if (last_entries_iter == last_entries_.end()) { + // Not found, therefore nothing to do. Most likely there was a race + // condition, but it's not that big of a deal in the current scenario + // (logging metrics). + NOTREACHED(); + return; + } + + // The AutofillEntry was found, use it to log the DaysSinceLastUsed. + const AutofillEntry& entry = last_entries_iter->second; + base::TimeDelta time_delta = AutofillClock::Now() - entry.date_last_used(); + AutofillMetrics::LogAutocompleteDaysSinceLastUse(time_delta.InDays()); } -void AutocompleteHistoryManager::CancelPendingQuery() { - if (pending_query_handle_) { - if (database_) - database_->CancelRequest(pending_query_handle_); - pending_query_handle_ = 0; +void AutocompleteHistoryManager::CancelPendingQueries( + const SuggestionsHandler* handler) { + if (handler && profile_database_) { + for (auto iter : pending_queries_) { + const QueryHandler& query_handler = iter.second; + + if (query_handler.handler_ && query_handler.handler_.get() == handler) { + profile_database_->CancelRequest(iter.first); + } + } } + + // Cleaning up the map with the cancelled handler to remove cancelled + // requests. + CleanupEntries(handler); +} + +void AutocompleteHistoryManager::OnWebDataServiceRequestDone( + WebDataServiceBase::Handle current_handle, + std::unique_ptr<WDTypedResult> result) { + DCHECK(current_handle); + + if (!result) { + // Returning early here if |result| is null. We've seen this happen on + // Linux due to NFS dismounting and causing sql failures. + // See http://crbug.com/68783. + return; + } + + WDResultType result_type = result->GetType(); + + auto request_callbacks_iter = request_callbacks_.find(result_type); + if (request_callbacks_iter == request_callbacks_.end()) { + // There are no callbacks for this response, hence nothing to do. + return; + } + + request_callbacks_iter->second.Run(current_handle, std::move(result)); } void AutocompleteHistoryManager::SendSuggestions( - const std::vector<base::string16>* autocomplete_results) { + const std::vector<AutofillEntry>& entries, + const QueryHandler& query_handler) { + if (!query_handler.handler_) { + // Either the handler has been destroyed, or it is invalid. + return; + } + + // If there is only one suggestion that is the exact same string as + // what is in the input box, then don't show the suggestion. + bool hide_suggestions = + entries.size() == 1 && query_handler.prefix_ == entries[0].key().value(); + std::vector<Suggestion> suggestions; - if (autocomplete_results) { - for (const auto& result : *autocomplete_results) { - suggestions.push_back(Suggestion(result)); + last_entries_.clear(); + + if (!hide_suggestions) { + for (const AutofillEntry& entry : entries) { + suggestions.push_back(Suggestion(entry.key().value())); + last_entries_.insert({entry.key().value(), AutofillEntry(entry)}); } } - external_delegate_->OnSuggestionsReturned(query_id_, suggestions, false); - query_id_ = 0; + query_handler.handler_->OnSuggestionsReturned( + query_handler.client_query_id_, + query_handler.autoselect_first_suggestion_, suggestions); } -void AutocompleteHistoryManager::OnWebDataServiceRequestDone( - WebDataServiceBase::Handle h, +void AutocompleteHistoryManager::OnAutofillValuesReturned( + WebDataServiceBase::Handle current_handle, std::unique_ptr<WDTypedResult> result) { - DCHECK(pending_query_handle_); - auto current_query_handle = pending_query_handle_; - pending_query_handle_ = 0; - DCHECK(result); - // Returning early here if |result| is NULL. We've seen this happen on - // Linux due to NFS dismounting and causing sql failures. - // See http://crbug.com/68783. - if (!result) { - SendSuggestions(nullptr); - uma_recorder_.OnWebDataServiceRequestDone(current_query_handle, - false /* has_suggestion */); + DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType()); + + auto pending_queries_iter = pending_queries_.find(current_handle); + if (pending_queries_iter == pending_queries_.end()) { + // There's no handler for this query, hence nothing to do. return; } - DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType()); - const WDResult<std::vector<base::string16>>* autofill_result = - static_cast<const WDResult<std::vector<base::string16>>*>(result.get()); - std::vector<base::string16> suggestions = autofill_result->GetValue(); - SendSuggestions(&suggestions); + // Moving the handler since we're erasing the entry. + auto query_handler = std::move(pending_queries_iter->second); + + // Removing the query, as it is no longer pending. + pending_queries_.erase(pending_queries_iter); + + const WDResult<std::vector<AutofillEntry>>* autofill_result = + static_cast<const WDResult<std::vector<AutofillEntry>>*>(result.get()); + std::vector<AutofillEntry> entries = autofill_result->GetValue(); + SendSuggestions(entries, query_handler); uma_recorder_.OnWebDataServiceRequestDone( - current_query_handle, !suggestions.empty() /* has_suggestion */); + current_handle, !entries.empty() /* has_suggestion */); +} + +void AutocompleteHistoryManager::OnAutofillCleanupReturned( + WebDataServiceBase::Handle current_handle, + std::unique_ptr<WDTypedResult> result) { + DCHECK(result); + DCHECK_EQ(AUTOFILL_CLEANUP_RESULT, result->GetType()); + + const WDResult<size_t>* cleanup_wdresult = + static_cast<const WDResult<size_t>*>(result.get()); + + AutofillMetrics::LogNumberOfAutocompleteEntriesCleanedUp( + cleanup_wdresult->GetValue()); + + // Cleanup was successful, update the latest run milestone. + pref_service_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR); + + Notify(NotificationType::AutocompleteCleanupDone); +} + +void AutocompleteHistoryManager::CancelAllPendingQueries() { + if (profile_database_) { + for (const auto& pending_query : pending_queries_) { + profile_database_->CancelRequest(pending_query.first); + } + } + + pending_queries_.clear(); +} + +void AutocompleteHistoryManager::CleanupEntries( + const SuggestionsHandler* handler) { + base::EraseIf(pending_queries_, [handler](const auto& pending_query) { + const QueryHandler& query_handler = pending_query.second; + return !query_handler.handler_ || query_handler.handler_.get() == handler; + }); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.h b/chromium/components/autofill/core/browser/autocomplete_history_manager.h index 84ad773b834..3f5536d2a23 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager.h +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.h @@ -5,57 +5,110 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOCOMPLETE_HISTORY_MANAGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOCOMPLETE_HISTORY_MANAGER_H_ +#include <map> #include <vector> +#include "base/callback.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/autofill/core/browser/autofill_subject.h" +#include "components/autofill/core/browser/suggestion.h" +#include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/form_data.h" +#include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_member.h" +#include "components/prefs/pref_service.h" #include "components/webdata/common/web_data_service_consumer.h" namespace autofill { -class AutofillDriver; -class AutofillExternalDelegate; -class AutofillClient; -struct FormData; - -// Per-tab Autocomplete history manager. Handles receiving form data -// from the renderer and the storing and retrieving of form data +// Per-profile Autocomplete history manager. Handles receiving form data +// from the renderers and the storing and retrieving of form data // through WebDataServiceBase. -class AutocompleteHistoryManager : public WebDataServiceConsumer { +class AutocompleteHistoryManager : public KeyedService, + public WebDataServiceConsumer, + public AutofillSubject { public: - AutocompleteHistoryManager(AutofillDriver* driver, - AutofillClient* autofill_client); + // Interface to be implemented by classes that want to fetch autocomplete + // suggestions. + class SuggestionsHandler { + public: + virtual ~SuggestionsHandler() = default; + + // Function that will be called-back once AutocompleteHistoryManager gets + // the corresponding response from the DB. + // |query_id| is the value given by the implementor when + // OnGetAutocompleteSuggestions was called (it is not the DB query ID). + // |suggestions| is the list of fetched autocomplete suggestions. + virtual void OnSuggestionsReturned( + int query_id, + bool autoselect_first_suggestion, + const std::vector<Suggestion>& suggestions) = 0; + }; + + AutocompleteHistoryManager(); ~AutocompleteHistoryManager() override; - // Pass-through functions that are called by AutofillManager, after it has - // dispatched a message. + // Initializes the instance with the given parameters. + // |profile_database_| is a profile-scope DB used to access autocomplete data. + // |is_off_the_record| indicates wheter the user is currently operating in an + // off-the-record context (i.e. incognito). + void Init(scoped_refptr<AutofillWebDataService> profile_database, + PrefService* pref_service, + bool is_off_the_record); + + // Returns a weak pointer to the current AutocompleteHistoryManager instance. + base::WeakPtr<AutocompleteHistoryManager> GetWeakPtr(); + + // Initiates a DB query to get suggestions given a field's information. + // |query_id| is given by the client as context. + // |is_autocomplete_enabled| is to determine if the feature is enable for the + // requestor's context (e.g. Android WebViews have different contexts). + // |name| is the name of the field, + // |prefix| is the field's values + // |form_control_type| is the field's control type. + // |handler| is weak pointer to the requestor, which we will callback once we + // receive the response. There can only be one pending query per |handler|, + // hence this function will cancel the previous pending query if it hadn't + // already been resolved, at which point no method of the handler will be + // called. virtual void OnGetAutocompleteSuggestions( int query_id, + bool is_autocomplete_enabled, + bool autoselect_first_suggestion, const base::string16& name, const base::string16& prefix, - const std::string& form_control_type); - virtual void OnWillSubmitForm(const FormData& form); + const std::string& form_control_type, + base::WeakPtr<SuggestionsHandler> handler); - // Cancels the currently pending WebDataService query, if there is one. - void CancelPendingQuery(); + // Will save the given input from the |form| as a new, or updated, + // autocomplete entry, which will be served in the future as a suggestion. + // This update is dependent on whether we are running in incognito and if + // autocomplete is enabled or not. + virtual void OnWillSubmitForm(const FormData& form, + bool is_autocomplete_enabled); - // Must be public for the external delegate to use. - void OnRemoveAutocompleteEntry(const base::string16& name, - const base::string16& value); + // WebDataServiceConsumer implementation. + void OnWebDataServiceRequestDone( + WebDataServiceBase::Handle h, + std::unique_ptr<WDTypedResult> result) override; - // Sets our external delegate. - void SetExternalDelegate(AutofillExternalDelegate* delegate); + // Cancels the currently pending WebDataService queries associated with the + // given |handler|. + virtual void CancelPendingQueries(const SuggestionsHandler* handler); - protected: - friend class AutofillManagerTest; + // Must be public for the autofill manager to use. + virtual void OnRemoveAutocompleteEntry(const base::string16& name, + const base::string16& value); - // Sends the stored suggestions plus the new autocomplete results for display - // in the Autofill popup. The parameter may be null if there are no new - // autocomplete additions. - void SendSuggestions(const std::vector<base::string16>* new_results); + // Invoked when the user selected |value| in the Autocomplete drop-down. This + // function logs the DaysSinceLastUse of the Autocomplete entry associated + // with |value|. + virtual void OnAutocompleteEntrySelected(const base::string16& value); private: + friend class AutocompleteHistoryManagerTest; FRIEND_TEST_ALL_PREFIXES(AutocompleteHistoryManagerTest, AutocompleteUMAQueryCreated); @@ -86,33 +139,94 @@ class AutocompleteHistoryManager : public WebDataServiceConsumer { DISALLOW_COPY_AND_ASSIGN(UMARecorder); }; - // WebDataServiceConsumer implementation. - void OnWebDataServiceRequestDone( - WebDataServiceBase::Handle h, - std::unique_ptr<WDTypedResult> result) override; + // Internal data object used to keep a request's context to associate it + // with the appropriate response. + struct QueryHandler { + QueryHandler(int client_query_id, + bool autoselect_first_suggestion, + base::string16 prefix, + base::WeakPtr<SuggestionsHandler> handler); + QueryHandler(const QueryHandler& original); + ~QueryHandler(); + + // Query ID living in the handler's scope, which is NOT the same as the + // database query ID. This ID is unique per frame, but not per profile. + int client_query_id_; + + // Determines whether we should auto-select the first suggestion when + // returning. This value was given by the handler when requesting + // suggestions. + bool autoselect_first_suggestion_; + + // Prefix used to search suggestions, submitted by the handler. + base::string16 prefix_; + + // Weak pointer to the handler instance which will be called-back when + // we get the response for the associate query. + base::WeakPtr<SuggestionsHandler> handler_; + }; - // Provides driver-level context. Must outlive this object. - AutofillDriver* driver_; - scoped_refptr<AutofillWebDataService> database_; + // Sends the autocomplete |suggestions| to the |query_handler|'s handler for + // display in the associated Autofill popup. The parameter may be empty if + // there are no new autocomplete additions. + void SendSuggestions(const std::vector<AutofillEntry>& entries, + const QueryHandler& query_handler); + + // Cancels all outstanding queries and clears out the |pending_queries_| map. + void CancelAllPendingQueries(); + + // Cleans-up the dictionary of |pending_queries_| by checking + // - If any handler instance was destroyed (known via WeakPtr) + // - If the given |handler| pointer is associated with a query. + void CleanupEntries(const SuggestionsHandler* handler); + + // Function handling WebDataService responses of type AUTOFILL_VALUE_RESULT. + // |current_handle| is the DB query handle, and is used to retrieve the + // handler associated with that query. + // |result| contains the Autocomplete suggestions retrieved from the DB that, + // if valid and if the handler exists, are to be returned to the handler. + void OnAutofillValuesReturned(WebDataServiceBase::Handle current_handle, + std::unique_ptr<WDTypedResult> result); + + // Function handling WebDataService responses of type AUTOFILL_CLEANUP_RESULT. + // |current_handle| is the DB query handle, and is used to retrieve the + // handler associated with that query. + // |result| contains the number of entries that were cleaned-up. + void OnAutofillCleanupReturned(WebDataServiceBase::Handle current_handle, + std::unique_ptr<WDTypedResult> result); + + // Must outlive this object. + scoped_refptr<AutofillWebDataService> profile_database_; + + // Map used to store WebDataService response callbacks, associating a + // response's WDResultType to the appropriate callback. + std::map<WDResultType, + base::RepeatingCallback<void(WebDataServiceBase::Handle, + std::unique_ptr<WDTypedResult>)>> + request_callbacks_; + + // The PrefService that this instance uses. Must outlive this instance. + PrefService* pref_service_; // When the manager makes a request from WebDataServiceBase, the database is - // queried on another thread, we record the query handle until we get called - // back. - WebDataServiceBase::Handle pending_query_handle_; - int query_id_; - - // Delegate to perform external processing (display, selection) on - // our behalf. Weak. - AutofillExternalDelegate* external_delegate_; + // queried asynchronously. We associate the query handle to the requestor + // (with some context parameters) and store the association here until we get + // called back. Then we update the initial requestor, and deleting the + // no-longer-pending query from this map. + std::map<WebDataServiceBase::Handle, QueryHandler> pending_queries_; - // Delegate to provide whether or not autocomplete functionality is enabled. - AutofillClient* const autofill_client_; + // Cached results of the last batch of autocomplete suggestions. + // Key are the suggestions' values, and values are the associated + // AutofillEntry. + std::map<base::string16, AutofillEntry> last_entries_; - // Whether IPC is sent. - bool send_ipc_; + // Whether the service is associated with an off-the-record browser context. + bool is_off_the_record_ = false; UMARecorder uma_recorder_; + base::WeakPtrFactory<AutocompleteHistoryManager> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(AutocompleteHistoryManager); }; diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc index cf785b2bc5c..249abd01d70 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc @@ -6,6 +6,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" @@ -14,16 +15,19 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "components/autofill/core/browser/autocomplete_history_manager.h" -#include "components/autofill/core/browser/autofill_external_delegate.h" -#include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/test_autofill_client.h" -#include "components/autofill/core/browser/test_autofill_driver.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" -#include "components/prefs/pref_service.h" +#include "components/prefs/testing_pref_service.h" +#include "components/version_info/version_info.h" #include "components/webdata_services/web_data_service_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -31,6 +35,10 @@ using base::ASCIIToUTF16; using testing::_; +using testing::Eq; +using testing::Field; +using testing::Return; +using testing::UnorderedElementsAre; namespace autofill { @@ -43,44 +51,50 @@ class MockWebDataService : public AutofillWebDataService { base::ThreadTaskRunnerHandle::Get()) {} MOCK_METHOD1(AddFormFields, void(const std::vector<FormFieldData>&)); - - WebDataServiceBase::Handle GetFormValuesForElementName( - const base::string16& name, - const base::string16& prefix, - int limit, - WebDataServiceConsumer* consumer) override { - return mock_handle_; - } - - void set_mock_handle(WebDataServiceBase::Handle handle) { - mock_handle_ = handle; - } + MOCK_METHOD1(CancelRequest, void(int)); + MOCK_METHOD4(GetFormValuesForElementName, + WebDataServiceBase::Handle(const base::string16& name, + const base::string16& prefix, + int limit, + WebDataServiceConsumer* consumer)); + MOCK_METHOD1(RemoveExpiredAutocompleteEntries, + WebDataServiceBase::Handle(WebDataServiceConsumer* consumer)); protected: ~MockWebDataService() override {} - - private: - WebDataServiceBase::Handle mock_handle_ = 0; }; class MockAutofillClient : public TestAutofillClient { public: - MockAutofillClient(scoped_refptr<MockWebDataService> web_data_service) - : web_data_service_(web_data_service), - prefs_(test::PrefServiceForTesting()) {} + MockAutofillClient() : prefs_(test::PrefServiceForTesting()) {} ~MockAutofillClient() override {} - scoped_refptr<AutofillWebDataService> GetDatabase() override { - return web_data_service_; - } PrefService* GetPrefs() override { return prefs_.get(); } private: - scoped_refptr<MockWebDataService> web_data_service_; std::unique_ptr<PrefService> prefs_; DISALLOW_COPY_AND_ASSIGN(MockAutofillClient); }; +class MockSuggestionsHandler + : public AutocompleteHistoryManager::SuggestionsHandler { + public: + MockSuggestionsHandler() : weak_ptr_factory_(this) {} + + MOCK_METHOD3(OnSuggestionsReturned, + void(int query_id, + bool autoselect_first_suggestion, + const std::vector<Suggestion>& suggestions)); + + base::WeakPtr<MockSuggestionsHandler> GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + + private: + base::WeakPtrFactory<MockSuggestionsHandler> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(MockSuggestionsHandler); +}; } // namespace class AutocompleteHistoryManagerTest : public testing::Test { @@ -88,20 +102,62 @@ class AutocompleteHistoryManagerTest : public testing::Test { AutocompleteHistoryManagerTest() {} void SetUp() override { + prefs_ = test::PrefServiceForTesting(); + + // Mock such that we don't trigger the cleanup. + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR); + + // Set time to some arbitrary date. + test_clock.SetNow(base::Time::FromDoubleT(1546889367)); web_data_service_ = base::MakeRefCounted<MockWebDataService>(); - autofill_client_ = std::make_unique<MockAutofillClient>(web_data_service_); - autofill_driver_ = std::make_unique<TestAutofillDriver>(); - autocomplete_manager_ = std::make_unique<AutocompleteHistoryManager>( - autofill_driver_.get(), autofill_client_.get()); + autocomplete_manager_ = std::make_unique<AutocompleteHistoryManager>(); + autocomplete_manager_->Init(web_data_service_, prefs_.get(), false); + } + + void TearDown() override { + // Ensure there are no left-over entries in the map (leak check). + EXPECT_TRUE(PendingQueriesEmpty()); + + autocomplete_manager_.reset(); + } + + bool PendingQueriesEmpty() { + return !autocomplete_manager_ || + autocomplete_manager_->pending_queries_.empty(); } - void TearDown() override { autocomplete_manager_.reset(); } + static bool IsEmptySuggestionVector( + const std::vector<Suggestion>& suggestions) { + return suggestions.empty(); + } + + static bool NonEmptySuggestionVector( + const std::vector<Suggestion>& suggestions) { + return !suggestions.empty(); + } + + std::unique_ptr<WDTypedResult> GetMockedDbResults( + std::vector<AutofillEntry> values) { + return std::make_unique<WDResult<std::vector<AutofillEntry>>>( + AUTOFILL_VALUE_RESULT, values); + } + + AutofillEntry GetAutofillEntry( + const base::string16& name, + const base::string16& value, + const base::Time& date_created = AutofillClock::Now(), + const base::Time& date_last_used = AutofillClock::Now()) { + return AutofillEntry(AutofillKey(name, value), date_created, + date_last_used); + } base::test::ScopedTaskEnvironment scoped_task_environment_; scoped_refptr<MockWebDataService> web_data_service_; std::unique_ptr<AutocompleteHistoryManager> autocomplete_manager_; - std::unique_ptr<AutofillDriver> autofill_driver_; - std::unique_ptr<MockAutofillClient> autofill_client_; + std::unique_ptr<PrefService> prefs_; + base::test::ScopedFeatureList scoped_features; + TestAutofillClock test_clock; }; // Tests that credit card numbers are not sent to the WebDatabase to be saved. @@ -119,8 +175,9 @@ TEST_F(AutocompleteHistoryManagerTest, CreditCardNumberValue) { valid_cc.form_control_type = "text"; form.fields.push_back(valid_cc); - EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0); - autocomplete_manager_->OnWillSubmitForm(form); + EXPECT_CALL(*(web_data_service_.get()), AddFormFields(_)).Times(0); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); } // Contrary test to AutocompleteHistoryManagerTest.CreditCardNumberValue. The @@ -141,7 +198,8 @@ TEST_F(AutocompleteHistoryManagerTest, NonCreditCardNumberValue) { form.fields.push_back(invalid_cc); EXPECT_CALL(*(web_data_service_.get()), AddFormFields(_)).Times(1); - autocomplete_manager_->OnWillSubmitForm(form); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); } // Tests that SSNs are not sent to the WebDatabase to be saved. @@ -159,7 +217,8 @@ TEST_F(AutocompleteHistoryManagerTest, SSNValue) { form.fields.push_back(ssn); EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0); - autocomplete_manager_->OnWillSubmitForm(form); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); } // Verify that autocomplete text is saved for search fields. @@ -178,7 +237,27 @@ TEST_F(AutocompleteHistoryManagerTest, SearchField) { form.fields.push_back(search_field); EXPECT_CALL(*(web_data_service_.get()), AddFormFields(_)).Times(1); - autocomplete_manager_->OnWillSubmitForm(form); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); +} + +TEST_F(AutocompleteHistoryManagerTest, AutocompleteFeatureOff) { + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.origin = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + + // Search field. + FormFieldData search_field; + search_field.label = ASCIIToUTF16("Search"); + search_field.name = ASCIIToUTF16("search"); + search_field.value = ASCIIToUTF16("my favorite query"); + search_field.form_control_type = "search"; + form.fields.push_back(search_field); + + EXPECT_CALL(*(web_data_service_.get()), AddFormFields(_)).Times(0); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/false); } // Tests that text entered into fields specifying autocomplete="off" is not sent @@ -201,7 +280,30 @@ TEST_F(AutocompleteHistoryManagerTest, FieldWithAutocompleteOff) { form.fields.push_back(field); EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0); - autocomplete_manager_->OnWillSubmitForm(form); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); +} + +// Shouldn't save entries when in Incognito mode. +TEST_F(AutocompleteHistoryManagerTest, Incognito) { + autocomplete_manager_->Init(web_data_service_, prefs_.get(), + /*is_off_the_record_=*/true); + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.origin = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + + // Search field. + FormFieldData search_field; + search_field.label = ASCIIToUTF16("Search"); + search_field.name = ASCIIToUTF16("search"); + search_field.value = ASCIIToUTF16("my favorite query"); + search_field.form_control_type = "search"; + form.fields.push_back(search_field); + + EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); } // Tests that text entered into fields that are not focusable is not sent to the @@ -222,7 +324,8 @@ TEST_F(AutocompleteHistoryManagerTest, NonFocusableField) { form.fields.push_back(field); EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0); - autocomplete_manager_->OnWillSubmitForm(form); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); } // Tests that text entered into presentation fields is not sent to the @@ -243,78 +346,530 @@ TEST_F(AutocompleteHistoryManagerTest, PresentationField) { form.fields.push_back(field); EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0); - autocomplete_manager_->OnWillSubmitForm(form); + autocomplete_manager_->OnWillSubmitForm(form, + /*is_autocomplete_enabled=*/true); } -namespace { +// Tests that the Init function will trigger the Autocomplete Retention Policy +// cleanup if the flag is enabled, we're not in OTR and it hadn't run in the +// current major version. +TEST_F(AutocompleteHistoryManagerTest, Init_TriggersCleanup) { + // Enable the feature, and set the major version. + scoped_features.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + + EXPECT_CALL(*web_data_service_, + RemoveExpiredAutocompleteEntries(autocomplete_manager_.get())) + .Times(1); + autocomplete_manager_->Init(web_data_service_, prefs_.get(), + /*is_off_the_record=*/false); +} -class MockAutofillExternalDelegate : public AutofillExternalDelegate { - public: - MockAutofillExternalDelegate(AutofillManager* autofill_manager, - AutofillDriver* autofill_driver) - : AutofillExternalDelegate(autofill_manager, autofill_driver) {} - ~MockAutofillExternalDelegate() override {} +// Tests that the Init function will not trigger the Autocomplete Retention +// Policy when running in OTR. +TEST_F(AutocompleteHistoryManagerTest, Init_OTR_Not_TriggersCleanup) { + // Enable the feature, and set the major version. + scoped_features.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + + EXPECT_CALL(*web_data_service_, + RemoveExpiredAutocompleteEntries(autocomplete_manager_.get())) + .Times(0); + autocomplete_manager_->Init(web_data_service_, prefs_.get(), + /*is_off_the_record=*/true); +} - MOCK_METHOD4(OnSuggestionsReturned, - void(int query_id, - const std::vector<Suggestion>& suggestions, - bool autoselect_first_suggestion, - bool is_all_server_suggestions)); +// Tests that the Init function will not trigger the Autocomplete Retention +// Policy when the feature is disabled. +TEST_F(AutocompleteHistoryManagerTest, + Init_FeatureDisabled_Not_TriggersCleanup) { + // Disable the feature, and set the major version. + scoped_features.InitAndDisableFeature( + features::kAutocompleteRetentionPolicyEnabled); + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + + EXPECT_CALL(*web_data_service_, + RemoveExpiredAutocompleteEntries(autocomplete_manager_.get())) + .Times(0); + autocomplete_manager_->Init(web_data_service_, prefs_.get(), + /*is_off_the_record=*/false); +} - private: - DISALLOW_COPY_AND_ASSIGN(MockAutofillExternalDelegate); -}; +// Tests that the Init function will not trigger the Autocomplete Retention +// Policy when running in a major version that was already cleaned. +TEST_F(AutocompleteHistoryManagerTest, + Init_SameMajorVersion_Not_TriggersCleanup) { + // Enable the feature, and set the major version. + scoped_features.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR); + + EXPECT_CALL(*web_data_service_, + RemoveExpiredAutocompleteEntries(autocomplete_manager_.get())) + .Times(0); + autocomplete_manager_->Init(web_data_service_, prefs_.get(), + /*is_off_the_record=*/false); +} -class TestAutocompleteHistoryManager : public AutocompleteHistoryManager { - public: - TestAutocompleteHistoryManager(AutofillDriver* driver, AutofillClient* client) - : AutocompleteHistoryManager(driver, client) {} +// Make sure our handler is called at the right time. +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_Empty) { + int mocked_db_query_id = 100; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id = 2; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values; + + std::unique_ptr<WDTypedResult> mocked_results = + GetMockedDbResults(expected_values); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id)); + + // Simulate request for suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Setting up mock to verify that DB response triggers a call to the handler's + // OnSuggestionsReturned + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned(test_query_id, + /*autoselect_first_suggestion=*/false, + testing::Truly(IsEmptySuggestionVector))); + + // Simulate response from DB. + autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id, + std::move(mocked_results)); +} - using AutocompleteHistoryManager::SendSuggestions; -}; +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_SingleValue) { + int mocked_db_query_id = 100; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id = 2; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixOne"))}; + + std::unique_ptr<WDTypedResult> mocked_results = + GetMockedDbResults(expected_values); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id)); + + // Simulate request for suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Setting up mock to verify that DB response triggers a call to the handler's + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned( + test_query_id, /*autoselect_first_suggestion=*/false, + UnorderedElementsAre(Field( + &Suggestion::value, expected_values[0].key().value())))); + + // Simulate response from DB. + autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id, + std::move(mocked_results)); +} -// Predicate for GMock. -bool IsEmptySuggestionVector(const std::vector<Suggestion>& suggestions) { - return suggestions.empty(); +// Tests that we are correctly forwarding the value of +// |autoselect_first_suggestion| back to the handler. +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_PassesAutoSelect) { + int mocked_db_query_id = 100; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id = 2; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixOne"))}; + + std::unique_ptr<WDTypedResult> mocked_results = + GetMockedDbResults(expected_values); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id)); + + // Simulate request for suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/true, test_name, test_prefix, "Some Type", + suggestions_handler->GetWeakPtr()); + + // Setting up mock to verify that DB response triggers a call to the handler's + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned( + test_query_id, /*autoselect_first_suggestion=*/true, + UnorderedElementsAre(Field( + &Suggestion::value, expected_values[0].key().value())))); + + // Simulate response from DB. + autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id, + std::move(mocked_results)); } -bool NonEmptySuggestionVector(const std::vector<Suggestion>& suggestions) { - return !suggestions.empty(); +// Tests that we don't return any suggestion if we only have one suggestion that +// is case-sensitive equal to the given prefix. +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_SingleValue_EqualsPrefix) { + int mocked_db_query_id = 100; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id = 2; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values = { + GetAutofillEntry(test_name, test_prefix)}; + + std::unique_ptr<WDTypedResult> mocked_results = + GetMockedDbResults(expected_values); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id)); + + // Simulate request for suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Setting up mock to verify that DB response triggers a call to the handler's + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned(test_query_id, + /*autoselect_first_suggestion=*/false, + testing::Truly(IsEmptySuggestionVector))); + + // Simulate response from DB. + autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id, + std::move(mocked_results)); } -} // namespace +// Tests the case sensitivity of the unique suggestion equal to the prefix +// filter. +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_SingleValue_EqualsPrefix_DiffCase) { + int mocked_db_query_id = 100; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id = 2; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values = { + GetAutofillEntry(test_name, ASCIIToUTF16("someprefix"))}; + + std::unique_ptr<WDTypedResult> mocked_results = + GetMockedDbResults(expected_values); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id)); + + // Simulate request for suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Setting up mock to verify that DB response triggers a call to the handler's + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned( + test_query_id, /*autoselect_first_suggestion=*/false, + UnorderedElementsAre(Field( + &Suggestion::value, expected_values[0].key().value())))); + + // Simulate response from DB. + autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id, + std::move(mocked_results)); +} -// Make sure our external delegate is called at the right time. -TEST_F(AutocompleteHistoryManagerTest, ExternalDelegate) { - TestAutocompleteHistoryManager autocomplete_history_manager( - autofill_driver_.get(), autofill_client_.get()); +TEST_F(AutocompleteHistoryManagerTest, + OnAutocompleteEntrySelected_Found_ShouldLogDays) { + // Setting up by simulating that there was a query for autocomplete + // suggestions, and that two values were found. + int mocked_db_query_id = 100; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id = 2; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + auto test_value = ASCIIToUTF16("SomePrefixOne"); + auto other_test_value = ASCIIToUTF16("SomePrefixOne"); + int days_since_last_use = 10; + + std::vector<AutofillEntry> expected_values = { + GetAutofillEntry(test_name, test_value, + AutofillClock::Now() - base::TimeDelta::FromDays(30), + AutofillClock::Now() - + base::TimeDelta::FromDays(days_since_last_use)), + GetAutofillEntry(test_name, other_test_value, + AutofillClock::Now() - base::TimeDelta::FromDays(30), + AutofillClock::Now() - + base::TimeDelta::FromDays(days_since_last_use))}; + + std::unique_ptr<WDTypedResult> mocked_results = + GetMockedDbResults(expected_values); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id)); + + EXPECT_CALL(*suggestions_handler.get(), OnSuggestionsReturned); + + // Simulate request for suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Simulate response from DB. + autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id, + std::move(mocked_results)); - auto autofill_manager = std::make_unique<AutofillManager>( - autofill_driver_.get(), autofill_client_.get(), "en-US", - AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); + base::HistogramTester histogram_tester; - MockAutofillExternalDelegate external_delegate(autofill_manager.get(), - autofill_driver_.get()); - autocomplete_history_manager.SetExternalDelegate(&external_delegate); + // Now simulate one autocomplete entry being selected, and expect a metric + // being logged for that value alone. + autocomplete_manager_->OnAutocompleteEntrySelected(test_value); - // Should trigger a call to OnSuggestionsReturned, verified by the mock. - EXPECT_CALL(external_delegate, OnSuggestionsReturned(_, _, _, _)); - autocomplete_history_manager.SendSuggestions(nullptr); + histogram_tester.ExpectBucketCount("Autocomplete.DaysSinceLastUse", + days_since_last_use, 1); } -// Verify that no autocomplete suggestion is returned for textarea. -TEST_F(AutocompleteHistoryManagerTest, NoAutocompleteSuggestionsForTextarea) { - TestAutocompleteHistoryManager autocomplete_history_manager( - autofill_driver_.get(), autofill_client_.get()); +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_TwoRequests_OneHandler_Cancels) { + int mocked_db_query_id_first = 100; + int mocked_db_query_id_second = 101; + + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + int test_query_id_first = 2; + int test_query_id_second = 3; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values_first = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixOne"))}; + + std::vector<AutofillEntry> expected_values_second = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixTwo"))}; + + std::unique_ptr<WDTypedResult> mocked_results_first = + GetMockedDbResults(expected_values_first); + + std::unique_ptr<WDTypedResult> mocked_results_second = + GetMockedDbResults(expected_values_second); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id_first)) + .WillOnce(Return(mocked_db_query_id_second)); + + // Simulate request for the first suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_first, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Simulate request for the second suggestions (this will cancel the first + // one). + EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_first)) + .Times(1); + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_second, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler->GetWeakPtr()); + + // Setting up mock to verify that we can get the second response first. + EXPECT_CALL( + *suggestions_handler.get(), + OnSuggestionsReturned( + test_query_id_second, /*autoselect_first_suggestion=*/false, + UnorderedElementsAre(Field( + &Suggestion::value, expected_values_second[0].key().value())))); + + // Simulate response from DB, second request comes back before. + autocomplete_manager_->OnWebDataServiceRequestDone( + mocked_db_query_id_second, std::move(mocked_results_second)); + + // Setting up mock to verify that the handler doesn't get called for the first + // request, which was cancelled. + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned(test_query_id_first, + /*autoselect_first_suggestion=*/false, _)) + .Times(0); + + // Simulate response from DB, first request comes back after. + autocomplete_manager_->OnWebDataServiceRequestDone( + mocked_db_query_id_first, std::move(mocked_results_first)); +} - auto autofill_manager = std::make_unique<AutofillManager>( - autofill_driver_.get(), autofill_client_.get(), "en-US", - AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_InvokeHandler_TwoRequests_TwoHandlers) { + int mocked_db_query_id_first = 100; + int mocked_db_query_id_second = 101; + + auto suggestions_handler_first = std::make_unique<MockSuggestionsHandler>(); + auto suggestions_handler_second = std::make_unique<MockSuggestionsHandler>(); + int test_query_id_first = 2; + int test_query_id_second = 3; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + std::vector<AutofillEntry> expected_values_first = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixOne"))}; + + std::vector<AutofillEntry> expected_values_second = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixTwo"))}; + + std::unique_ptr<WDTypedResult> mocked_results_first = + GetMockedDbResults(expected_values_first); + + std::unique_ptr<WDTypedResult> mocked_results_second = + GetMockedDbResults(expected_values_second); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id_first)) + .WillOnce(Return(mocked_db_query_id_second)); + + // Simulate request for the first suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_first, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler_first->GetWeakPtr()); + + // Simulate request for the second suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_second, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler_second->GetWeakPtr()); + + // Setting up mock to verify that we get the second response first. + EXPECT_CALL( + *suggestions_handler_second.get(), + OnSuggestionsReturned( + test_query_id_second, /*autoselect_first_suggestion=*/false, + UnorderedElementsAre(Field( + &Suggestion::value, expected_values_second[0].key().value())))); + + // Simulate response from DB, second request comes back before. + autocomplete_manager_->OnWebDataServiceRequestDone( + mocked_db_query_id_second, std::move(mocked_results_second)); + + // Setting up mock to verify that we get the first response second. + EXPECT_CALL( + *suggestions_handler_first.get(), + OnSuggestionsReturned( + test_query_id_first, /*autoselect_first_suggestion=*/false, + UnorderedElementsAre(Field(&Suggestion::value, + expected_values_first[0].key().value())))); + + // Simulate response from DB, first request comes back after. + autocomplete_manager_->OnWebDataServiceRequestDone( + mocked_db_query_id_first, std::move(mocked_results_first)); +} - MockAutofillExternalDelegate external_delegate(autofill_manager.get(), - autofill_driver_.get()); - autocomplete_history_manager.SetExternalDelegate(&external_delegate); +TEST_F(AutocompleteHistoryManagerTest, + SuggestionsReturned_CancelOne_ReturnOne) { + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + // Initialize variables for the first handler, which is the one that will be + // cancelled. + auto suggestions_handler_one = std::make_unique<MockSuggestionsHandler>(); + int mocked_db_query_id_one = 100; + int test_query_id_one = 1; + std::vector<AutofillEntry> expected_values_one = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixOne"))}; + std::unique_ptr<WDTypedResult> mocked_results_one = + GetMockedDbResults(expected_values_one); + + // Initialize variables for the second handler, which will be fulfilled. + auto suggestions_handler_two = std::make_unique<MockSuggestionsHandler>(); + int test_query_id_two = 2; + int mocked_db_query_id_two = 101; + std::vector<AutofillEntry> expected_values_two = { + GetAutofillEntry(test_name, ASCIIToUTF16("SomePrefixTwo"))}; + std::unique_ptr<WDTypedResult> mocked_results_two = + GetMockedDbResults(expected_values_two); + + // Simulate first handler request for autocomplete suggestions. + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id_one)) + .WillOnce(Return(mocked_db_query_id_two)); + + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_one, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler_one->GetWeakPtr()); + + // Simlate second handler request for autocomplete suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_two, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler_two->GetWeakPtr()); + + // Simlate first handler cancelling its request. + EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_one)) + .Times(1); + autocomplete_manager_->CancelPendingQueries(suggestions_handler_one.get()); + + // Simulate second handler receiving the suggestions. + EXPECT_CALL( + *suggestions_handler_two.get(), + OnSuggestionsReturned( + test_query_id_two, /*autoselect_first_suggestion=*/false, + UnorderedElementsAre(Field(&Suggestion::value, + expected_values_two[0].key().value())))); + autocomplete_manager_->OnWebDataServiceRequestDone( + mocked_db_query_id_two, std::move(mocked_results_two)); + + // Make sure first handler is not called when the DB responds. + EXPECT_CALL(*suggestions_handler_one.get(), + OnSuggestionsReturned(test_query_id_one, + /*autoselect_first_suggestion=*/false, _)) + .Times(0); + autocomplete_manager_->OnWebDataServiceRequestDone( + mocked_db_query_id_one, std::move(mocked_results_one)); +} +// // Verify that no autocomplete suggestion is returned for textarea and UMA is +// // logged correctly. +TEST_F(AutocompleteHistoryManagerTest, NoAutocompleteSuggestionsForTextarea) { FormData form; form.name = ASCIIToUTF16("MyForm"); form.origin = GURL("http://myform.com/form.html"); @@ -323,109 +878,160 @@ TEST_F(AutocompleteHistoryManagerTest, NoAutocompleteSuggestionsForTextarea) { FormFieldData field; test::CreateTestFormField("Address", "address", "", "textarea", &field); - EXPECT_CALL(external_delegate, - OnSuggestionsReturned(0, testing::Truly(IsEmptySuggestionVector), - false, _)); - autocomplete_history_manager.OnGetAutocompleteSuggestions( - 0, - field.name, - field.value, - field.form_control_type); -} - -// Verify that no autocomplete suggestion is returned for textarea and UMA is -// logged correctly. -TEST_F(AutocompleteHistoryManagerTest, AutocompleteUMAQueryNotCreated) { - TestAutocompleteHistoryManager autocomplete_history_manager( - autofill_driver_.get(), autofill_client_.get()); - auto autofill_manager = std::make_unique<AutofillManager>( - autofill_driver_.get(), autofill_client_.get(), "en-US", - AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned(0, /*autoselect_first_suggestion=*/false, + testing::Truly(IsEmptySuggestionVector))); - MockAutofillExternalDelegate external_delegate(autofill_manager.get(), - autofill_driver_.get()); - autocomplete_history_manager.SetExternalDelegate(&external_delegate); + base::HistogramTester histogram_tester; - FormFieldData field; - test::CreateTestFormField("Address", "address", "", "textarea", &field); + autocomplete_manager_->OnGetAutocompleteSuggestions( + 0, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, field.name, field.value, + field.form_control_type, suggestions_handler->GetWeakPtr()); - base::HistogramTester histogram_tester; - EXPECT_CALL(external_delegate, - OnSuggestionsReturned(0, testing::Truly(IsEmptySuggestionVector), - false, _)); - autocomplete_history_manager.OnGetAutocompleteSuggestions( - 0, field.name, field.value, field.form_control_type); histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 0, 1); histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 1, 0); } -// Verify that autocomplete suggestion is returned and suggestions is logged -// correctly. +// // Verify that autocomplete suggestion is returned and suggestions is logged +// // correctly. TEST_F(AutocompleteHistoryManagerTest, AutocompleteUMAQueryCreated) { - TestAutocompleteHistoryManager autocomplete_history_manager( - autofill_driver_.get(), autofill_client_.get()); - auto autofill_manager = std::make_unique<AutofillManager>( - autofill_driver_.get(), autofill_client_.get(), "en-US", - AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); - - MockAutofillExternalDelegate external_delegate(autofill_manager.get(), - autofill_driver_.get()); - autocomplete_history_manager.SetExternalDelegate(&external_delegate); - + auto suggestions_handler = std::make_unique<MockSuggestionsHandler>(); FormFieldData field; test::CreateTestFormField("Address", "address", "", "text", &field); // Mock returned handle to match it in OnWebDataServiceRequestDone(). - scoped_refptr<AutofillWebDataService> service = - autofill_client_->GetDatabase(); - MockWebDataService* data_service = - static_cast<MockWebDataService*>(service.get()); WebDataServiceBase::Handle mock_handle = 1; - data_service->set_mock_handle(mock_handle); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(field.name, field.value, _, + autocomplete_manager_.get())) + .WillOnce(Return(mock_handle)); // Verify that the query has been created. base::HistogramTester histogram_tester; - EXPECT_CALL(external_delegate, - OnSuggestionsReturned(0, testing::Truly(IsEmptySuggestionVector), - false, _)); - autocomplete_history_manager.OnGetAutocompleteSuggestions( - 0, field.name, field.value, field.form_control_type); + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned(0, /*autoselect_first_suggestion=*/false, + testing::Truly(IsEmptySuggestionVector))); + autocomplete_manager_->OnGetAutocompleteSuggestions( + 0, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, field.name, field.value, + field.form_control_type, suggestions_handler->GetWeakPtr()); histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 1, 1); histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 0, 0); // Mock no suggestion returned and verify that the suggestion UMA is correct. std::unique_ptr<WDTypedResult> result = - std::make_unique<WDResult<std::vector<base::string16>>>( - AUTOFILL_VALUE_RESULT, std::vector<base::string16>()); - autocomplete_history_manager.OnWebDataServiceRequestDone(mock_handle, - std::move(result)); + std::make_unique<WDResult<std::vector<AutofillEntry>>>( + AUTOFILL_VALUE_RESULT, std::vector<AutofillEntry>()); + autocomplete_manager_->OnWebDataServiceRequestDone(mock_handle, + std::move(result)); histogram_tester.ExpectBucketCount("Autofill.AutocompleteSuggestions", 0, 1); histogram_tester.ExpectBucketCount("Autofill.AutocompleteSuggestions", 1, 0); // Changed the returned handle - mock_handle = 2; - data_service->set_mock_handle(mock_handle); // Changed field's name to trigger UMA again. + mock_handle = 2; test::CreateTestFormField("Address", "address1", "", "text", &field); - EXPECT_CALL(external_delegate, - OnSuggestionsReturned(0, testing::Truly(NonEmptySuggestionVector), - false, _)); - autocomplete_history_manager.OnGetAutocompleteSuggestions( - 0, field.name, field.value, field.form_control_type); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(field.name, field.value, _, + autocomplete_manager_.get())) + .WillOnce(Return(mock_handle)); + + EXPECT_CALL(*suggestions_handler.get(), + OnSuggestionsReturned(0, /*autoselect_first_suggestion=*/false, + testing::Truly(NonEmptySuggestionVector))); + autocomplete_manager_->OnGetAutocompleteSuggestions( + 0, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, field.name, field.value, + field.form_control_type, suggestions_handler->GetWeakPtr()); histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 1, 2); histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 0, 0); // Mock one suggestion returned and verify that the suggestion UMA is correct. - std::vector<base::string16> values; - values.push_back(ASCIIToUTF16("value")); - result = std::make_unique<WDResult<std::vector<base::string16>>>( - AUTOFILL_VALUE_RESULT, values); - autocomplete_history_manager.OnWebDataServiceRequestDone(mock_handle, - std::move(result)); + std::vector<AutofillEntry> values; + values.push_back(GetAutofillEntry(field.name, ASCIIToUTF16("value"))); + result = GetMockedDbResults(values); + autocomplete_manager_->OnWebDataServiceRequestDone(mock_handle, + std::move(result)); histogram_tester.ExpectBucketCount("Autofill.AutocompleteSuggestions", 0, 1); histogram_tester.ExpectBucketCount("Autofill.AutocompleteSuggestions", 1, 1); } +TEST_F(AutocompleteHistoryManagerTest, DestructorCancelsRequests) { + int mocked_db_query_id_first = 100; + int mocked_db_query_id_second = 101; + + auto suggestions_handler_first = std::make_unique<MockSuggestionsHandler>(); + auto suggestions_handler_second = std::make_unique<MockSuggestionsHandler>(); + int test_query_id_first = 2; + int test_query_id_second = 3; + auto test_name = ASCIIToUTF16("Some Field Name"); + auto test_prefix = ASCIIToUTF16("SomePrefix"); + + EXPECT_CALL(*web_data_service_, + GetFormValuesForElementName(test_name, test_prefix, _, + autocomplete_manager_.get())) + .WillOnce(Return(mocked_db_query_id_first)) + .WillOnce(Return(mocked_db_query_id_second)); + + // Simulate request for the first suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_first, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler_first->GetWeakPtr()); + + // Simulate request for the second suggestions. + autocomplete_manager_->OnGetAutocompleteSuggestions( + test_query_id_second, /*is_autocomplete_enabled=*/true, + /*autoselect_first_suggestion=*/false, test_name, test_prefix, + "Some Type", suggestions_handler_second->GetWeakPtr()); + + // Expect cancel calls for both requests. + EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_first)) + .Times(1); + EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_second)) + .Times(1); + + autocomplete_manager_.reset(); + + EXPECT_TRUE(PendingQueriesEmpty()); +} + +// Tests that a successful Autocomplete Retention Policy cleanup will +// overwrite the last cleaned major version preference, and will also +// log a Autocomplete.Cleanup metric. +TEST_F(AutocompleteHistoryManagerTest, EntriesCleanup_Success) { + // Set Pref major version to some impossible number. + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, -1); + + EXPECT_EQ(-1, + prefs_->GetInteger(prefs::kAutocompleteLastVersionRetentionPolicy)); + + size_t cleanup_result = 10; + base::HistogramTester histogram_tester; + + autocomplete_manager_->OnWebDataServiceRequestDone( + 1, std::make_unique<WDResult<size_t>>(AUTOFILL_CLEANUP_RESULT, + cleanup_result)); + + EXPECT_EQ(CHROME_VERSION_MAJOR, + prefs_->GetInteger(prefs::kAutocompleteLastVersionRetentionPolicy)); + histogram_tester.ExpectBucketCount("Autocomplete.Cleanup", cleanup_result, 1); +} + +// Tests that AutocompleteHistoryManager::OnWebDataServiceRequestDone does not +// crash on empty results. +TEST_F(AutocompleteHistoryManagerTest, EmptyResult_DoesNotCrash) { + auto empty_unique_ptr = std::unique_ptr<WDTypedResult>(nullptr); + + // The expectation in this test is that the following call doesn't crash. + autocomplete_manager_->OnWebDataServiceRequestDone( + 1, std::move(empty_unique_ptr)); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_address_util.cc b/chromium/components/autofill/core/browser/autofill_address_util.cc index 3a2dafd17c4..34806bcdb77 100644 --- a/chromium/components/autofill/core/browser/autofill_address_util.cc +++ b/chromium/components/autofill/core/browser/autofill_address_util.cc @@ -103,7 +103,7 @@ void GetAddressComponents(const std::string& country_code, components[i - 1].length_hint == AddressUiComponent::HINT_LONG || components[i].length_hint == AddressUiComponent::HINT_LONG) { line = new base::ListValue; - address_components->Append(base::WrapUnique(line)); + address_components->Append(std::unique_ptr<base::ListValue>(line)); // |line| is invalidated at this point, so it needs to be reset. address_components->GetList(address_components->GetSize() - 1, &line); } diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc index fbd2a3cab8f..958759bc688 100644 --- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc @@ -9,14 +9,15 @@ #include "base/callback.h" #include "base/feature_list.h" -#include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" +#include "base/test/scoped_task_environment.h" #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_credit_card_save_manager.h" @@ -37,9 +38,10 @@ class MockAutofillManager : public AutofillManager { public: MockAutofillManager(TestAutofillDriver* driver, TestAutofillClient* client, - PersonalDataManager* pdm) + PersonalDataManager* pdm, + AutocompleteHistoryManager* ahm) // Force to use the constructor designated for unit test. - : AutofillManager(driver, client, pdm) {} + : AutofillManager(driver, client, pdm, ahm) {} virtual ~MockAutofillManager() {} MOCK_METHOD5(FillCreditCardForm, @@ -60,7 +62,11 @@ class MockAutofillManager : public AutofillManager { class AutofillAssistantTest : public testing::Test { protected: AutofillAssistantTest() - : message_loop_(), autofill_client_(), autofill_driver_(), pdm_() {} + : task_environment_(), + autofill_client_(), + autofill_driver_(), + pdm_(), + ahm_() {} void SetUp() { payments::TestPaymentsClient* payments_client = @@ -81,7 +87,7 @@ class AutofillAssistantTest : public testing::Test { std::unique_ptr<TestFormDataImporter>(test_form_data_importer)); autofill_manager_ = std::make_unique<MockAutofillManager>( - &autofill_driver_, &autofill_client_, &pdm_); + &autofill_driver_, &autofill_client_, &pdm_, &ahm_); autofill_assistant_ = std::make_unique<AutofillAssistant>(autofill_manager_.get()); @@ -133,10 +139,11 @@ class AutofillAssistantTest : public testing::Test { return form_structure; } - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; TestAutofillClient autofill_client_; testing::NiceMock<TestAutofillDriver> autofill_driver_; TestPersonalDataManager pdm_; + MockAutocompleteHistoryManager ahm_; std::unique_ptr<MockAutofillManager> autofill_manager_; std::unique_ptr<AutofillAssistant> autofill_assistant_; base::test::ScopedFeatureList scoped_feature_list_; diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h index 5b6ab0ad44a..cb53a600e65 100644 --- a/chromium/components/autofill/core/browser/autofill_client.h +++ b/chromium/components/autofill/core/browser/autofill_client.h @@ -50,9 +50,9 @@ enum class Channel; namespace autofill { class AddressNormalizer; +class AutocompleteHistoryManager; class AutofillPopupDelegate; class AutofillProfile; -class AutofillWebDataService; class CardUnmaskDelegate; class CreditCard; class FormDataImporter; @@ -60,6 +60,7 @@ class FormStructure; class LegacyStrikeDatabase; class MigratableCreditCard; class PersonalDataManager; +class StrikeDatabase; struct Suggestion; namespace payments { @@ -95,6 +96,17 @@ class AutofillClient : public RiskDataLoader { NETWORK_ERROR, }; + enum SaveCardOfferUserDecision { + // The user accepted credit card save. + ACCEPTED, + + // The user explicitly declined credit card save. + DECLINED, + + // The user ignored the credit card save prompt. + IGNORED, + }; + enum UnmaskCardReason { // The card is being unmasked for PaymentRequest. UNMASK_FOR_PAYMENT_REQUEST, @@ -110,11 +122,22 @@ class AutofillClient : public RiskDataLoader { base::string16 expiration_date_month; base::string16 expiration_date_year; }; + + // Callback to run after local credit card save is offered. Sends whether the + // prompt was accepted, declined, or ignored in |user_decision|. + typedef base::OnceCallback<void(SaveCardOfferUserDecision user_decision)> + LocalSaveCardPromptCallback; + + // Callback to run after upload credit card save is offered. Sends whether the + // prompt was accepted, declined, or ignored in |user_decision|, and + // additional |user_provided_card_details| if applicable. typedef base::OnceCallback<void( + SaveCardOfferUserDecision user_decision, const UserProvidedCardDetails& user_provided_card_details)> - UserAcceptedUploadCallback; + UploadSaveCardPromptCallback; typedef base::Callback<void(const CreditCard&)> CreditCardScanCallback; + // Callback to run if user presses the Save button in the migration dialog. // Will pass a vector of GUIDs of cards that the user selected to upload to // LocalCardMigrationManager. @@ -139,8 +162,8 @@ class AutofillClient : public RiskDataLoader { // Gets the PersonalDataManager instance associated with the client. virtual PersonalDataManager* GetPersonalDataManager() = 0; - // Gets the AutofillWebDataService instance associated with the client. - virtual scoped_refptr<AutofillWebDataService> GetDatabase() = 0; + // Gets the AutocompleteHistoryManager instance associate with the client. + virtual AutocompleteHistoryManager* GetAutocompleteHistoryManager() = 0; // Gets the preferences associated with the client. virtual PrefService* GetPrefs() = 0; @@ -161,6 +184,9 @@ class AutofillClient : public RiskDataLoader { // TODO(crbug.com/884817): Delete this once v2 of StrikeDatabase is launched. virtual LegacyStrikeDatabase* GetLegacyStrikeDatabase() = 0; + // Gets the StrikeDatabase associated with the client. + virtual StrikeDatabase* GetStrikeDatabase() = 0; + // Gets the UKM service associated with this client (for metrics). virtual ukm::UkmRecorder* GetUkmRecorder() = 0; @@ -193,11 +219,12 @@ class AutofillClient : public RiskDataLoader { virtual void ShowLocalCardMigrationDialog( base::OnceClosure show_migration_dialog_closure) = 0; - // Shows a dialog with the given |legal_message|. Runs + // Shows a dialog with the given |legal_message| and the |user_email|. Runs // |start_migrating_cards_callback| if the user would like the selected cards // in the |migratable_credit_cards| to be uploaded to cloud. virtual void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) = 0; @@ -218,13 +245,15 @@ class AutofillClient : public RiskDataLoader { virtual void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) = 0; - // Runs |callback| if the |card| should be imported as personal data. On - // desktop, shows the offer-to-save bubble if |show_prompt| is true; otherwise - // only shows the omnibox icon. On mobile, shows the offer-to-save infobar if - // |show_prompt| is true; otherwise does not offer to save at all. - virtual void ConfirmSaveCreditCardLocally(const CreditCard& card, - bool show_prompt, - base::OnceClosure callback) = 0; + // Runs |callback| once the user makes a decision with respect to the + // offer-to-save prompt. On desktop, shows the offer-to-save bubble if + // |show_prompt| is true; otherwise only shows the omnibox icon. On mobile, + // shows the offer-to-save infobar if |show_prompt| is true; otherwise does + // not offer to save at all. + virtual void ConfirmSaveCreditCardLocally( + const CreditCard& card, + bool show_prompt, + LocalSaveCardPromptCallback callback) = 0; #if defined(OS_ANDROID) // Run |callback| if the card should be uploaded to payments with updated @@ -233,21 +262,21 @@ class AutofillClient : public RiskDataLoader { base::OnceCallback<void(const base::string16&)> callback) = 0; #endif // defined(OS_ANDROID) - // Runs |callback| if the |card| should be uploaded to Payments. Displays the - // contents of |legal_message| to the user. Displays a cardholder name - // textfield in the bubble if |should_request_name_from_user| is true. - // Displays a pair of expiration date dropdowns in the bubble if - // |should_request_expiration_date_from_user| is true. On desktop, - // shows the offer-to-save bubble if |show_prompt| is true; otherwise only - // shows the omnibox icon. On mobile, shows the offer-to-save infobar if - // |show_prompt| is true; otherwise does not offer to save at all. + // Runs |callback| once the user makes a decision with respect to the + // offer-to-save prompt. Displays the contents of |legal_message| to the user. + // Displays a cardholder name textfield in the bubble if + // |should_request_name_from_user| is true. Displays a pair of expiration date + // dropdowns in the bubble if |should_request_expiration_date_from_user| is + // true. On desktop, shows the offer-to-save bubble if |show_prompt| is true; + // otherwise only shows the omnibox icon. On mobile, shows the offer-to-save + // infobar if |show_prompt| is true; otherwise does not offer to save at all. virtual void ConfirmSaveCreditCardToCloud( const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, bool should_request_name_from_user, bool should_request_expiration_date_from_user, bool show_prompt, - UserAcceptedUploadCallback callback) = 0; + UploadSaveCardPromptCallback callback) = 0; // Will show an infobar to get user consent for Credit Card assistive filling. // Will run |callback| on success. @@ -295,10 +324,6 @@ class AutofillClient : public RiskDataLoader { const base::string16& autofilled_value, const base::string16& profile_full_name) = 0; - // Inform the client that the user interacted with a non-secure credit card - // field. - virtual void DidInteractWithNonsecureCreditCardInput() = 0; - // If the context is secure. virtual bool IsContextSecure() = 0; diff --git a/chromium/components/autofill/core/browser/autofill_data_model.cc b/chromium/components/autofill/core/browser/autofill_data_model.cc index 72464e8e5bc..913bfe22e69 100644 --- a/chromium/components/autofill/core/browser/autofill_data_model.cc +++ b/chromium/components/autofill/core/browser/autofill_data_model.cc @@ -9,17 +9,17 @@ #include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_constants.h" #include "url/gurl.h" namespace autofill { AutofillDataModel::AutofillDataModel(const std::string& guid, const std::string& origin) - : guid_(guid), - origin_(origin), - use_count_(1), - use_date_(AutofillClock::Now()), - modification_date_(AutofillClock::Now()) {} + : guid_(guid), origin_(origin), use_count_(1) { + set_use_date(AutofillClock::Now()); + set_modification_date(AutofillClock::Now()); +} AutofillDataModel::~AutofillDataModel() {} bool AutofillDataModel::IsVerified() const { @@ -29,7 +29,12 @@ bool AutofillDataModel::IsVerified() const { // TODO(crbug.com/629507): Add support for injected mock clock for testing. void AutofillDataModel::RecordUse() { ++use_count_; - use_date_ = AutofillClock::Now(); + set_use_date(AutofillClock::Now()); +} + +bool AutofillDataModel::UseDateEqualsInSeconds( + const AutofillDataModel* other) const { + return !((other->use_date() - use_date()).InSeconds()); } bool AutofillDataModel::CompareFrecency(const AutofillDataModel* other, @@ -70,4 +75,8 @@ double AutofillDataModel::GetFrecencyScore(base::Time time) const { return -log((time - use_date_).InDays() + 2) / log(use_count_ + 1); } +bool AutofillDataModel::IsDeletable() const { + return use_date_ < AutofillClock::Now() - kDisusedDataModelDeletionTimeDelta; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_data_model.h b/chromium/components/autofill/core/browser/autofill_data_model.h index a9f562ac5ff..719df504e04 100644 --- a/chromium/components/autofill/core/browser/autofill_data_model.h +++ b/chromium/components/autofill/core/browser/autofill_data_model.h @@ -38,9 +38,14 @@ class AutofillDataModel : public FormGroup { size_t use_count() const { return use_count_; } void set_use_count(size_t count) { use_count_ = count; } + // Writing in and reading from database converts dates between time_t and + // Time, therefore the microseconds get lost. Therefore, we need to round the + // dates to seconds for both |use_date_| and |modification_date_|. const base::Time& use_date() const { return use_date_; } void set_use_date(const base::Time& time) { use_date_ = time; } + bool UseDateEqualsInSeconds(const AutofillDataModel* other) const; + const base::Time& modification_date() const { return modification_date_; } // This should only be called from database code. void set_modification_date(const base::Time& time) { @@ -61,6 +66,10 @@ class AutofillDataModel : public FormGroup { // whether the metadata was set. virtual bool SetMetadata(const AutofillMetadata metadata); + // Returns whether the data model is deletable: if it has not been used for + // longer than |kDisusedCreditCardDeletionTimeDelta|. + virtual bool IsDeletable() const; + protected: // Called to update |use_count_| and |use_date_| when this data model is // the subject of user interaction (usually, when it's used to fill a form). @@ -81,10 +90,12 @@ class AutofillDataModel : public FormGroup { // The number of times this model has been used. size_t use_count_; - // The last time the model was used. + // The last time the model was used, rounded in seconds. Any change should + // use set_previous_use_date() base::Time use_date_; - // The last time data in the model was modified. + // The last time data in the model was modified, rounded in seconds. Any + // change should use set_previous_modification_date() base::Time modification_date_; // Returns a score based on both the recency (relative to |time|) and diff --git a/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc index 5ab0d1be3fe..670e50ce8d1 100644 --- a/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc @@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_metadata.h" +#include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "testing/gtest/include/gtest/gtest.h" @@ -95,6 +96,19 @@ TEST(AutofillDataModelTest, SetMetadata) { EXPECT_EQ(metadata.use_date, model.use_date()); } +TEST(AutofillDataModelTest, IsDeletable) { + TestAutofillDataModel model("guid", std::string()); + model.set_use_date(kArbitraryTime); + + TestAutofillClock test_clock; + test_clock.SetNow(kArbitraryTime); + EXPECT_FALSE(model.IsDeletable()); + + test_clock.SetNow(kArbitraryTime + kDisusedDataModelDeletionTimeDelta + + base::TimeDelta::FromDays(1)); + EXPECT_TRUE(model.IsDeletable()); +} + enum Expectation { GREATER, LESS }; struct CompareFrecencyTestCase { const std::string guid_a; diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc index af020675b6e..542571769a6 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util.cc @@ -8,6 +8,7 @@ #include <vector> #include "base/i18n/char_iterator.h" +#include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -114,7 +115,7 @@ bool ContainsString(const char* const set[], void StripPrefixes(std::vector<base::StringPiece16>* name_tokens) { auto iter = name_tokens->begin(); while (iter != name_tokens->end()) { - if (!ContainsString(name_prefixes, arraysize(name_prefixes), *iter)) + if (!ContainsString(name_prefixes, base::size(name_prefixes), *iter)) break; ++iter; } @@ -127,7 +128,7 @@ void StripPrefixes(std::vector<base::StringPiece16>* name_tokens) { // Removes common name suffixes from |name_tokens|. void StripSuffixes(std::vector<base::StringPiece16>* name_tokens) { while (!name_tokens->empty()) { - if (!ContainsString(name_suffixes, arraysize(name_suffixes), + if (!ContainsString(name_suffixes, base::size(name_suffixes), name_tokens->back())) { break; } @@ -216,13 +217,13 @@ bool SplitCJKName(const std::vector<base::StringPiece16>& name_tokens, // ones) surname_length = std::max<size_t>( 1, StartsWithAny(name, korean_multi_char_surnames, - arraysize(korean_multi_char_surnames))); + base::size(korean_multi_char_surnames))); } else { // Default to 1 character if the surname is not in // |common_cjk_multi_char_surnames|. surname_length = std::max<size_t>( 1, StartsWithAny(name, common_cjk_multi_char_surnames, - arraysize(common_cjk_multi_char_surnames))); + base::size(common_cjk_multi_char_surnames))); } parts->family = name.substr(0, surname_length).as_string(); parts->given = name.substr(surname_length).as_string(); @@ -335,7 +336,7 @@ NameParts SplitName(base::StringPiece16 name) { reverse_family_tokens.push_back(name_tokens.back()); name_tokens.pop_back(); while (name_tokens.size() >= 1 && - ContainsString(family_name_prefixes, arraysize(family_name_prefixes), + ContainsString(family_name_prefixes, base::size(family_name_prefixes), name_tokens.back())) { reverse_family_tokens.push_back(name_tokens.back()); name_tokens.pop_back(); diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc index ac679de3a0d..adeb0145dd7 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc @@ -158,9 +158,6 @@ void LogHttpResponseData(AutofillDownloadManager::RequestType request_type, break; default: NOTREACHED(); - base::UmaHistogramSparse("Autofill.Unknown.HttpResponseOrErrorCode", - response_or_error_code); - UMA_HISTOGRAM_TIMES("Autofill.Unknown.RequestDuration", request_duration); } } @@ -179,8 +176,6 @@ void LogFailingPayloadSize(AutofillDownloadManager::RequestType request_type, break; default: NOTREACHED(); - UMA_HISTOGRAM_COUNTS_100000("Autofill.Unknown.FailingPayloadSize", - num_bytes); } } @@ -197,7 +192,6 @@ void LogExponentialBackoffDelay( break; default: NOTREACHED(); - UMA_HISTOGRAM_MEDIUM_TIMES("Autofill.Unknown.BackoffDelay", delay); } } diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc index 69e2bd66516..13d7f760d5c 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc @@ -14,7 +14,6 @@ #include "base/base64url.h" #include "base/bind.h" #include "base/format_macros.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -187,7 +186,7 @@ class AutofillDownloadManagerTest : public AutofillDownloadManager::Observer, ResponseData() : type_of_response(REQUEST_QUERY_FAILED), error(0) {} }; - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; std::list<ResponseData> responses_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; network::TestURLLoaderFactory test_url_loader_factory_; diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h index 304d818bf87..82f8a68839f 100644 --- a/chromium/components/autofill/core/browser/autofill_driver.h +++ b/chromium/components/autofill/core/browser/autofill_driver.h @@ -102,10 +102,6 @@ class AutofillDriver { // renderers cannot do this transformation themselves. virtual gfx::RectF TransformBoundingBoxToViewportCoordinates( const gfx::RectF& bounding_box) = 0; - - // Called when the user interacted with a credit card form, so that - // the current page's security state can be updated appropriately. - virtual void DidInteractWithCreditCardForm() = 0; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc index 9637edfe9cb..0df561935d5 100644 --- a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc @@ -8,7 +8,7 @@ #include <utility> #include "base/bind_helpers.h" -#include "base/message_loop/message_loop.h" +#include "base/test/scoped_task_environment.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "testing/gmock/include/gmock/gmock.h" @@ -98,7 +98,8 @@ class AutofillDriverFactoryTest : public testing::Test { } protected: - base::MessageLoop message_loop_; // For TestAutofillDriver. + // For TestAutofillDriver. + base::test::ScopedTaskEnvironment task_environment_; MockAutofillClient client_; diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc index 76816b84f0a..13e96ebe22c 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments.cc @@ -29,26 +29,6 @@ namespace autofill { #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -namespace { -// Returns the font weight corresponding to the value of param -// kAutofillForcedFontWeightParameterName, or kDefault if the param is not -// valid. -ForcedFontWeight GetFontWeightFromParam() { - std::string param = base::GetFieldTrialParamValueByFeature( - kAutofillPrimaryInfoStyleExperiment, - kAutofillForcedFontWeightParameterName); - - if (param == kAutofillForcedFontWeightParameterMedium) - return ForcedFontWeight::kMedium; - if (param == kAutofillForcedFontWeightParameterBold) - return ForcedFontWeight::kBold; - - return ForcedFontWeight::kDefault; -} -} // namespace -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) const base::Feature kAutofillDropdownLayoutExperiment{ "AutofillDropdownLayout", base::FEATURE_DISABLED_BY_DEFAULT}; const char kAutofillDropdownLayoutParameterName[] = "variant"; @@ -58,14 +38,6 @@ const char kAutofillDropdownLayoutParameterTwoLinesLeadingIcon[] = "two-lines-leading-icon"; #endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -const base::Feature kAutofillPrimaryInfoStyleExperiment{ - "AutofillPrimaryInfoStyleExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; -const char kAutofillForcedFontWeightParameterName[] = "font_weight"; -const char kAutofillForcedFontWeightParameterMedium[] = "medium"; -const char kAutofillForcedFontWeightParameterBold[] = "bold"; -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - bool IsCreditCardUploadEnabled(const PrefService* pref_service, const syncer::SyncService* sync_service, const std::string& user_email) { @@ -118,10 +90,13 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, // If the "allow all email domains" flag is off, restrict credit card upload // only to Google Accounts with @googlemail, @gmail, @google, or @chromium // domains. + // example.com is on the list because ChromeOS tests rely on using this. That + // should be fine, since example.com is an IANA reserved domain. if (!base::FeatureList::IsEnabled( features::kAutofillUpstreamAllowAllEmailDomains) && !(domain == "googlemail.com" || domain == "gmail.com" || - domain == "google.com" || domain == "chromium.org")) { + domain == "google.com" || domain == "chromium.org" || + domain == "example.com")) { return false; } @@ -167,13 +142,18 @@ bool IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled() { features::kAutofillNoLocalSaveOnUploadSuccess); } -bool OfferStoreUnmaskedCards() { +bool OfferStoreUnmaskedCards(bool is_off_the_record) { #if defined(OS_LINUX) && !defined(OS_CHROMEOS) // The checkbox can be forced on with a flag, but by default we don't store // on Linux due to lack of system keychain integration. See crbug.com/162735 return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableOfferStoreUnmaskedWalletCards); #else + // Never offer to store unmasked cards when off the record. + if (is_off_the_record) { + return false; + } + // Query the field trial before checking command line flags to ensure UMA // reports the correct group. std::string group_name = @@ -202,17 +182,6 @@ bool ShouldUseActiveSignedInAccount() { } #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -ForcedFontWeight GetForcedFontWeight() { - if (!base::FeatureList::IsEnabled(kAutofillPrimaryInfoStyleExperiment)) - return ForcedFontWeight::kDefault; - - // Only read the feature param's value the first time it's needed. - static ForcedFontWeight font_weight_from_param = GetFontWeightFromParam(); - return font_weight_from_param; -} -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) ForcedPopupLayoutState GetForcedPopupLayoutState() { if (!base::FeatureList::IsEnabled( autofill::kAutofillDropdownLayoutExperiment)) diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h index ee4bf603f7b..d4247999259 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.h +++ b/chromium/components/autofill/core/browser/autofill_experiments.h @@ -31,13 +31,6 @@ extern const char kAutofillDropdownLayoutParameterTrailingIcon[]; extern const char kAutofillDropdownLayoutParameterTwoLinesLeadingIcon[]; #endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -extern const base::Feature kAutofillPrimaryInfoStyleExperiment; -extern const char kAutofillForcedFontWeightParameterName[]; -extern const char kAutofillForcedFontWeightParameterMedium[]; -extern const char kAutofillForcedFontWeightParameterBold[]; -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - // Returns true if uploading credit cards to Wallet servers is enabled. This // requires the appropriate flags and user settings to be true and the user to // be a member of a supported domain. @@ -61,26 +54,12 @@ bool IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled(); // Returns true if the user should be offered to locally store unmasked cards. // This controls whether the option is presented at all rather than the default // response of the option. -bool OfferStoreUnmaskedCards(); +bool OfferStoreUnmaskedCards(bool is_off_the_record); // Returns whether the account of the active signed-in user should be used. bool ShouldUseActiveSignedInAccount(); #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -enum class ForcedFontWeight { - kDefault, // No change to the font weight. - kMedium, - kBold, -}; - -// Returns the font weight to be used for primary information on the Autofill -// dropdown for Addresses and Credit Cards. Returns kDefault if feature -// kAutofillPrimaryInfoStyleExperiment is disabled or if the corresponding -// feature param is invalid. -ForcedFontWeight GetForcedFontWeight(); -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) enum class ForcedPopupLayoutState { kDefault, // No popup layout forced by experiment. kLeadingIcon, // Experiment forces leading (left in LTR) icon layout. diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc index 3a440c1260e..f1f617296f1 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc @@ -82,17 +82,6 @@ void AutofillExternalDelegate::OnSuggestionsReturned( // Hide warnings as appropriate. PossiblyRemoveAutofillWarnings(&suggestions); -#if !defined(OS_ANDROID) - // If there are above the fold suggestions at this point, add a separator to - // go between the values and menu items. Skip this when using the Native Views - // implementation, which has its own logic for distinguishing footer rows. - // TODO(crbug.com/831603): Remove this when the relevant feature is on 100%. - if (!suggestions.empty() && !features::ShouldUseNativeViews()) { - suggestions.push_back(Suggestion()); - suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR; - } -#endif - if (should_show_scan_credit_card_) { Suggestion scan_credit_card( l10n_util::GetStringUTF16(IDS_AUTOFILL_SCAN_CREDIT_CARD)); @@ -124,16 +113,6 @@ void AutofillExternalDelegate::OnSuggestionsReturned( // Append the credit card signin promo, if appropriate (there are no other // suggestions). if (suggestions.empty() && should_show_cc_signin_promo_) { -// No separator on Android. -#if !defined(OS_ANDROID) - // If there are autofill suggestions, the "Autofill options" row was added - // above. Add a separator between it and the signin promo. - if (has_autofill_suggestions_) { - suggestions.push_back(Suggestion()); - suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR; - } -#endif - Suggestion signin_promo_suggestion( l10n_util::GetStringUTF16(IDS_AUTOFILL_CREDIT_CARD_SIGNIN_PROMO)); signin_promo_suggestion.frontend_id = @@ -143,14 +122,6 @@ void AutofillExternalDelegate::OnSuggestionsReturned( signin_metrics::AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN); } -#if !defined(OS_ANDROID) - // Remove the separator if there is one, and if it is the last element. - if (!suggestions.empty() && - suggestions.back().frontend_id == POPUP_ITEM_ID_SEPARATOR) { - suggestions.pop_back(); - } -#endif - // If anything else is added to modify the values after inserting the data // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be // updated to match. @@ -242,6 +213,7 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, // User selected an Autocomplete, so we fill directly. driver_->RendererShouldFillFieldWithValue(value); AutofillMetrics::LogAutocompleteSuggestionAcceptedIndex(position); + manager_->OnAutocompleteEntrySelected(value); } else if (identifier == POPUP_ITEM_ID_SCAN_CREDIT_CARD) { manager_->client()->ScanCreditCard(base::Bind( &AutofillExternalDelegate::OnCreditCardScanned, GetWeakPtr())); diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc index 044913561f6..32c3dd956b0 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc @@ -8,12 +8,12 @@ #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/user_action_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/test/scoped_task_environment.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_external_delegate.h" @@ -95,7 +95,10 @@ class MockAutofillManager : public AutofillManager { public: MockAutofillManager(AutofillDriver* driver, MockAutofillClient* client) // Force to use the constructor designated for unit test. - : AutofillManager(driver, client, client->GetPersonalDataManager()) {} + : AutofillManager(driver, + client, + client->GetPersonalDataManager(), + client->GetAutocompleteHistoryManager()) {} ~MockAutofillManager() override {} PopupType GetPopupType(const FormData& form, @@ -176,7 +179,7 @@ class AutofillExternalDelegateUnitTest : public testing::Test { kQueryId, suggestions, /*autoselect_first_suggestion=*/false); } - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; testing::NiceMock<MockAutofillClient> autofill_client_; std::unique_ptr<testing::NiceMock<MockAutofillDriver>> autofill_driver_; @@ -736,6 +739,9 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateFillFieldWithValue) { base::string16 dummy_string(ASCIIToUTF16("baz foo")); EXPECT_CALL(*autofill_driver_, RendererShouldFillFieldWithValue(dummy_string)); + EXPECT_CALL(*autofill_client_.GetMockAutocompleteHistoryManager(), + OnAutocompleteEntrySelected(dummy_string)) + .Times(1); base::HistogramTester histogram_tester; external_delegate_->DidAcceptSuggestion(dummy_string, POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, @@ -890,46 +896,4 @@ TEST_F(AutofillExternalDelegateCardsFromAccountTest, /*autoselect_first_suggestion=*/false); } -#if !defined(OS_ANDROID) -// Test that the delegate includes a separator between the content rows and the -// footer, if and only if the kAutofillExpandedPopupViews feature is disabled. -TEST_F(AutofillExternalDelegateUnitTest, IncludeFooterSeparatorForOldUIOnly) { - // The guts of the test. This will be run once with the feature enabled, - // expecting not to find a separator, and a second time with the feature - // disabled, expecting to find a separator. - auto tester = [this](bool enabled, auto element_ids) { - base::test::ScopedFeatureList scoped_feature_list; - - if (enabled) { - scoped_feature_list.InitAndEnableFeature( - features::kAutofillExpandedPopupViews); - } else { - scoped_feature_list.InitAndDisableFeature( - features::kAutofillExpandedPopupViews); - } - - IssueOnQuery(kQueryId); - - EXPECT_CALL( - autofill_client_, - ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), false, _)); - - std::vector<Suggestion> autofill_item; - autofill_item.push_back(Suggestion()); - autofill_item[0].frontend_id = kAutofillProfileId; - external_delegate_->OnSuggestionsReturned( - kQueryId, autofill_item, /*autoselect_first_suggestion=*/false); - }; - - tester(false, - testing::ElementsAre( - kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_SEPARATOR), - static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS))); - - tester(true, testing::ElementsAre( - kAutofillProfileId, - static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS))); -} -#endif // !defined(OS_ANDROID) - } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc index 865ecd43122..a495cefa853 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_handler.cc @@ -54,10 +54,9 @@ AutofillHandler::~AutofillHandler() = default; void AutofillHandler::OnFormSubmitted(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) { + SubmissionSource source) { if (IsValidFormData(form)) - OnFormSubmittedImpl(form, known_success, source, timestamp); + OnFormSubmittedImpl(form, known_success, source); } void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms, diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h index f228eaff880..16f06b44368 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.h +++ b/chromium/components/autofill/core/browser/autofill_handler.h @@ -76,8 +76,7 @@ class AutofillHandler { // personal profile. void OnFormSubmitted(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp); + SubmissionSource source); // Invoked when |forms| has been detected. void OnFormsSeen(const std::vector<FormData>& forms, @@ -135,8 +134,7 @@ class AutofillHandler { virtual void OnFormSubmittedImpl(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) = 0; + SubmissionSource source) = 0; virtual void OnTextFieldDidChangeImpl(const FormData& form, const FormFieldData& field, diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc index 7ed1e4e63eb..cf75c3d4165 100644 --- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc +++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc @@ -18,9 +18,8 @@ AutofillHandlerProxy::~AutofillHandlerProxy() {} void AutofillHandlerProxy::OnFormSubmittedImpl(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) { - provider_->OnFormSubmitted(this, form, known_success, source, timestamp); + SubmissionSource source) { + provider_->OnFormSubmitted(this, form, known_success, source); } void AutofillHandlerProxy::OnTextFieldDidChangeImpl( diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.h b/chromium/components/autofill/core/browser/autofill_handler_proxy.h index 364643a9aae..3c560df3e3f 100644 --- a/chromium/components/autofill/core/browser/autofill_handler_proxy.h +++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.h @@ -39,8 +39,7 @@ class AutofillHandlerProxy : public AutofillHandler { protected: void OnFormSubmittedImpl(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) override; + SubmissionSource source) override; void OnTextFieldDidChangeImpl(const FormData& form, const FormFieldData& field, diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc index abc0088a62f..1d218fcc902 100644 --- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc @@ -6,7 +6,7 @@ #include <stddef.h> -#include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/win/registry.h" #include "components/autofill/core/browser/autofill_profile.h" @@ -152,13 +152,13 @@ TEST_F(AutofillIeToolbarImportTest, TestAutofillImport) { profile_key.Create(HKEY_CURRENT_USER, kProfileKey, KEY_ALL_ACCESS); EXPECT_TRUE(profile_key.Valid()); - CreateSubkey(&profile_key, L"0", profile1, arraysize(profile1)); - CreateSubkey(&profile_key, L"1", profile2, arraysize(profile2)); + CreateSubkey(&profile_key, L"0", profile1, base::size(profile1)); + CreateSubkey(&profile_key, L"1", profile2, base::size(profile2)); RegKey cc_key; cc_key.Create(HKEY_CURRENT_USER, kCreditCardKey, KEY_ALL_ACCESS); EXPECT_TRUE(cc_key.Valid()); - CreateSubkey(&cc_key, L"0", credit_card, arraysize(credit_card)); + CreateSubkey(&cc_key, L"0", credit_card, base::size(credit_card)); EncryptAndWrite(&cc_key, &empty_password); EncryptAndWrite(&cc_key, &empty_salt); diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc index d68e6bdfd11..95dcd22455c 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_manager.cc @@ -24,6 +24,7 @@ #include "base/i18n/rtl.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/path_service.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" @@ -198,17 +199,21 @@ AutofillManager::AutofillManager( : AutofillManager(driver, client, client->GetPersonalDataManager(), + client->GetAutocompleteHistoryManager(), app_locale, enable_download_manager) {} -AutofillManager::~AutofillManager() {} +AutofillManager::~AutofillManager() { + if (autocomplete_history_manager_) { + autocomplete_history_manager_->CancelPendingQueries(this); + } +} void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) { // TODO(jrg): consider passing delegate into the ctor. That won't // work if the delegate has a pointer to the AutofillManager, but // future directions may not need such a pointer. external_delegate_ = delegate; - autocomplete_history_manager_->SetExternalDelegate(delegate); } void AutofillManager::ShowAutofillSettings(bool show_credit_card_settings) { @@ -361,8 +366,7 @@ bool AutofillManager::ShouldParseForms(const std::vector<FormData>& forms, void AutofillManager::OnFormSubmittedImpl(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) { + SubmissionSource source) { // TODO(crbug.com/801698): handle PROBABLY_FORM_SUBMITTED. if (source == SubmissionSource::PROBABLY_FORM_SUBMITTED && !base::FeatureList::IsEnabled( @@ -373,7 +377,8 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form, // We will always give Autocomplete a chance to save the data. std::unique_ptr<FormStructure> submitted_form = ValidateSubmittedForm(form); if (!submitted_form) { - autocomplete_history_manager_->OnWillSubmitForm(form); + autocomplete_history_manager_->OnWillSubmitForm( + form, client_->IsAutocompleteEnabled()); return; } @@ -386,7 +391,8 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form, form_for_autocomplete.fields[i].should_autocomplete = false; } } - autocomplete_history_manager_->OnWillSubmitForm(form_for_autocomplete); + autocomplete_history_manager_->OnWillSubmitForm( + form_for_autocomplete, client_->IsAutocompleteEnabled()); if (IsProfileAutofillEnabled()) { address_form_event_logger_->OnWillSubmitForm(sync_state_); @@ -396,7 +402,7 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form, } submitted_form->set_submission_source(source); - MaybeStartVoteUploadProcess(std::move(submitted_form), timestamp, + MaybeStartVoteUploadProcess(std::move(submitted_form), /*observed_submission=*/true); // TODO(crbug.com/803334): Add FormStructure::Clone() method. @@ -435,7 +441,6 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form, bool AutofillManager::MaybeStartVoteUploadProcess( std::unique_ptr<FormStructure> form_structure, - const TimeTicks& timestamp, bool observed_submission) { // It is possible for |personal_data_| to be null, such as when used in the // Android webview. @@ -445,7 +450,7 @@ bool AutofillManager::MaybeStartVoteUploadProcess( // Only upload server statistics and UMA metrics if at least some local data // is available to use as a baseline. std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles(); - personal_data_->UpdateProfilesValidityMapsIfNeeded(profiles); + personal_data_->UpdateProfilesServerValidityMapsIfNeeded(profiles); if (observed_submission && form_structure->IsAutofillable()) { AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission( personal_data_->GetProfiles().size()); @@ -485,10 +490,11 @@ bool AutofillManager::MaybeStartVoteUploadProcess( base::BindOnce(&AutofillManager::DeterminePossibleFieldTypesForUpload, copied_profiles, copied_credit_cards, app_locale_, raw_form), - base::BindOnce( - &AutofillManager::UploadFormDataAsyncCallback, - weak_ptr_factory_.GetWeakPtr(), base::Owned(form_structure.release()), - initial_interaction_timestamp_, timestamp, observed_submission)); + base::BindOnce(&AutofillManager::UploadFormDataAsyncCallback, + weak_ptr_factory_.GetWeakPtr(), + base::Owned(form_structure.release()), + initial_interaction_timestamp_, base::TimeTicks::Now(), + observed_submission)); return true; } @@ -513,7 +519,7 @@ void AutofillManager::ProcessPendingFormForUpload() { if (!upload_form) return; - MaybeStartVoteUploadProcess(std::move(upload_form), TimeTicks::Now(), + MaybeStartVoteUploadProcess(std::move(upload_form), /*observed_submission=*/false); } @@ -602,7 +608,7 @@ void AutofillManager::OnQueryFormFieldAutofillImpl( case SuppressReason::kCreditCardsAblation: enable_ablation_logging_ = true; - autocomplete_history_manager_->CancelPendingQuery(); + autocomplete_history_manager_->CancelPendingQueries(this); external_delegate_->OnSuggestionsReturned(query_id, suggestions, autoselect_first_suggestion); return; @@ -646,12 +652,14 @@ void AutofillManager::OnQueryFormFieldAutofillImpl( // Suggestions come back asynchronously, so the Autocomplete manager will // handle sending the results back to the renderer. autocomplete_history_manager_->OnGetAutocompleteSuggestions( - query_id, field.name, field.value, field.form_control_type); + query_id, client_->IsAutocompleteEnabled(), autoselect_first_suggestion, + field.name, field.value, field.form_control_type, + weak_ptr_factory_.GetWeakPtr()); return; } // Send Autofill suggestions (could be an empty list). - autocomplete_history_manager_->CancelPendingQuery(); + autocomplete_history_manager_->CancelPendingQueries(this); external_delegate_->OnSuggestionsReturned(query_id, suggestions, autoselect_first_suggestion, context.is_all_server_suggestions); @@ -903,7 +911,7 @@ void AutofillManager::OnHidePopup() { if (!IsAutofillEnabled()) return; - autocomplete_history_manager_->CancelPendingQuery(); + autocomplete_history_manager_->CancelPendingQueries(this); client_->HideAutofillPopup(); } @@ -991,6 +999,10 @@ void AutofillManager::RemoveAutocompleteEntry(const base::string16& name, autocomplete_history_manager_->OnRemoveAutocompleteEntry(name, value); } +void AutofillManager::OnAutocompleteEntrySelected(const base::string16& value) { + autocomplete_history_manager_->OnAutocompleteEntrySelected(value); +} + bool AutofillManager::IsShowingUnmaskPrompt() { return full_card_request_ && full_card_request_->IsGettingFullCard(); } @@ -1154,6 +1166,15 @@ bool AutofillManager::ShouldUploadForm(const FormStructure& form) { form.ShouldBeUploaded(); } +// AutocompleteHistoryManager::SuggestionsHandler implementation +void AutofillManager::OnSuggestionsReturned( + int query_id, + bool autoselect_first_suggestion, + const std::vector<Suggestion>& suggestions) { + external_delegate_->OnSuggestionsReturned(query_id, suggestions, + autoselect_first_suggestion); +} + // Note that |submitted_form| is passed as a pointer rather than as a reference // so that we can get memory management right across threads. Note also that we // explicitly pass in all the time stamps of interest, as the cached ones might @@ -1236,6 +1257,7 @@ AutofillManager::AutofillManager( AutofillDriver* driver, AutofillClient* client, PersonalDataManager* personal_data, + AutocompleteHistoryManager* autocomplete_history_manager, const std::string app_locale, AutofillDownloadManagerState enable_download_manager) : AutofillHandler(driver), @@ -1243,8 +1265,7 @@ AutofillManager::AutofillManager( app_locale_(app_locale), personal_data_(personal_data), field_filler_(app_locale, client->GetAddressNormalizer()), - autocomplete_history_manager_( - std::make_unique<AutocompleteHistoryManager>(driver, client)), + autocomplete_history_manager_(autocomplete_history_manager->GetWeakPtr()), form_interactions_ukm_logger_( std::make_unique<AutofillMetrics::FormInteractionsUkmLogger>( client->GetUkmRecorder(), @@ -1272,8 +1293,14 @@ AutofillManager::AutofillManager( new AutofillDownloadManager(driver, this, GetAPIKeyForUrl(channel))); } CountryNames::SetLocaleString(app_locale_); - if (personal_data_ && client_) + // Since we want Downstream to still work in incognito, only overwrite the + // PDM's sync service if this is not an incognito AutofillManager. However, if + // the opened window is in incognito, the sync service would be null. Unless + // there is a major refactor with the Autofill Sync interation, there is + // nothing we can do for that specific case. + if (personal_data_ && client_ && !driver->IsIncognito()) { personal_data_->OnSyncServiceInitialized(client_->GetSyncService()); + } } bool AutofillManager::RefreshDataModels() { @@ -1361,13 +1388,9 @@ void AutofillManager::FillOrPreviewDataModelForm( DCHECK(form_structure); DCHECK(autofill_field); - FormData result = form; - - if (base::FeatureList::IsEnabled( - features::kAutofillRationalizeFieldTypePredictions)) { - form_structure->RationalizePhoneNumbersInSection(autofill_field->section); - } + form_structure->RationalizePhoneNumbersInSection(autofill_field->section); + FormData result = form; DCHECK_EQ(form_structure->field_count(), form.fields.size()); // Only record the types that are filled for an eventual refill if all the @@ -2093,7 +2116,6 @@ void AutofillManager::GetAvailableSuggestions( if (got_autofillable_form) { if (context->focused_field->Type().group() == CREDIT_CARD) { context->is_filling_credit_card = true; - driver()->DidInteractWithCreditCardForm(); credit_card_form_event_logger_->OnDidInteractWithAutofillableForm( context->form_structure->form_signature(), sync_state_); } else { diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h index bcb6ac6bdfe..588f1ee0693 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.h +++ b/chromium/components/autofill/core/browser/autofill_manager.h @@ -68,7 +68,8 @@ extern const int kCreditCardSigninPromoImpressionLimit; class AutofillManager : public AutofillHandler, public AutofillDownloadManager::Observer, public payments::FullCardRequest::ResultDelegate, - public payments::FullCardRequest::UIDelegate { + public payments::FullCardRequest::UIDelegate, + public AutocompleteHistoryManager::SuggestionsHandler { public: AutofillManager(AutofillDriver* driver, AutofillClient* client, @@ -140,6 +141,9 @@ class AutofillManager : public AutofillHandler, void RemoveAutocompleteEntry(const base::string16& name, const base::string16& value); + // Invoked when the user selected |value| in the Autocomplete drop-down. + void OnAutocompleteEntrySelected(const base::string16& value); + // Returns true when the Payments card unmask prompt is being displayed. bool IsShowingUnmaskPrompt(); @@ -170,7 +174,6 @@ class AutofillManager : public AutofillHandler, // start. virtual bool MaybeStartVoteUploadProcess( std::unique_ptr<FormStructure> form_structure, - const base::TimeTicks& timestamp, bool observed_submission); // Update the pending form with |form|, possibly processing the current @@ -199,6 +202,12 @@ class AutofillManager : public AutofillHandler, void SelectFieldOptionsDidChange(const FormData& form) override; void Reset() override; + // AutocompleteHistoryManager::SuggestionsHandler: + void OnSuggestionsReturned( + int query_id, + bool autoselect_first_suggestion, + const std::vector<Suggestion>& suggestions) override; + // Returns the value of AutofillEnabled pref. virtual bool IsAutofillEnabled() const; @@ -224,6 +233,7 @@ class AutofillManager : public AutofillHandler, AutofillManager(AutofillDriver* driver, AutofillClient* client, PersonalDataManager* personal_data, + AutocompleteHistoryManager* autocomplete_history_manager, const std::string app_locale = "en-US", AutofillDownloadManagerState enable_download_manager = DISABLE_AUTOFILL_DOWNLOAD_MANAGER); @@ -259,8 +269,7 @@ class AutofillManager : public AutofillHandler, // AutofillHandler: void OnFormSubmittedImpl(const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) override; + SubmissionSource source) override; void OnTextFieldDidChangeImpl(const FormData& form, const FormFieldData& field, const gfx::RectF& bounding_box, @@ -533,7 +542,8 @@ class AutofillManager : public AutofillHandler, std::unique_ptr<AutofillDownloadManager> download_manager_; // Handles single-field autocomplete form data. - std::unique_ptr<AutocompleteHistoryManager> autocomplete_history_manager_; + // May be NULL. NULL indicates OTR. + base::WeakPtr<AutocompleteHistoryManager> autocomplete_history_manager_; // Utility for logging URL keyed metrics. std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger> diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc index 879e3d7ecb9..68c0d62c8da 100644 --- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc @@ -14,10 +14,10 @@ #include "base/base64.h" #include "base/command_line.h" #include "base/feature_list.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/metrics/field_trial.h" #include "base/metrics/metrics_hashes.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -33,6 +33,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/popup_item_ids.h" @@ -59,6 +60,7 @@ #include "components/prefs/pref_service.h" #include "components/security_state/core/security_state.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/driver/test_sync_service.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_params_manager.h" #include "components/version_info/channel.h" @@ -262,22 +264,6 @@ void ExpectFilledCreditCardYearMonthWithYearMonth(int page_id, month, year, has_address_fields, true, true); } -class MockAutocompleteHistoryManager : public AutocompleteHistoryManager { - public: - MockAutocompleteHistoryManager(AutofillDriver* driver, AutofillClient* client) - : AutocompleteHistoryManager(driver, client) {} - - MOCK_METHOD4(OnGetAutocompleteSuggestions, - void(int query_id, - const base::string16& name, - const base::string16& prefix, - const std::string& form_control_type)); - MOCK_METHOD1(OnWillSubmitForm, void(const FormData& form)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockAutocompleteHistoryManager); -}; - class MockAutofillDriver : public TestAutofillDriver { public: MockAutofillDriver() {} @@ -303,7 +289,7 @@ class AutofillManagerTest : public testing::Test { void SetUp() override { autofill_client_.SetPrefs(test::PrefServiceForTesting()); - personal_data_.Init(/*profile_database=*/autofill_client_.GetDatabase(), + personal_data_.Init(/*profile_database=*/database_, /*account_database=*/nullptr, /*pref_service=*/autofill_client_.GetPrefs(), /*identity_manager=*/nullptr, @@ -312,6 +298,13 @@ class AutofillManagerTest : public testing::Test { /*cookie_manager_sevice=*/nullptr, /*is_off_the_record=*/false); personal_data_.SetPrefService(autofill_client_.GetPrefs()); + + autocomplete_history_manager_ = + std::make_unique<MockAutocompleteHistoryManager>(); + autocomplete_history_manager_->Init( + /*profile_database=*/database_, + /*is_off_the_record=*/false); + autofill_driver_ = std::make_unique<testing::NiceMock<MockAutofillDriver>>(); request_context_ = new net::TestURLRequestContextGetter( @@ -336,7 +329,8 @@ class AutofillManagerTest : public testing::Test { std::unique_ptr<autofill::TestFormDataImporter>( test_form_data_importer)); autofill_manager_ = std::make_unique<TestAutofillManager>( - autofill_driver_.get(), &autofill_client_, &personal_data_); + autofill_driver_.get(), &autofill_client_, &personal_data_, + autocomplete_history_manager_.get()); download_manager_ = new MockAutofillDownloadManager( autofill_driver_.get(), autofill_manager_.get()); // AutofillManager takes ownership of |download_manager_|. @@ -427,8 +421,15 @@ class AutofillManagerTest : public testing::Test { } void AutocompleteSuggestionsReturned( - const std::vector<base::string16>& result) { - autofill_manager_->autocomplete_history_manager_->SendSuggestions(&result); + const std::vector<base::string16>& results, + int query_id = kDefaultPageID) { + std::vector<Suggestion> suggestions; + std::transform(results.begin(), results.end(), + std::back_inserter(suggestions), + [](auto result) { return Suggestion(result); }); + + autofill_manager_->OnSuggestionsReturned( + query_id, /*autoselect_first_suggestion=*/false, suggestions); } void FormsSeen(const std::vector<FormData>& forms) { @@ -436,8 +437,8 @@ class AutofillManagerTest : public testing::Test { } void FormSubmitted(const FormData& form) { - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); } void FillAutofillFormData(int query_id, @@ -530,16 +531,6 @@ class AutofillManagerTest : public testing::Test { form->fields[0], *card); } - // Convenience method for using and retrieving a mock autocomplete history - // manager. - MockAutocompleteHistoryManager* RecreateMockAutocompleteHistoryManager() { - MockAutocompleteHistoryManager* manager = - new MockAutocompleteHistoryManager(autofill_driver_.get(), - autofill_manager_->client()); - autofill_manager_->autocomplete_history_manager_.reset(manager); - return manager; - } - // Convenience method to cast the FullCardRequest into a CardUnmaskDelegate. CardUnmaskDelegate* full_card_unmask_delegate() { DCHECK(autofill_manager_->full_card_request_); @@ -589,8 +580,10 @@ class AutofillManagerTest : public testing::Test { std::unique_ptr<TestAutofillManager> autofill_manager_; std::unique_ptr<TestAutofillExternalDelegate> external_delegate_; scoped_refptr<net::TestURLRequestContextGetter> request_context_; + scoped_refptr<AutofillWebDataService> database_; MockAutofillDownloadManager* download_manager_; TestPersonalDataManager personal_data_; + std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_; base::test::ScopedFeatureList scoped_feature_list_; variations::testing::VariationParamsManager variation_params_; @@ -761,8 +754,9 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) { FormsSeen(forms); // Ensure that autocomplete manager is not called for suggestions either. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); // Suggestions should be returned for the first two fields. GetAutofillSuggestions(form, form.fields[0]); @@ -799,8 +793,9 @@ TEST_F(AutofillManagerTest, FormsSeen(forms); // Ensure that autocomplete manager is called for both fields. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(2); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(2); GetAutofillSuggestions(form, form.fields[0]); EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen()); @@ -867,8 +862,9 @@ TEST_F(AutofillManagerTest, FormsSeen(forms); // Ensure that autocomplete manager is called for both fields. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); GetAutofillSuggestions(form, form.fields[0]); CheckSuggestions(kDefaultPageID, @@ -951,6 +947,16 @@ TEST_F(AutofillManagerTest, Suggestion("Presley", "Elvis Aaron Presley", "", 2)); } +// Test that the call is properly forwarded to AutocompleteHistoryManager. +TEST_F(AutofillManagerTest, OnAutocompleteEntrySelected) { + base::string16 test_value = ASCIIToUTF16("TestValue"); + EXPECT_CALL(*autocomplete_history_manager_.get(), + OnAutocompleteEntrySelected(test_value)) + .Times(1); + + autofill_manager_->OnAutocompleteEntrySelected(test_value); +} + // Test that we return all address profile suggestions when all form fields are // empty. TEST_F(AutofillManagerTest, GetProfileSuggestions_EmptyValue) { @@ -1126,6 +1132,27 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_AutofillDisabledByUser) { EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen()); } +TEST_F(AutofillManagerTest, OnSuggestionsReturned_CallsExternalDelegate) { + std::vector<Suggestion> suggestions = { + Suggestion("Charles", "123 Apple St.", "", 1), + Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2)}; + + { + autofill_manager_->OnSuggestionsReturned( + kDefaultPageID, /*autoselect_first_suggestion=*/false, suggestions); + + EXPECT_FALSE(external_delegate_->autoselect_first_suggestion()); + CheckSuggestions(kDefaultPageID, suggestions[0], suggestions[1]); + } + { + autofill_manager_->OnSuggestionsReturned( + kDefaultPageID, /*autoselect_first_suggestion=*/true, suggestions); + + EXPECT_TRUE(external_delegate_->autoselect_first_suggestion()); + CheckSuggestions(kDefaultPageID, suggestions[0], suggestions[1]); + } +} + // Test that we return all credit card profile suggestions when all form fields // are empty. TEST_F(AutofillManagerTest, GetCreditCardSuggestions_EmptyValue) { @@ -1327,8 +1354,9 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_OnlySigninPromo) { EXPECT_TRUE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field)); // Autocomplete suggestions are not queried. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); GetAutofillSuggestions(form, field); @@ -2973,60 +3001,27 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_ComponentizedNumbers) { std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_with_multiple_componentized_phone_fields, - *form_with_multiple_componentized_phone_fields.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify only the first complete set of phone number fields are filled. - ASSERT_EQ(8U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(base::string16(), response_data.fields[5].value); - EXPECT_EQ(base::string16(), response_data.fields[6].value); - EXPECT_EQ(base::string16(), response_data.fields[7].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + page_id, form_with_multiple_componentized_phone_fields, + *form_with_multiple_componentized_phone_fields.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms_copy); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: all phone number fields are filled. - ASSERT_EQ(8U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[5].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[6].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[7].value); - } + // Verify only the first complete set of phone number fields are filled. + ASSERT_EQ(8U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value); + EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); + EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value); + EXPECT_EQ(base::string16(), response_data.fields[4].value); + EXPECT_EQ(base::string16(), response_data.fields[5].value); + EXPECT_EQ(base::string16(), response_data.fields[6].value); + EXPECT_EQ(base::string16(), response_data.fields[7].value); } TEST_F(AutofillManagerTest, FillFirstPhoneNumber_WholeNumbers) { @@ -3062,52 +3057,23 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_WholeNumbers) { std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_with_multiple_whole_number_fields, - *form_with_multiple_whole_number_fields.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify only the first complete set of phone number fields are filled. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(base::string16(), response_data.fields[3].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + page_id, form_with_multiple_whole_number_fields, + *form_with_multiple_whole_number_fields.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms_copy); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: all phone number fields are filled. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - } + // Verify only the first complete set of phone number fields are filled. + ASSERT_EQ(4U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value); + EXPECT_EQ(base::string16(), response_data.fields[2].value); + EXPECT_EQ(base::string16(), response_data.fields[3].value); } TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FillPartsOnceOnly) { @@ -3158,61 +3124,28 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FillPartsOnceOnly) { std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_with_multiple_componentized_phone_fields, - *form_with_multiple_componentized_phone_fields.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify only the first complete set of phone number fields are filled, - // and phone components are not filled more than once. - ASSERT_EQ(8U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(base::string16(), response_data.fields[5].value); - EXPECT_EQ(base::string16(), response_data.fields[6].value); - EXPECT_EQ(base::string16(), response_data.fields[7].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + page_id, form_with_multiple_componentized_phone_fields, + *form_with_multiple_componentized_phone_fields.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms_copy); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: all phone number fields are filled. - ASSERT_EQ(8U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[5].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[6].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[7].value); - } + // Verify only the first complete set of phone number fields are filled, + // and phone components are not filled more than once. + ASSERT_EQ(8U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value); + EXPECT_EQ(base::string16(), response_data.fields[2].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); + EXPECT_EQ(base::string16(), response_data.fields[4].value); + EXPECT_EQ(base::string16(), response_data.fields[5].value); + EXPECT_EQ(base::string16(), response_data.fields[6].value); + EXPECT_EQ(base::string16(), response_data.fields[7].value); } // Verify when extension is misclassified, and there is a complete @@ -3258,55 +3191,24 @@ TEST_F(AutofillManagerTest, std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_with_misclassified_extension, - *form_with_misclassified_extension.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify the misclassified extension field is not filled. - ASSERT_EQ(5U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + page_id, form_with_misclassified_extension, + *form_with_misclassified_extension.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms_copy); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: the misclassified extension field is - // filled. - ASSERT_EQ(5U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value); - EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[4].value); - } + // Verify the misclassified extension field is not filled. + ASSERT_EQ(5U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(base::string16(), response_data.fields[1].value); + EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); + EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value); + EXPECT_EQ(base::string16(), response_data.fields[4].value); } // Verify when no complete number can be found, we do best-effort filling. @@ -3346,53 +3248,24 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_BestEfforFilling) { std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_with_no_complete_number, - *form_with_no_complete_number.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify when there is no complete phone number fields, we do best effort - // filling. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(base::string16(), response_data.fields[3].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + page_id, form_with_no_complete_number, + *form_with_no_complete_number.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: always do best effort filling. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); - EXPECT_EQ(base::string16(), response_data.fields[3].value); - } + // Verify when there is no complete phone number fields, we do best effort + // filling. + ASSERT_EQ(4U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(base::string16(), response_data.fields[1].value); + EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value); + EXPECT_EQ(base::string16(), response_data.fields[3].value); } // When the focus is on second phone field explicitly, we will fill the @@ -3430,58 +3303,26 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FocusOnSecondPhoneNumber) { std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - auto it = form_with_multiple_whole_number_fields.fields.begin(); - // Move it to point to "shipping number". - std::advance(it, 3); - FillAutofillFormDataAndSaveResults( - page_id, form_with_multiple_whole_number_fields, *it, - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify when the second phone number field is being focused, we fill - // that field *AND* the first phone number field. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + auto it = form_with_multiple_whole_number_fields.fields.begin(); + // Move it to point to "shipping number". + std::advance(it, 3); + FillAutofillFormDataAndSaveResults( + page_id, form_with_multiple_whole_number_fields, *it, + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - auto it = form_data_copy.fields.begin(); - // Move it to point to "shipping number". - std::advance(it, 3); - FillAutofillFormDataAndSaveResults(page_id, form_data_copy, *it, - MakeFrontendID(std::string(), guid), - &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: fill all the phone fields we can find. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - } + // Verify when the second phone number field is being focused, we fill + // that field *AND* the first phone number field. + ASSERT_EQ(4U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value); + EXPECT_EQ(base::string16(), response_data.fields[2].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); } TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) { @@ -3519,52 +3360,23 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) { std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_with_multiple_whole_number_fields, - *form_with_multiple_whole_number_fields.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify hidden/non-focusable phone field is set to only_fill_when_focused. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + page_id, form_with_multiple_whole_number_fields, + *form_with_multiple_whole_number_fields.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Sanity check for old behavior: fill hidden phone fields. - ASSERT_EQ(4U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16(""), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - } + // Verify hidden/non-focusable phone field is set to only_fill_when_focused. + ASSERT_EQ(4U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(base::string16(), response_data.fields[1].value); + EXPECT_EQ(base::string16(), response_data.fields[2].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); } // The hidden and the presentational fields should be filled, only if their @@ -3685,107 +3497,51 @@ TEST_F(AutofillManagerTest, std::vector<FormData> forms_copy; forms_copy.push_back(form_data_copy); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - // Fill first sections. - FillAutofillFormDataAndSaveResults( - page_id, form_with_multiple_sections, - *form_with_multiple_sections.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify first section is filled with rationalization. - ASSERT_EQ(9U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[2].value); - EXPECT_EQ(base::string16(), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(base::string16(), response_data.fields[5].value); - EXPECT_EQ(base::string16(), response_data.fields[6].value); - EXPECT_EQ(base::string16(), response_data.fields[7].value); - EXPECT_EQ(base::string16(), response_data.fields[8].value); - - // Fill second section. - auto it = form_with_multiple_sections.fields.begin(); - std::advance(it, 6); // Pointing to second section. - - FillAutofillFormDataAndSaveResults(page_id, form_with_multiple_sections, - *it, MakeFrontendID(std::string(), guid), - &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify second section is filled with rationalization. - ASSERT_EQ(9U, response_data.fields.size()); - EXPECT_EQ(base::string16(), response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(base::string16(), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[5].value); - EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[6].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[7].value); - EXPECT_EQ(base::string16(), response_data.fields[8].value); - } + FormsSeen(forms); + int page_id = 1; + int response_page_id = 0; + FormData response_data; + // Fill first sections. + FillAutofillFormDataAndSaveResults( + page_id, form_with_multiple_sections, + *form_with_multiple_sections.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormsSeen(forms); - int page_id = 1; - int response_page_id = 0; - FormData response_data; - // Fill first section. - FillAutofillFormDataAndSaveResults( - page_id, form_data_copy, *form_data_copy.fields.begin(), - MakeFrontendID(std::string(), guid), &response_page_id, &response_data); - - // Verify first section is filled without rationalization. - ASSERT_EQ(9U, response_data.fields.size()); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[0].value); - EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[1].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[2].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(base::string16(), response_data.fields[5].value); - EXPECT_EQ(base::string16(), response_data.fields[6].value); - EXPECT_EQ(base::string16(), response_data.fields[7].value); - EXPECT_EQ(base::string16(), response_data.fields[8].value); - - // Fill second section. - auto it = form_data_copy.fields.begin(); - std::advance(it, 6); // Pointing to second section. - - FillAutofillFormDataAndSaveResults(page_id, form_data_copy, *it, - MakeFrontendID(std::string(), guid), - &response_page_id, &response_data); - EXPECT_EQ(1, response_page_id); - - // Verify second section is filled without rationalization. - ASSERT_EQ(9U, response_data.fields.size()); - EXPECT_EQ(base::string16(), response_data.fields[0].value); - EXPECT_EQ(base::string16(), response_data.fields[1].value); - EXPECT_EQ(base::string16(), response_data.fields[2].value); - EXPECT_EQ(base::string16(), response_data.fields[3].value); - EXPECT_EQ(base::string16(), response_data.fields[4].value); - EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), - response_data.fields[5].value); - EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[6].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[7].value); - EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[8].value); - } + // Verify first section is filled with rationalization. + ASSERT_EQ(9U, response_data.fields.size()); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[0].value); + EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[1].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[2].value); + EXPECT_EQ(base::string16(), response_data.fields[3].value); + EXPECT_EQ(base::string16(), response_data.fields[4].value); + EXPECT_EQ(base::string16(), response_data.fields[5].value); + EXPECT_EQ(base::string16(), response_data.fields[6].value); + EXPECT_EQ(base::string16(), response_data.fields[7].value); + EXPECT_EQ(base::string16(), response_data.fields[8].value); + + // Fill second section. + auto it = form_with_multiple_sections.fields.begin(); + std::advance(it, 6); // Pointing to second section. + + FillAutofillFormDataAndSaveResults(page_id, form_with_multiple_sections, *it, + MakeFrontendID(std::string(), guid), + &response_page_id, &response_data); + EXPECT_EQ(1, response_page_id); + + // Verify second section is filled with rationalization. + ASSERT_EQ(9U, response_data.fields.size()); + EXPECT_EQ(base::string16(), response_data.fields[0].value); + EXPECT_EQ(base::string16(), response_data.fields[1].value); + EXPECT_EQ(base::string16(), response_data.fields[2].value); + EXPECT_EQ(base::string16(), response_data.fields[3].value); + EXPECT_EQ(base::string16(), response_data.fields[4].value); + EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"), + response_data.fields[5].value); + EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[6].value); + EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[7].value); + EXPECT_EQ(base::string16(), response_data.fields[8].value); } // Test that we can still fill a form when a field has been removed from it. @@ -3963,8 +3719,7 @@ TEST_F(AutofillManagerTest, FormSubmittedSaveData) { false); autofill_manager_->OnFormSubmitted(response_data, false, - SubmissionSource::FORM_SUBMISSION, - base::TimeTicks::Now()); + SubmissionSource::FORM_SUBMISSION); EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called()); } @@ -3972,16 +3727,17 @@ TEST_F(AutofillManagerTest, FormSubmittedSaveData) { // submissions are still received by AutocompleteHistoryManager. TEST_F(AutofillManagerTest, FormSubmittedAutocompleteEnabled) { TestAutofillClient client; - autofill_manager_.reset(new TestAutofillManager(autofill_driver_.get(), - &client, &personal_data_)); + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_, + autocomplete_history_manager_.get())); autofill_manager_->SetAutofillEnabled(false); // Set up our form data. FormData form; test::CreateTestAddressFormData(&form); - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnWillSubmitForm(_)); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnWillSubmitForm(_, true)); FormSubmitted(form); } @@ -3989,8 +3745,9 @@ TEST_F(AutofillManagerTest, FormSubmittedAutocompleteEnabled) { // queried. TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillDisabled) { TestAutofillClient client; - autofill_manager_.reset(new TestAutofillManager(autofill_driver_.get(), - &client, &personal_data_)); + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_, + autocomplete_history_manager_.get())); autofill_manager_->SetAutofillEnabled(false); autofill_manager_->SetExternalDelegate(external_delegate_.get()); @@ -4002,8 +3759,8 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillDisabled) { const FormFieldData& field = form.fields[0]; // Expect Autocomplete manager to be called for suggestions. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions); GetAutofillSuggestions(form, field); } @@ -4013,8 +3770,9 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillDisabled) { TEST_F(AutofillManagerTest, AutocompleteSuggestions_AutofillDisabledAndFieldShouldNotAutocomplete) { TestAutofillClient client; - autofill_manager_.reset(new TestAutofillManager(autofill_driver_.get(), - &client, &personal_data_)); + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_, + autocomplete_history_manager_.get())); autofill_manager_->SetAutofillEnabled(false); autofill_manager_->SetExternalDelegate(external_delegate_.get()); @@ -4028,8 +3786,9 @@ TEST_F(AutofillManagerTest, // Autocomplete manager is not called for suggestions. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); GetAutofillSuggestions(form, field); } @@ -4046,8 +3805,9 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_NoneWhenAutofillPresent) { const FormFieldData& field = form.fields[0]; // Autocomplete manager is not called for suggestions. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); GetAutofillSuggestions(form, field); @@ -4073,8 +3833,8 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillEmpty) { test::CreateTestFormField("Email", "email", "donkey", "email", &field); // Autocomplete manager is called for suggestions because Autofill is empty. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions); GetAutofillSuggestions(form, field); } @@ -4085,8 +3845,9 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillEmpty) { TEST_F(AutofillManagerTest, AutocompleteSuggestions_CreditCardNameFieldShouldAutocomplete) { TestAutofillClient client; - autofill_manager_.reset(new TestAutofillManager(autofill_driver_.get(), - &client, &personal_data_)); + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_, + autocomplete_history_manager_.get())); autofill_manager_->SetAutofillEnabled(false); autofill_manager_->SetExternalDelegate(external_delegate_.get()); @@ -4100,8 +3861,8 @@ TEST_F(AutofillManagerTest, field.should_autocomplete = true; // Autocomplete manager is not called for suggestions. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions); GetAutofillSuggestions(form, field); } @@ -4111,8 +3872,9 @@ TEST_F(AutofillManagerTest, TEST_F(AutofillManagerTest, AutocompleteSuggestions_CreditCardNumberShouldNotAutocomplete) { TestAutofillClient client; - autofill_manager_.reset(new TestAutofillManager(autofill_driver_.get(), - &client, &personal_data_)); + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_, + autocomplete_history_manager_.get())); autofill_manager_->SetAutofillEnabled(false); autofill_manager_->SetExternalDelegate(external_delegate_.get()); @@ -4126,8 +3888,9 @@ TEST_F(AutofillManagerTest, field.should_autocomplete = true; // Autocomplete manager is not called for suggestions. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); GetAutofillSuggestions(form, field); } @@ -4149,21 +3912,24 @@ TEST_F( test::CreateTestFormField("Email", "email", "donkey", "email", &field); // Autocomplete manager is not called for suggestions. - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); GetAutofillSuggestions(form, field); } TEST_F(AutofillManagerTest, AutocompleteOffRespectedForAutocomplete) { TestAutofillClient client; - autofill_manager_.reset(new TestAutofillManager(autofill_driver_.get(), - &client, &personal_data_)); + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_, + autocomplete_history_manager_.get())); autofill_manager_->SetAutofillEnabled(false); autofill_manager_->SetExternalDelegate(external_delegate_.get()); - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0); + EXPECT_CALL(*(autocomplete_history_manager_.get()), + OnGetAutocompleteSuggestions) + .Times(0); // Set up our form data. FormData form; @@ -4175,6 +3941,20 @@ TEST_F(AutofillManagerTest, AutocompleteOffRespectedForAutocomplete) { GetAutofillSuggestions(form, *field); } +TEST_F(AutofillManagerTest, DestructorCancelsAutocompleteQueries) { + EXPECT_CALL(*(autocomplete_history_manager_.get()), CancelPendingQueries) + .Times(1); + autofill_manager_.reset(); +} + +// Make sure that we don't error out when AutocompleteHistoryManager was +// destroyed before AutofillManager. +TEST_F(AutofillManagerTest, Destructor_DeletedAutocomplete_Works) { + // The assertion here is that no exceptions will be thrown. + autocomplete_history_manager_.reset(); + autofill_manager_.reset(); +} + // Test that OnLoadedServerPredictions can obtain the FormStructure with the // signature of the queried form and apply type predictions. TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { @@ -4186,7 +3966,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); form_structure->DetermineHeuristicTypes(); - autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); + autofill_manager_->AddSeenFormStructure( + std::unique_ptr<TestFormStructure>(form_structure)); // Similarly, a second form. FormData form2; @@ -4206,7 +3987,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { TestFormStructure* form_structure2 = new TestFormStructure(form2); form_structure2->DetermineHeuristicTypes(); - autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure2)); + autofill_manager_->AddSeenFormStructure( + std::unique_ptr<TestFormStructure>(form_structure2)); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(3); @@ -4368,7 +4150,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) { // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); form_structure->DetermineHeuristicTypes(); - autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); + autofill_manager_->AddSeenFormStructure( + std::unique_ptr<TestFormStructure>(form_structure)); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(3); @@ -4422,7 +4205,8 @@ TEST_F(AutofillManagerTest, DetermineHeuristicsWithOverallPrediction) { // |form_structure| will be owned by |autofill_manager_|. TestFormStructure* form_structure = new TestFormStructure(form); form_structure->DetermineHeuristicTypes(); - autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); + autofill_manager_->AddSeenFormStructure( + std::unique_ptr<TestFormStructure>(form_structure)); AutofillQueryResponseContents response; response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_FIRST); @@ -4497,7 +4281,8 @@ TEST_F(AutofillManagerTest, FormSubmittedServerTypes) { server_types.push_back(form_structure->field(i)->heuristic_type()); } form_structure->SetFieldTypes(heuristic_types, server_types); - autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure)); + autofill_manager_->AddSeenFormStructure( + std::unique_ptr<TestFormStructure>(form_structure)); // Fill the form. const char guid[] = "00000000-0000-0000-0000-000000000001"; @@ -5452,8 +5237,8 @@ TEST_F(AutofillManagerTest, // !should_autocomplete for AutocompleteHistoryManager::OnWillSubmitForm. TEST_F(AutofillManagerTest, DontSaveCvcInAutocompleteHistory) { FormData form_seen_by_ahm; - MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager(); - EXPECT_CALL(*m, OnWillSubmitForm(_)).WillOnce(SaveArg<0>(&form_seen_by_ahm)); + EXPECT_CALL(*(autocomplete_history_manager_.get()), OnWillSubmitForm(_, true)) + .WillOnce(SaveArg<0>(&form_seen_by_ahm)); FormData form; form.name = ASCIIToUTF16("MyForm"); @@ -5483,8 +5268,8 @@ TEST_F(AutofillManagerTest, DontSaveCvcInAutocompleteHistory) { FormSubmitted(form); EXPECT_EQ(form.fields.size(), form_seen_by_ahm.fields.size()); - ASSERT_EQ(arraysize(test_fields), form_seen_by_ahm.fields.size()); - for (size_t i = 0; i < arraysize(test_fields); ++i) { + ASSERT_EQ(base::size(test_fields), form_seen_by_ahm.fields.size()); + for (size_t i = 0; i < base::size(test_fields); ++i) { EXPECT_EQ( form_seen_by_ahm.fields[i].should_autocomplete, test_fields[i].expected_field_type != CREDIT_CARD_VERIFICATION_CODE); @@ -5514,8 +5299,8 @@ TEST_F(AutofillManagerTest, DontOfferToSavePaymentsCard) { full_card_unmask_delegate()->OnUnmaskResponse(response); autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, "4012888888881881"); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); } TEST_F(AutofillManagerTest, FillInUpdatedExpirationDate) { @@ -6174,38 +5959,6 @@ TEST_F(AutofillManagerTest, } } -// Tests that querying for credit card field suggestions notifies the -// driver of an interaction with a credit card field. -TEST_F(AutofillManagerTest, NotifyDriverOfCreditCardInteraction) { - // Set up a credit card form. - FormData form; - form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); - form.action = GURL("https://myform.com/submit.html"); - FormFieldData field; - test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field); - field.should_autocomplete = false; - form.fields.push_back(field); - test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field); - field.should_autocomplete = true; - form.fields.push_back(field); - test::CreateTestFormField("Expiration Month", "ccexpiresmonth", "", "text", - &field); - field.should_autocomplete = false; - form.fields.push_back(field); - form.fields.push_back(field); - std::vector<FormData> forms(1, form); - FormsSeen(forms); - EXPECT_FALSE(autofill_driver_->GetDidInteractWithCreditCardForm()); - - // The driver should always be notified. - for (const FormFieldData& field : form.fields) { - GetAutofillSuggestions(form, field); - EXPECT_TRUE(autofill_driver_->GetDidInteractWithCreditCardForm()); - autofill_driver_->ClearDidInteractWithCreditCardForm(); - } -} - // Tests that a form with server only types is still autofillable if the form // gets updated in cache. TEST_F(AutofillManagerTest, DisplaySuggestionsForUpdatedServerTypedForm) { @@ -6401,7 +6154,8 @@ TEST_F(AutofillManagerTest, IsRichQueryEnabled_FeatureEnabled) { << "Channel " << static_cast<int>(channel)); EXPECT_CALL(autofill_client_, GetChannel()).WillOnce(Return(channel)); TestAutofillManager test_instance(autofill_driver_.get(), &autofill_client_, - &personal_data_); + &personal_data_, + autocomplete_history_manager_.get()); switch (channel) { case version_info::Channel::STABLE: case version_info::Channel::BETA: @@ -6434,7 +6188,8 @@ TEST_F(AutofillManagerTest, IsRichQueryEnabled_FeatureDisabled) { EXPECT_FALSE(AutofillManager::IsRichQueryEnabled(channel)); EXPECT_CALL(autofill_client_, GetChannel()).WillOnce(Return(channel)); TestAutofillManager test_instance(autofill_driver_.get(), &autofill_client_, - &personal_data_); + &personal_data_, + autocomplete_history_manager_.get()); EXPECT_FALSE(test_instance.is_rich_query_enabled()); } } @@ -6559,6 +6314,47 @@ TEST_F(AutofillManagerTest, HasSubstr("Autofill.FormEvents.Address")))); } +// Tests that a call to the PDM's SyncServiceInitialized happens if in incognito +// mode even if the sync service is null. +TEST_F(AutofillManagerTest, CallingOnSyncServiceInitialized_NotOffTheRecord) { + // Setup the test PDM. + TestPersonalDataManager test_pdm; + ASSERT_FALSE(test_pdm.sync_service_initialized()); + + // Set the client to return a null sync service (default). + TestAutofillClient client; + + // Create a new AutofillManager. + autofill_manager_.reset( + new TestAutofillManager(autofill_driver_.get(), &client, &test_pdm, + autocomplete_history_manager_.get())); + + // Make sure the PDM's sync service was initialized. + EXPECT_TRUE(test_pdm.sync_service_initialized()); +} + +// Tests that no call to the PDM's SyncServiceInitialized happens in incognito +// mode. +TEST_F(AutofillManagerTest, CallingOnSyncServiceInitialized_OffTheRecord) { + // Setup the test PDM. + TestPersonalDataManager test_pdm; + ASSERT_FALSE(test_pdm.sync_service_initialized()); + + // Set the client to return a null sync service (default). + TestAutofillClient client; + + // Set the driver to return that the user is off the record. + TestAutofillDriver driver; + driver.SetIsIncognito(true); + + // Create a new AutofillManager. + autofill_manager_.reset(new TestAutofillManager( + &driver, &client, &test_pdm, autocomplete_history_manager_.get())); + + // Make sure the PDM's sync service was not initialized. + EXPECT_FALSE(test_pdm.sync_service_initialized()); +} + // Test param indicates if there is an active screen reader. class OnFocusOnFormFieldTest : public AutofillManagerTest, public testing::WithParamInterface<bool> { diff --git a/chromium/components/autofill/core/browser/autofill_metadata.cc b/chromium/components/autofill/core/browser/autofill_metadata.cc index fa5619f701f..99527207f77 100644 --- a/chromium/components/autofill/core/browser/autofill_metadata.cc +++ b/chromium/components/autofill/core/browser/autofill_metadata.cc @@ -13,4 +13,14 @@ bool AutofillMetadata::operator==(const AutofillMetadata& metadata) const { billing_address_id == metadata.billing_address_id; } +bool AutofillMetadata::operator!=(const AutofillMetadata& metadata) const { + return !(*this == metadata); +} + +std::ostream& operator<<(std::ostream& os, const AutofillMetadata& metadata) { + return os << metadata.id << " " << metadata.use_count << " " + << metadata.use_date << " " << metadata.has_converted << " " + << metadata.billing_address_id; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_metadata.h b/chromium/components/autofill/core/browser/autofill_metadata.h index 50c67d16f19..6a70a06bb49 100644 --- a/chromium/components/autofill/core/browser/autofill_metadata.h +++ b/chromium/components/autofill/core/browser/autofill_metadata.h @@ -19,6 +19,7 @@ struct AutofillMetadata { ~AutofillMetadata(){}; bool operator==(const AutofillMetadata&) const; + bool operator!=(const AutofillMetadata&) const; // The ID for the model. This should be the guid for local data and server_id // for the server data. @@ -39,6 +40,9 @@ struct AutofillMetadata { std::string billing_address_id; }; +// So we can compare AutofillMetadata with EXPECT_EQ(). +std::ostream& operator<<(std::ostream& os, const AutofillMetadata& metadata); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_ diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc index 9c199d4d3cc..6e405659280 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics.cc @@ -57,10 +57,6 @@ enum FieldTypeGroupForMetrics { NUM_FIELD_TYPE_GROUPS_FOR_METRICS }; -const int KMaxFieldTypeGroupMetric = - (NUM_FIELD_TYPE_GROUPS_FOR_METRICS << 8) | - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS; - std::string PreviousSaveCreditCardPromptUserDecisionToString( int previous_save_credit_card_prompt_user_decision) { DCHECK_LT(previous_save_credit_card_prompt_user_decision, @@ -236,22 +232,6 @@ int GetFieldTypeGroupMetric(ServerFieldType field_type, namespace { -// A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name| -// to vary over the program's runtime. -// TODO(crbug.com/850520): Remove this function when the remaining logs use the -// histogram_functions instead. -void LogUMAHistogramEnumeration(const std::string& name, - int sample, - int boundary_value) { - DCHECK_LT(sample, boundary_value); - - // Note: This leaks memory, which is expected behavior. - base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( - name, 1, boundary_value, boundary_value + 1, - base::HistogramBase::kUmaTargetedHistogramFlag); - histogram->Add(sample); -} - const char* GetQualityMetricPredictionSource( AutofillMetrics::QualityMetricPredictionSource source) { switch (source) { @@ -371,18 +351,16 @@ void LogPredictionQualityMetricsForFieldsOnlyFilledWhenFocused( // Only log aggregate true negative; do not log type specific metrics // for UNKNOWN/EMPTY. DVLOG(2) << "TRUE NEGATIVE"; - base::UmaHistogramEnumeration( + base::UmaHistogramSparse( aggregate_histogram, (is_empty ? AutofillMetrics::TRUE_NEGATIVE_EMPTY : (is_ambiguous ? AutofillMetrics::TRUE_NEGATIVE_AMBIGUOUS - : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN)), - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN))); if (log_rationalization_metrics) { - base::UmaHistogramEnumeration( + base::UmaHistogramSparse( rationalization_quality_histogram, (is_empty ? AutofillMetrics::RATIONALIZATION_GOOD - : AutofillMetrics::RATIONALIZATION_OK), - AutofillMetrics::NUM_RATIONALIZATION_QUALITY_METRICS); + : AutofillMetrics::RATIONALIZATION_OK)); } return; } @@ -393,20 +371,17 @@ void LogPredictionQualityMetricsForFieldsOnlyFilledWhenFocused( // automatically if there has been no rationalization. if (predicted_type == actual_type) { DVLOG(2) << "TRUE POSITIVE"; - base::UmaHistogramEnumeration( - aggregate_histogram, AutofillMetrics::TRUE_POSITIVE, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); - LogUMAHistogramEnumeration( + base::UmaHistogramSparse(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE); + base::UmaHistogramSparse( type_specific_histogram, - GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE), - KMaxFieldTypeGroupMetric); + GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE)); if (log_rationalization_metrics) { bool duplicated_filling = DuplicatedFilling(form, field); - base::UmaHistogramEnumeration( + base::UmaHistogramSparse( rationalization_quality_histogram, (duplicated_filling ? AutofillMetrics::RATIONALIZATION_BAD - : AutofillMetrics::RATIONALIZATION_OK), - AutofillMetrics::NUM_RATIONALIZATION_QUALITY_METRICS); + : AutofillMetrics::RATIONALIZATION_OK)); } return; } @@ -414,24 +389,21 @@ void LogPredictionQualityMetricsForFieldsOnlyFilledWhenFocused( DVLOG(2) << "MISMATCH"; // Here the prediction is wrong, but user has to provide some value still. // This should be a false negative. - base::UmaHistogramEnumeration( - aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + base::UmaHistogramSparse(aggregate_histogram, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH); // Log FALSE_NEGATIVE_MISMATCH for predicted type if it did predicted // something but actual type is different. if (predicted_type != UNKNOWN_TYPE) - LogUMAHistogramEnumeration( + base::UmaHistogramSparse( type_specific_histogram, GetFieldTypeGroupMetric(predicted_type, - AutofillMetrics::FALSE_NEGATIVE_MISMATCH), - KMaxFieldTypeGroupMetric); + AutofillMetrics::FALSE_NEGATIVE_MISMATCH)); if (log_rationalization_metrics) { // Logging RATIONALIZATION_OK despite of type mismatch here because autofill // would have got it wrong with or without rationalization. Rationalization // here does not help, neither does it do any harm. - base::UmaHistogramEnumeration( - rationalization_quality_histogram, AutofillMetrics::RATIONALIZATION_OK, - AutofillMetrics::NUM_RATIONALIZATION_QUALITY_METRICS); + base::UmaHistogramSparse(rationalization_quality_histogram, + AutofillMetrics::RATIONALIZATION_OK); } return; } @@ -451,25 +423,22 @@ void LogPredictionQualityMetricsForCommonFields( // Only log aggregate true negative; do not log type specific metrics // for UNKNOWN/EMPTY. DVLOG(2) << "TRUE NEGATIVE"; - base::UmaHistogramEnumeration( + base::UmaHistogramSparse( aggregate_histogram, (is_empty ? AutofillMetrics::TRUE_NEGATIVE_EMPTY : (is_ambiguous ? AutofillMetrics::TRUE_NEGATIVE_AMBIGUOUS - : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN)), - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN))); return; } DVLOG(2) << "TRUE POSITIVE"; // Log both aggregate and type specific true positive if we correctly // predict that type with which the field was filled. - base::UmaHistogramEnumeration( - aggregate_histogram, AutofillMetrics::TRUE_POSITIVE, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); - LogUMAHistogramEnumeration( + base::UmaHistogramSparse(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE); + base::UmaHistogramSparse( type_specific_histogram, - GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE), - KMaxFieldTypeGroupMetric); + GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE)); return; } @@ -483,12 +452,9 @@ void LogPredictionQualityMetricsForCommonFields( (is_empty ? AutofillMetrics::FALSE_POSITIVE_EMPTY : (is_ambiguous ? AutofillMetrics::FALSE_POSITIVE_AMBIGUOUS : AutofillMetrics::FALSE_POSITIVE_UNKNOWN)); - base::UmaHistogramEnumeration( - aggregate_histogram, metric, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); - LogUMAHistogramEnumeration(type_specific_histogram, - GetFieldTypeGroupMetric(predicted_type, metric), - KMaxFieldTypeGroupMetric); + base::UmaHistogramSparse(aggregate_histogram, metric); + base::UmaHistogramSparse(type_specific_histogram, + GetFieldTypeGroupMetric(predicted_type, metric)); return; } @@ -497,14 +463,12 @@ void LogPredictionQualityMetricsForCommonFields( // unknown. if (predicted_type == UNKNOWN_TYPE) { DVLOG(2) << "FALSE NEGATIVE"; - base::UmaHistogramEnumeration( - aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); - LogUMAHistogramEnumeration( + base::UmaHistogramSparse(aggregate_histogram, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN); + base::UmaHistogramSparse( type_specific_histogram, GetFieldTypeGroupMetric(actual_type, - AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), - KMaxFieldTypeGroupMetric); + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN)); return; } @@ -515,19 +479,16 @@ void LogPredictionQualityMetricsForCommonFields( // This is a mismatch. From the reference of the actual type, this is a false // negative (it was T, but predicted U). From the reference of the prediction, // this is a false positive (predicted it was T, but it was U). - base::UmaHistogramEnumeration( - aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); - LogUMAHistogramEnumeration( + base::UmaHistogramSparse(aggregate_histogram, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH); + base::UmaHistogramSparse( type_specific_histogram, GetFieldTypeGroupMetric(actual_type, - AutofillMetrics::FALSE_NEGATIVE_MISMATCH), - KMaxFieldTypeGroupMetric); - LogUMAHistogramEnumeration( + AutofillMetrics::FALSE_NEGATIVE_MISMATCH)); + base::UmaHistogramSparse( type_specific_histogram, GetFieldTypeGroupMetric(predicted_type, - AutofillMetrics::FALSE_POSITIVE_MISMATCH), - KMaxFieldTypeGroupMetric); + AutofillMetrics::FALSE_POSITIVE_MISMATCH)); } // Logs field type prediction quality metrics. The primary histogram name is @@ -1512,6 +1473,7 @@ void AutofillMetrics::LogProfileActionOnFormSubmitted( void AutofillMetrics::LogAutofillFormSubmittedState( AutofillFormSubmittedState state, bool is_for_credit_card, + bool has_upi_vpa_field, const std::set<FormType>& form_types, const base::TimeTicks& form_parsed_timestamp, FormSignature form_signature, @@ -1549,9 +1511,9 @@ void AutofillMetrics::LogAutofillFormSubmittedState( NOTREACHED(); break; } - form_interactions_ukm_logger->LogFormSubmitted(is_for_credit_card, form_types, - state, form_parsed_timestamp, - form_signature); + form_interactions_ukm_logger->LogFormSubmitted( + is_for_credit_card, has_upi_vpa_field, form_types, state, + form_parsed_timestamp, form_signature); } // static @@ -1601,6 +1563,11 @@ void AutofillMetrics::LogShowedHttpNotSecureExplanation() { } // static +void AutofillMetrics::LogAutocompleteDaysSinceLastUse(size_t days) { + UMA_HISTOGRAM_COUNTS_1000("Autocomplete.DaysSinceLastUse", days); +} + +// static void AutofillMetrics::LogAutocompleteSuggestionAcceptedIndex(int index) { base::UmaHistogramSparse("Autofill.SuggestionAcceptedIndex.Autocomplete", std::min(index, kMaxBucketsCount)); @@ -1622,6 +1589,10 @@ void AutofillMetrics::OnAutocompleteSuggestionsShown() { AutofillMetrics::Log(AutocompleteEvent::AUTOCOMPLETE_SUGGESTIONS_SHOWN); } +void AutofillMetrics::LogNumberOfAutocompleteEntriesCleanedUp(int nb_entries) { + UMA_HISTOGRAM_COUNTS_1000("Autocomplete.Cleanup", nb_entries); +} + // static void AutofillMetrics::Log(AutocompleteEvent event) { DCHECK_LT(event, AutocompleteEvent::NUM_AUTOCOMPLETE_EVENTS); @@ -1657,8 +1628,9 @@ const char* AutofillMetrics::SubmissionSourceToUploadEventMetric( void AutofillMetrics::LogUploadEvent(SubmissionSource submission_source, bool was_sent) { UMA_HISTOGRAM_BOOLEAN("Autofill.UploadEvent", was_sent); - LogUMAHistogramEnumeration( - SubmissionSourceToUploadEventMetric(submission_source), was_sent, 2); + base::UmaHistogramEnumeration( + SubmissionSourceToUploadEventMetric(submission_source), + was_sent ? UploadEventStatus::kSent : UploadEventStatus::kNotSent); } // static @@ -2227,6 +2199,7 @@ void AutofillMetrics::LogWalletSyncTransportCardsOptIn(bool is_opted_in) { void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted( bool is_for_credit_card, + bool has_upi_vpa_field, const std::set<FormType>& form_types, AutofillFormSubmittedState state, const base::TimeTicks& form_parsed_timestamp, @@ -2237,6 +2210,7 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted( ukm::builders::Autofill_FormSubmitted builder(source_id_); builder.SetAutofillFormSubmittedState(static_cast<int>(state)) .SetIsForCreditCard(is_for_credit_card) + .SetHasUpiVpaField(has_upi_vpa_field) .SetFormTypes(FormTypesToBitVector(form_types)) .SetFormSignature(HashFormSignature(form_signature)); if (form_parsed_timestamp.is_null()) diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h index eef415c2805..2e2f6150140 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.h +++ b/chromium/components/autofill/core/browser/autofill_metrics.h @@ -843,6 +843,9 @@ class AutofillMetrics { NUM_CONVERTED_ADDRESS_CONVERSION_TYPES }; + // To record whether or not the upload event was sent, + enum class UploadEventStatus { kNotSent, kSent, kMaxValue = kSent }; + // Utility to log URL keyed form interaction events. class FormInteractionsUkmLogger { public: @@ -888,6 +891,7 @@ class AutofillMetrics { ServerFieldType predicted_type, ServerFieldType actual_type); void LogFormSubmitted(bool is_for_credit_card, + bool has_upi_vpa_field, const std::set<FormType>& form_types, AutofillFormSubmittedState state, const base::TimeTicks& form_parsed_timestamp, @@ -1177,12 +1181,19 @@ class AutofillMetrics { // Log the index of the selected Autofill suggestion in the popup. static void LogAutofillSuggestionAcceptedIndex(int index); + // Log the number of days since an Autocomplete suggestion was last used. + static void LogAutocompleteDaysSinceLastUse(size_t days); + // Log the index of the selected Autocomplete suggestion in the popup. static void LogAutocompleteSuggestionAcceptedIndex(int index); - // Log the fact that a autocomplete popup was shown. + // Log the fact that an autocomplete popup was shown. static void OnAutocompleteSuggestionsShown(); + // Log the number of autocomplete entries that were cleaned-up as a result + // of the Autocomplete Retention Policy. + static void LogNumberOfAutocompleteEntriesCleanedUp(int nb_entries); + // Log how many autofilled fields in a given form were edited before the // submission or when the user unfocused the form (depending on // |observed_submission|). @@ -1202,6 +1213,7 @@ class AutofillMetrics { static void LogAutofillFormSubmittedState( AutofillFormSubmittedState state, bool is_for_credit_card, + bool has_upi_vpa_field, const std::set<FormType>& form_types, const base::TimeTicks& form_parsed_timestamp, FormSignature form_signature, diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc index e027498d675..213d7d340fa 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc @@ -23,6 +23,7 @@ #include "base/time/time.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/popup_item_ids.h" @@ -151,12 +152,14 @@ void VerifySubmitFormUkm(const ukm::TestAutoSetUkmRecorder& ukm_recorder, const FormData& form, AutofillMetrics::AutofillFormSubmittedState state, bool is_for_credit_card, + bool has_upi_vpa_field, const std::set<FormType>& form_types) { VerifyFormInteractionUkm( ukm_recorder, form, UkmFormSubmittedType::kEntryName, {{{UkmFormSubmittedType::kAutofillFormSubmittedStateName, state}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, is_for_credit_card}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, has_upi_vpa_field}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector(form_types)}, {UkmFormSubmittedType::kFormSignatureName, @@ -265,6 +268,7 @@ class AutofillMetricsTest : public testing::Test { std::unique_ptr<TestAutofillDriver> autofill_driver_; std::unique_ptr<TestAutofillManager> autofill_manager_; std::unique_ptr<TestPersonalDataManager> personal_data_; + std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_; std::unique_ptr<AutofillExternalDelegate> external_delegate_; base::test::ScopedFeatureList scoped_feature_list_; @@ -289,6 +293,9 @@ void AutofillMetricsTest::SetUp() { personal_data_->SetPrefService(autofill_client_.GetPrefs()); personal_data_->SetSyncServiceForTest(&sync_service_); + autocomplete_history_manager_ = + std::make_unique<MockAutocompleteHistoryManager>(); + payments::TestPaymentsClient* payments_client = new payments::TestPaymentsClient( autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(), @@ -307,7 +314,8 @@ void AutofillMetricsTest::SetUp() { std::unique_ptr<TestFormDataImporter>(test_form_data_importer)); autofill_manager_ = std::make_unique<TestAutofillManager>( - autofill_driver_.get(), &autofill_client_, personal_data_.get()); + autofill_driver_.get(), &autofill_client_, personal_data_.get(), + autocomplete_history_manager_.get()); external_delegate_ = std::make_unique<AutofillExternalDelegate>( autofill_manager_.get(), autofill_driver_.get()); autofill_manager_->SetExternalDelegate(external_delegate_.get()); @@ -528,8 +536,8 @@ TEST_F(AutofillMetricsTest, QualityMetrics) { // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Heuristic predictions. { @@ -725,8 +733,8 @@ TEST_F(AutofillMetricsTest, // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Rationalization quality. { @@ -790,8 +798,8 @@ TEST_F(AutofillMetricsTest, // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Rationalization quality. { @@ -1244,8 +1252,8 @@ TEST_F(AutofillMetricsTest, // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Rationalization quality. { @@ -1325,8 +1333,8 @@ TEST_F(AutofillMetricsTest, // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Rationalization quality. { @@ -1608,8 +1616,8 @@ TEST_P(QualityMetricsTest, Classification) { // Run the form submission code while tracking the histograms. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); ExpectedUkmMetrics expected_ukm_metrics; AppendFieldTypeUkm(form, heuristic_types, server_types, actual_types, @@ -2115,8 +2123,8 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) { // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1); @@ -2167,8 +2175,8 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) { // match what is in the test profile. form.fields[1].value = base::ASCIIToUTF16("79401"); form.fields[2].value = base::ASCIIToUTF16("2345678901"); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); for (const std::string source : {"Heuristic", "Server", "Overall"}) { std::string histogram_name = @@ -2268,8 +2276,8 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) { // Simulate form submission. base::HistogramTester histogram_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); for (const std::string source : {"Heuristic", "Server", "Overall"}) { std::string aggregate_histogram = @@ -2337,8 +2345,8 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) { // Simulate form submission. base::HistogramTester histogram_tester; autofill_manager_->OnFormsSeen(forms, TimeTicks()); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // An autofillable form was submitted, and the number of stored profiles is // logged. @@ -2371,8 +2379,8 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) { // Simulate form submission. base::HistogramTester histogram_tester; autofill_manager_->OnFormsSeen(forms, TimeTicks()); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // A non-autofillable form was submitted, and number of stored profiles is NOT // logged. @@ -2425,8 +2433,8 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) { TimeTicks()); // Simulate form submission. - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // An autofillable form was submitted, and the number of edited autofilled // fields is logged. @@ -2868,7 +2876,7 @@ TEST_F(AutofillMetricsTest, LogStoredCreditCardMetrics) { TEST_F(AutofillMetricsTest, AutofillIsEnabledAtStartup) { base::HistogramTester histogram_tester; personal_data_->SetAutofillEnabled(true); - personal_data_->Init(autofill_client_.GetDatabase(), + personal_data_->Init(scoped_refptr<AutofillWebDataService>(nullptr), /*account_database=*/nullptr, autofill_client_.GetPrefs(), /*identity_manager=*/nullptr, @@ -2883,7 +2891,7 @@ TEST_F(AutofillMetricsTest, AutofillIsEnabledAtStartup) { TEST_F(AutofillMetricsTest, AutofillIsDisabledAtStartup) { base::HistogramTester histogram_tester; personal_data_->SetAutofillEnabled(false); - personal_data_->Init(autofill_client_.GetDatabase(), + personal_data_->Init(scoped_refptr<AutofillWebDataService>(nullptr), /*account_database=*/nullptr, autofill_client_.GetPrefs(), /*identity_manager=*/nullptr, @@ -3001,8 +3009,7 @@ TEST_P(AutofillMetricsCompanyTest, CompanyNameSuggestions) { histogram_tester.ExpectUniqueSample("Autofill.AddressSuggestionsCount", 2, 1); } else { - EXPECT_EQ(nullptr, base::StatisticsRecorder::FindHistogram( - "Autofill.AddressSuggestionsCount")); + histogram_tester.ExpectTotalCount("Autofill.AddressSuggestionsCount", 0); } } } @@ -3092,8 +3099,8 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) { base::UserActionTester user_action_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_OnWillSubmitForm")); EXPECT_EQ(1, user_action_tester.GetActionCount( @@ -3139,9 +3146,37 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) { Collapse(CalculateFormSignature(form))}}}); // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState| // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|. - VerifySubmitFormUkm( - test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, - /*is_for_credit_card=*/true, {FormType::CREDIT_CARD_FORM}); + VerifySubmitFormUkm(test_ukm_recorder_, form, + AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, + /*is_for_credit_card=*/true, /* has_upi_vpa_field=*/false, + {FormType::CREDIT_CARD_FORM}); +} + +// Test that the UPI Checkout flow form submit is correctly logged +TEST_F(AutofillMetricsTest, UpiVpaUkmTest) { + FormData form; + form.name = ASCIIToUTF16("TestForm"); + form.origin = GURL("http://example.com/form.html"); + form.action = GURL("http://example.com/submit.html"); + form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); + FormFieldData field; + test::CreateTestFormField("Enter VPA", "upi-vpa", "unique_id@upi", "text", + &field); + form.fields.push_back(field); + + std::vector<FormData> forms(1, form); + + { + autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + + VerifySubmitFormUkm(test_ukm_recorder_, forms.back(), + AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, + /*is_for_credit_card=*/false, + /* has_upi_vpa_field */ true, + /* UPI VPA has Unknown form type.*/ + {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE}); + PurgeUKM(); + } } // Test that the profile checkout flow user actions are correctly logged. @@ -3227,8 +3262,8 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) { base::UserActionTester user_action_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_OnWillSubmitForm")); EXPECT_EQ(1, user_action_tester.GetActionCount( @@ -3278,7 +3313,8 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) { // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|. VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, - /*is_for_credit_card=*/false, {FormType::ADDRESS_FORM}); + /*is_for_credit_card=*/false, + /* has_upi_vpa_field=*/false, {FormType::ADDRESS_FORM}); } // Tests that the Autofill_PolledCreditCardSuggestions user action is only @@ -3998,8 +4034,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) { autofill_manager_->MakeFrontendID(guid, std::string())); autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, "6011000990139424"); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1); @@ -4100,8 +4136,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) { autofill_manager_->MakeFrontendID(guid, std::string())); autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, "4444333322221111"); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard.BankNameDisplayed", AutofillMetrics:: @@ -4125,8 +4161,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) { autofill_manager_->MakeFrontendID(guid, std::string())); autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, "4444333322221111"); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard.BankNameDisplayed", AutofillMetrics:: @@ -4288,8 +4324,8 @@ TEST_F(AutofillMetricsTest, autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, @@ -4330,8 +4366,8 @@ TEST_P(AutofillMetricsIFrameTest, autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics:: @@ -4379,8 +4415,8 @@ TEST_P(AutofillMetricsIFrameTest, autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics:: @@ -4429,8 +4465,8 @@ TEST_P(AutofillMetricsIFrameTest, autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics:: @@ -4479,8 +4515,8 @@ TEST_P(AutofillMetricsIFrameTest, autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics:: @@ -4534,8 +4570,8 @@ TEST_P(AutofillMetricsIFrameTest, AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(), autofill_manager_->MakeFrontendID(guid, std::string())); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics:: @@ -4598,8 +4634,8 @@ TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) { autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, @@ -4640,8 +4676,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", @@ -4659,6 +4695,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } @@ -4673,8 +4710,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 1); @@ -4702,6 +4739,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } @@ -4718,8 +4756,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Trigger UploadFormDataAsyncCallback. autofill_manager_->Reset(); histogram_tester.ExpectBucketCount( @@ -4749,6 +4787,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } @@ -4766,8 +4805,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { autofill_manager_->FillOrPreviewForm( AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(guid, std::string())); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -4793,6 +4832,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } @@ -4811,8 +4851,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { autofill_manager_->FillOrPreviewForm( AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(guid, std::string())); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -4839,6 +4879,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } @@ -4857,8 +4898,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { autofill_manager_->MakeFrontendID(guid, std::string())); autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS, "6011000990139424"); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1); @@ -4890,6 +4931,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } @@ -4911,16 +4953,17 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); VerifyFormInteractionUkm( test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName, @@ -4928,6 +4971,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, true}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM})}, {UkmFormSubmittedType::kFormSignatureName, @@ -4936,6 +4980,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, true}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM})}, {UkmFormSubmittedType::kFormSignatureName, @@ -5021,8 +5066,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { // interaction. base::HistogramTester histogram_tester; autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0); @@ -5106,6 +5151,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, /*is_for_credit_card=*/true, + /* has_upi_vpa_field=*/false, {FormType::CREDIT_CARD_FORM}); } } @@ -5145,8 +5191,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -5171,8 +5217,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1); @@ -5200,8 +5246,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { autofill_manager_->FillOrPreviewForm( AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(guid, std::string())); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -5230,8 +5276,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { autofill_manager_->FillOrPreviewForm( AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(guid, std::string())); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -5291,10 +5337,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -5374,8 +5420,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { // interaction. base::HistogramTester histogram_tester; autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0); @@ -5818,8 +5864,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -5829,7 +5875,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, - /*is_for_credit_card=*/false, {FormType::ADDRESS_FORM}); + /*is_for_credit_card=*/false, + /* has_upi_vpa_field=*/false, {FormType::ADDRESS_FORM}); } // Reset the autofill manager state and purge UKM logs. @@ -5844,8 +5891,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); // Trigger UploadFormDataAsyncCallback. autofill_manager_->Reset(); histogram_tester.ExpectBucketCount( @@ -5857,7 +5904,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { VerifySubmitFormUkm(test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, - /*is_for_credit_card=*/false, {FormType::ADDRESS_FORM}); + /*is_for_credit_card=*/false, + /* has_upi_vpa_field=*/false, {FormType::ADDRESS_FORM}); } // Reset the autofill manager state and purge UKM logs. @@ -5871,8 +5919,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1); @@ -5894,8 +5942,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { autofill_manager_->FillOrPreviewForm( AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(std::string(), guid)); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -5913,10 +5961,10 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", @@ -5953,8 +6001,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { // interaction. base::HistogramTester histogram_tester; autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", @@ -6025,8 +6073,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -6045,8 +6093,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1); @@ -6068,8 +6116,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { autofill_manager_->FillOrPreviewForm( AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), autofill_manager_->MakeFrontendID(std::string(), guid)); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -6087,10 +6135,10 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { base::HistogramTester histogram_tester; autofill_manager_->OnQueryFormFieldAutofill( 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0); @@ -6136,8 +6184,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { // interaction. base::HistogramTester histogram_tester; autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0); @@ -6409,8 +6457,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1); @@ -6422,6 +6470,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6445,8 +6494,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1); @@ -6458,6 +6507,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6483,8 +6533,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS, @@ -6498,6 +6548,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6519,8 +6570,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS, 1); @@ -6545,6 +6596,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6568,8 +6620,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME, 1); @@ -6581,6 +6633,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6605,8 +6658,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1); @@ -6618,6 +6671,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6649,8 +6703,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { {}); base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1); @@ -6662,6 +6716,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector( {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}, @@ -6721,8 +6776,8 @@ TEST_F( form.fields[2].value = ASCIIToUTF16("12345678901"); form.fields[2].is_autofilled = true; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FormSubmittedState", AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1); @@ -6737,6 +6792,7 @@ TEST_F( AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL}, {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmFormSubmittedType::kIsForCreditCardName, false}, + {UkmFormSubmittedType::kHasUpiVpaFieldName, false}, {UkmFormSubmittedType::kFormTypesName, AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})}, {UkmFormSubmittedType::kFormSignatureName, @@ -7299,12 +7355,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { { base::HistogramTester histogram_tester; autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); - base::TimeTicks parse_time = autofill_manager_->form_structures() - .begin() - ->second->form_parsed_timestamp(); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, - parse_time + base::TimeDelta::FromMicroseconds(17)); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectTotalCount( "Autofill.FillDuration.FromLoad.WithAutofill", 0); @@ -7328,9 +7380,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { autofill_manager_->OnTextFieldDidChange( form, form.fields.front(), gfx::RectF(), parse_time + base::TimeDelta::FromMicroseconds(3)); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, - parse_time + base::TimeDelta::FromMicroseconds(17)); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectTotalCount( "Autofill.FillDuration.FromLoad.WithAutofill", 0); @@ -7355,9 +7406,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { ->second->form_parsed_timestamp(); autofill_manager_->OnDidFillAutofillFormData( form, parse_time + base::TimeDelta::FromMicroseconds(5)); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, - parse_time + base::TimeDelta::FromMicroseconds(17)); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FillDuration.FromLoad.WithAutofill", 16, 1); @@ -7387,9 +7437,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { autofill_manager_->OnTextFieldDidChange( form, form.fields.front(), gfx::RectF(), parse_time + base::TimeDelta::FromMicroseconds(3)); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, - parse_time + base::TimeDelta::FromMicroseconds(17)); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FillDuration.FromLoad.WithAutofill", 16, 1); @@ -7418,9 +7467,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { autofill_manager_->OnTextFieldDidChange( form, form.fields.front(), gfx::RectF(), parse_time + base::TimeDelta::FromMicroseconds(3)); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, - parse_time + base::TimeDelta::FromMicroseconds(17)); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectUniqueSample( "Autofill.FillDuration.FromLoad.WithAutofill", 16, 1); @@ -7446,9 +7494,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { if (kv.second->form_parsed_timestamp() > parse_time) parse_time = kv.second->form_parsed_timestamp(); } - autofill_manager_->OnFormSubmitted( - second_form, false, SubmissionSource::FORM_SUBMISSION, - parse_time + base::TimeDelta::FromMicroseconds(17)); + autofill_manager_->OnFormSubmitted(second_form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectTotalCount( "Autofill.FillDuration.FromLoad.WithAutofill", 0); @@ -7746,8 +7793,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log NEW_PROFILE_CREATED for the metric since a new profile is // submitted. autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", AutofillMetrics::NEW_PROFILE_CREATED, 1); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7759,8 +7806,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log EXISTING_PROFILE_USED for the metric since the same profile // is submitted. autofill_manager_->OnFormsSeen(second_forms, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - second_form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(second_form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", AutofillMetrics::NEW_PROFILE_CREATED, 1); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7772,8 +7819,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log NEW_PROFILE_CREATED for the metric since a new profile is // submitted. autofill_manager_->OnFormsSeen(third_forms, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - third_form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(third_form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", AutofillMetrics::NEW_PROFILE_CREATED, 2); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7785,8 +7832,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log EXISTING_PROFILE_UPDATED for the metric since the profile was // updated. autofill_manager_->OnFormsSeen(fourth_forms, TimeTicks::Now()); - autofill_manager_->OnFormSubmitted( - fourth_form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(fourth_form, false, + SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", AutofillMetrics::NEW_PROFILE_CREATED, 2); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7959,8 +8006,8 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) { // Simulate submitting the credit card form. { base::HistogramTester histograms; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histograms.ExpectBucketCount( "Autofill.FormEvents.CreditCard.OnNonsecurePage", AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1); @@ -8017,8 +8064,8 @@ TEST_F(AutofillMetricsTest, // Simulate submitting the credit card form. { base::HistogramTester histograms; - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); histograms.ExpectBucketCount( "Autofill.FormEvents.CreditCard", AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -8441,6 +8488,14 @@ TEST_F(AutofillMetricsTest, OnAutocompleteSuggestionsShown) { /*expected_count=*/1); } +TEST_F(AutofillMetricsTest, LogNumberOfAutocompleteEntriesCleanedUp) { + base::HistogramTester histogram_tester; + const int kNbEntries = 10; + AutofillMetrics::LogNumberOfAutocompleteEntriesCleanedUp(kNbEntries); + histogram_tester.ExpectBucketCount("Autocomplete.Cleanup", kNbEntries, + /*expected_count=*/1); +} + // Verify that we correctly log FormEvent metrics with the appropriate sync // state. TEST_F(AutofillMetricsTest, FormEventMetrics_BySyncState) { diff --git a/chromium/components/autofill/core/browser/autofill_observer.cc b/chromium/components/autofill/core/browser/autofill_observer.cc new file mode 100644 index 00000000000..43030e44811 --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_observer.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2019 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 "components/autofill/core/browser/autofill_observer.h" + +#include "base/run_loop.h" + +namespace autofill { + +AutofillObserver::AutofillObserver(NotificationType notification_type, + bool detach_on_notify) + : notification_type_(notification_type), + detach_on_notify_(detach_on_notify) {} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_observer.h b/chromium/components/autofill/core/browser/autofill_observer.h new file mode 100644 index 00000000000..ea32c66fc1f --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_observer.h @@ -0,0 +1,38 @@ +// Copyright 2019 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_OBSERVER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_OBSERVER_H_ + +#include "base/observer_list_types.h" + +namespace autofill { + +class AutofillObserver : public base::CheckedObserver { + public: + enum NotificationType { + AutocompleteFormSubmitted, + AutocompleteFormSkipped, + AutocompleteCleanupDone + }; + + // |notification_type| is the notification type that this observer observes. + // |detach_on_notify| will let the AutofillSubject know that this + // observer only wants to watch for the first notification of that type. + AutofillObserver(NotificationType notification_type, bool detach_on_notify); + + // Invoked by the watched AutofillSubject. + virtual void OnNotify() = 0; + + NotificationType notification_type() { return notification_type_; } + bool detach_on_notify() { return detach_on_notify_; } + + private: + NotificationType notification_type_; + bool detach_on_notify_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_OBSERVER_H_ diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc index 71606bb2b61..750b4bb9b34 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.cc +++ b/chromium/components/autofill/core/browser/autofill_profile.cc @@ -15,10 +15,10 @@ #include "base/i18n/case_conversion.h" #include "base/i18n/char_iterator.h" #include "base/logging.h" -#include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/sha1.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" @@ -151,9 +151,9 @@ void GetFieldsForDistinguishingProfiles( std::vector<ServerFieldType> default_fields; if (!suggested_fields) { - default_fields.assign( - kDefaultDistinguishingFields, - kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields)); + default_fields.assign(kDefaultDistinguishingFields, + kDefaultDistinguishingFields + + base::size(kDefaultDistinguishingFields)); if (excluded_field == UNKNOWN_TYPE) { distinguishing_fields->swap(default_fields); return; @@ -312,6 +312,10 @@ bool AutofillProfile::SetMetadata(const AutofillMetadata metadata) { return true; } +bool AutofillProfile::IsDeletable() const { + return AutofillDataModel::IsDeletable() && !IsVerified(); +} + // TODO(crbug.com/589535): Disambiguate similar field types before uploading. void AutofillProfile::GetMatchingTypes( const base::string16& text, @@ -444,22 +448,36 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const { bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const { return guid() == profile.guid() && language_code() == profile.language_code() && - is_client_validity_states_updated() == - profile.is_client_validity_states_updated() && Compare(profile) == 0; } bool AutofillProfile::EqualsForSyncPurposes(const AutofillProfile& profile) const { return use_count() == profile.use_count() && - use_date() == profile.use_date() && - EqualsSansGuid(profile); + UseDateEqualsInSeconds(&profile) && EqualsSansGuid(profile); +} + +bool AutofillProfile::EqualsForUpdatePurposes( + const AutofillProfile& profile) const { + return use_count() == profile.use_count() && + UseDateEqualsInSeconds(&profile) && + language_code() == profile.language_code() && Compare(profile) == 0; +} + +bool AutofillProfile::EqualsForClientValidationPurpose( + const AutofillProfile& profile) const { + for (ServerFieldType type : kSupportedTypesByClientForValidation) { + if (GetRawInfo(type).compare(profile.GetRawInfo(type))) { + return false; + } + } + return true; } bool AutofillProfile::EqualsIncludingUsageStatsForTesting( const AutofillProfile& profile) const { return use_count() == profile.use_count() && - use_date() == profile.use_date() && *this == profile; + UseDateEqualsInSeconds(&profile) && *this == profile; } bool AutofillProfile::operator==(const AutofillProfile& profile) const { @@ -804,7 +822,7 @@ void AutofillProfile::GenerateServerProfileIdentifier() { } void AutofillProfile::RecordAndLogUse() { - previous_use_date_ = use_date(); + set_previous_use_date(use_date()); UMA_HISTOGRAM_COUNTS_1000("Autofill.DaysSinceLastUse.Profile", (AutofillClock::Now() - use_date()).InDays()); RecordUse(); @@ -1097,13 +1115,15 @@ FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) { bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const { return origin() == profile.origin() && language_code() == profile.language_code() && - is_client_validity_states_updated() == - profile.is_client_validity_states_updated() && Compare(profile) == 0; } std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) { - return os << profile.guid() << " " << profile.origin() << " " + return os << (profile.record_type() == AutofillProfile::LOCAL_PROFILE + ? profile.guid() + : base::HexEncode(profile.server_id().data(), + profile.server_id().size())) + << " " << profile.origin() << " " << UTF16ToUTF8(profile.GetRawInfo(NAME_FULL)) << " " << UTF16ToUTF8(profile.GetRawInfo(NAME_FIRST)) << " " << UTF16ToUTF8(profile.GetRawInfo(NAME_MIDDLE)) << " " @@ -1122,7 +1142,8 @@ std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) { << profile.language_code() << " " << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)) << " " << profile.GetClientValidityBitfieldValue() << " " - << profile.use_count() << " " << profile.use_date(); + << profile.has_converted() << " " << profile.use_count() << " " + << profile.use_date(); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_profile.h b/chromium/components/autofill/core/browser/autofill_profile.h index 0a60b08a863..3d051f90202 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.h +++ b/chromium/components/autofill/core/browser/autofill_profile.h @@ -77,6 +77,9 @@ class AutofillProfile : public AutofillDataModel { // AutofillDataModel: AutofillMetadata GetMetadata() const override; bool SetMetadata(const AutofillMetadata metadata) override; + // Returns whether the profile is deletable: if it is not verified and has not + // been used for longer than |kDisusedAddressDeletionTimeDelta|. + bool IsDeletable() const override; // FormGroup: void GetMatchingTypes(const base::string16& text, @@ -123,6 +126,11 @@ class AutofillProfile : public AutofillDataModel { // differences in usage stats. bool EqualsForSyncPurposes(const AutofillProfile& profile) const; + bool EqualsForUpdatePurposes(const AutofillProfile& profile) const; + + // Compares the values of kSupportedTypesByClientForValidation fields. + bool EqualsForClientValidationPurpose(const AutofillProfile& profile) const; + // Same as operator==, but cares about differences in usage stats. bool EqualsIncludingUsageStatsForTesting( const AutofillProfile& profile) const; diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc index 5da52384aaa..2a045233d55 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc @@ -11,7 +11,6 @@ #include "base/format_macros.h" #include "base/guid.h" -#include "base/macros.h" #include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h" @@ -20,6 +19,7 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/form_field_data.h" #include "testing/gtest/include/gtest/gtest.h" @@ -289,7 +289,7 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_CH) { }; std::vector<base::string16> labels; - for (size_t i = 0; i < arraysize(kExpectedLabels); ++i) { + for (size_t i = 0; i < base::size(kExpectedLabels); ++i) { AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles), nullptr, UNKNOWN_TYPE, i, "en-US", &labels); ASSERT_FALSE(labels.empty()); @@ -328,7 +328,7 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_FR) { }; std::vector<base::string16> labels; - for (size_t i = 0; i < arraysize(kExpectedLabels); ++i) { + for (size_t i = 0; i < base::size(kExpectedLabels); ++i) { AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles), nullptr, UNKNOWN_TYPE, i, "en-US", &labels); ASSERT_FALSE(labels.empty()); @@ -372,7 +372,7 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_KR) { }; std::vector<base::string16> labels; - for (size_t i = 0; i < arraysize(kExpectedLabels); ++i) { + for (size_t i = 0; i < base::size(kExpectedLabels); ++i) { AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles), nullptr, UNKNOWN_TYPE, i, "en-US", &labels); ASSERT_FALSE(labels.empty()); @@ -409,7 +409,7 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_Latn) { }; std::vector<base::string16> labels; - for (size_t i = 0; i < arraysize(kExpectedLabels); ++i) { + for (size_t i = 0; i < base::size(kExpectedLabels); ++i) { AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles), nullptr, UNKNOWN_TYPE, i, "en-US", &labels); ASSERT_FALSE(labels.empty()); @@ -442,7 +442,7 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_ja) { }; std::vector<base::string16> labels; - for (size_t i = 0; i < arraysize(kExpectedLabels); ++i) { + for (size_t i = 0; i < base::size(kExpectedLabels); ++i) { AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles), nullptr, UNKNOWN_TYPE, i, "en-US", &labels); ASSERT_FALSE(labels.empty()); @@ -1792,4 +1792,47 @@ TEST(AutofillProfileTest, SetMetadata_NotMatchingId) { EXPECT_NE(server_metadata.use_date, server_profile.use_date()); } +// Tests that the profile is only deletable if it is not verified. +TEST(AutofillProfileTest, IsDeletable) { + // Set up an arbitrary time, as setup the current time to just above the + // threshold later than that time. + const base::Time kArbitraryTime = base::Time::FromDoubleT(25000000000); + TestAutofillClock test_clock; + test_clock.SetNow(kArbitraryTime + kDisusedDataModelDeletionTimeDelta + + base::TimeDelta::FromDays(1)); + + // Created a profile that has not been used since over the deletion threshold. + AutofillProfile profile = test::GetFullProfile(); + profile.set_use_date(kArbitraryTime); + + // Make sure it's deletable. + EXPECT_TRUE(profile.IsDeletable()); + + // Set the profile as being verified. + profile.set_origin("Not empty"); + ASSERT_TRUE(profile.IsVerified()); + + // Make sure it's not deletable. + EXPECT_FALSE(profile.IsDeletable()); +} + +// Tests that the two profiles can be compared for validation purposes. +TEST(AutofillProfileTest, EqualsForClientValidationPurpose) { + AutofillProfile profile = test::GetFullProfile(); + + AutofillProfile profile2(profile); + profile2.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("different@email.com")); + + AutofillProfile profile3(profile); + profile3.SetRawInfo(NAME_FULL, base::ASCIIToUTF16("Alice Munro")); + + // For client validation purposes, + // profile2 != profile, because they differ in the email, which is validated + // by the client. + // profile3 == profile, because they only differ in name, and name is not + // validated by the client. + EXPECT_FALSE(profile.EqualsForClientValidationPurpose(profile2)); + EXPECT_TRUE(profile.EqualsForClientValidationPurpose(profile3)); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.cc b/chromium/components/autofill/core/browser/autofill_profile_validator.cc index 6616bb002f0..35d0a46aa30 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_validator.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_validator.cc @@ -43,8 +43,9 @@ AutofillProfileValidator::ValidationRequest::ValidationRequest( validator_(validator), on_validated_(std::move(on_validated)), has_responded_(false), - on_timeout_(base::Bind(&ValidationRequest::OnRulesLoaded, - base::Unretained(this))) { + weak_factory_(this) { + on_timeout_.Reset(base::BindOnce(&ValidationRequest::OnRulesLoaded, + weak_factory_.GetWeakPtr())); DCHECK(profile_); base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, on_timeout_.callback(), diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.h b/chromium/components/autofill/core/browser/autofill_profile_validator.h index cf562b2749b..52d88a8d677 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_validator.h +++ b/chromium/components/autofill/core/browser/autofill_profile_validator.h @@ -68,8 +68,8 @@ class AutofillProfileValidator : public autofill::LoadRulesListener { AutofillProfileValidatorCallback on_validated_; bool has_responded_ = false; - base::CancelableCallback<void()> on_timeout_; - + base::CancelableOnceCallback<void()> on_timeout_; + base::WeakPtrFactory<ValidationRequest> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ValidationRequest); }; diff --git a/chromium/components/autofill/core/browser/autofill_provider.h b/chromium/components/autofill/core/browser/autofill_provider.h index 359c3b62995..ada8e1d0c32 100644 --- a/chromium/components/autofill/core/browser/autofill_provider.h +++ b/chromium/components/autofill/core/browser/autofill_provider.h @@ -50,8 +50,7 @@ class AutofillProvider { virtual void OnFormSubmitted(AutofillHandlerProxy* handler, const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) = 0; + SubmissionSource source) = 0; virtual void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) = 0; diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc index dc5766a8cba..f46ca53cf0c 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc @@ -11,7 +11,6 @@ #include "base/values.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/legacy_strike_database.h" #include "components/autofill/core/browser/legal_message_line.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" @@ -32,30 +31,28 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( bool should_request_name_from_user, const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, - LegacyStrikeDatabase* strike_database, - AutofillClient::UserAcceptedUploadCallback upload_save_card_callback, - base::OnceClosure local_save_card_callback, - PrefService* pref_service) + AutofillClient::UploadSaveCardPromptCallback + upload_save_card_prompt_callback, + AutofillClient::LocalSaveCardPromptCallback local_save_card_prompt_callback, + PrefService* pref_service, + bool is_off_the_record) : ConfirmInfoBarDelegate(), upload_(upload), should_request_name_from_user_(should_request_name_from_user), - upload_save_card_callback_(std::move(upload_save_card_callback)), - local_save_card_callback_(std::move(local_save_card_callback)), + upload_save_card_prompt_callback_( + std::move(upload_save_card_prompt_callback)), + local_save_card_prompt_callback_( + std::move(local_save_card_prompt_callback)), pref_service_(pref_service), - legacy_strike_database_(strike_database), had_user_interaction_(false), issuer_icon_id_(CreditCard::IconResourceId(card.network())), card_label_(card.NetworkAndLastFourDigits()), card_sub_label_(card.AbbreviatedExpirationDateForDisplay( !features::IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled())), - card_last_four_digits_(card.LastFourDigits()) { - if (upload) { - DCHECK(!upload_save_card_callback_.is_null()); - DCHECK(local_save_card_callback_.is_null()); - } else { - DCHECK(upload_save_card_callback_.is_null()); - DCHECK(!local_save_card_callback_.is_null()); - } + card_last_four_digits_(card.LastFourDigits()), + is_off_the_record_(is_off_the_record) { + DCHECK_EQ(upload, !upload_save_card_prompt_callback_.is_null()); + DCHECK_EQ(upload, local_save_card_prompt_callback_.is_null()); if (legal_message) { if (!LegalMessageLine::Parse(*legal_message, &legal_messages_, @@ -78,16 +75,8 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( AutofillSaveCardInfoBarDelegateMobile:: ~AutofillSaveCardInfoBarDelegateMobile() { if (!had_user_interaction_) { + RunSaveCardPromptCallbackWithUserDecision(AutofillClient::IGNORED); LogUserAction(AutofillMetrics::INFOBAR_IGNORED); - if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem)) { - // If the infobar was ignored, count that as a strike against offering - // save in the future. - legacy_strike_database_->AddStrike( - legacy_strike_database_->GetKeyForCreditCardSave( - base::UTF16ToUTF8(card_last_four_digits_)), - base::DoNothing()); - } } } @@ -103,9 +92,7 @@ bool AutofillSaveCardInfoBarDelegateMobile::LegalMessagesParsedSuccessfully() { } bool AutofillSaveCardInfoBarDelegateMobile::IsGooglePayBrandingEnabled() const { - return upload_ && - base::FeatureList::IsEnabled( - features::kAutofillUpstreamUseGooglePayBrandingOnMobile); + return upload_; } base::string16 AutofillSaveCardInfoBarDelegateMobile::GetDescriptionText() @@ -116,7 +103,7 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetDescriptionText() return base::string16(); bool offer_to_save_on_device_message = - OfferStoreUnmaskedCards() && + OfferStoreUnmaskedCards(is_off_the_record_) && !IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled(); return l10n_util::GetStringUTF16( offer_to_save_on_device_message @@ -151,16 +138,8 @@ bool AutofillSaveCardInfoBarDelegateMobile::ShouldExpire( } void AutofillSaveCardInfoBarDelegateMobile::InfoBarDismissed() { + RunSaveCardPromptCallbackWithUserDecision(AutofillClient::DECLINED); LogUserAction(AutofillMetrics::INFOBAR_DENIED); - if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem)) { - // If the infobar was explicitly denied, count that as a strike against - // offering save in the future. - legacy_strike_database_->AddStrike( - legacy_strike_database_->GetKeyForCreditCardSave( - base::UTF16ToUTF8(card_last_four_digits_)), - base::DoNothing()); - } } int AutofillSaveCardInfoBarDelegateMobile::GetButtons() const { @@ -175,20 +154,25 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetButtonLabel( } return should_request_name_from_user_ - ? l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_NEXT) + ? l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_CONTINUE) : l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT); } bool AutofillSaveCardInfoBarDelegateMobile::Accept() { - if (upload_) - std::move(upload_save_card_callback_).Run({}); - else - std::move(local_save_card_callback_).Run(); - + RunSaveCardPromptCallbackWithUserDecision(AutofillClient::ACCEPTED); LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED); return true; } +void AutofillSaveCardInfoBarDelegateMobile:: + RunSaveCardPromptCallbackWithUserDecision( + AutofillClient::SaveCardOfferUserDecision user_decision) { + if (upload_) + std::move(upload_save_card_prompt_callback_).Run(user_decision, {}); + else + std::move(local_save_card_prompt_callback_).Run(user_decision); +} + void AutofillSaveCardInfoBarDelegateMobile::LogUserAction( AutofillMetrics::InfoBarMetric user_action) { DCHECK(!had_user_interaction_); diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h index 9b2af4c7cf1..ed98a20297b 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h @@ -24,7 +24,6 @@ class DictionaryValue; namespace autofill { class CreditCard; -class LegacyStrikeDatabase; // An InfoBarDelegate that enables the user to allow or deny storing credit // card information gathered from a form submission. Only used on mobile. @@ -35,10 +34,12 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { bool should_request_name_from_user, const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, - LegacyStrikeDatabase* legacy_strike_database, - AutofillClient::UserAcceptedUploadCallback upload_save_card_callback, - base::OnceClosure local_save_card_callback, - PrefService* pref_service); + AutofillClient::UploadSaveCardPromptCallback + upload_save_card_prompt_callback, + AutofillClient::LocalSaveCardPromptCallback + local_save_card_prompt_callback, + PrefService* pref_service, + bool is_off_the_record); ~AutofillSaveCardInfoBarDelegateMobile() override; @@ -73,6 +74,11 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { bool Accept() override; private: + // Runs the appropriate local or upload save callback with the given + // |user_decision|. + void RunSaveCardPromptCallbackWithUserDecision( + AutofillClient::SaveCardOfferUserDecision user_decision); + void LogUserAction(AutofillMetrics::InfoBarMetric user_action); // Whether the action is an upload or a local save. @@ -81,20 +87,18 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { // Whether the user should enter/confirm cardholder name. bool should_request_name_from_user_; - // The callback to save the credit card to Google Payments if |upload_| is - // true and the user accepts the infobar. - AutofillClient::UserAcceptedUploadCallback upload_save_card_callback_; + // The callback to run once the user makes a decision with respect to the + // credit card upload offer-to-save prompt (if |upload_| is true). + AutofillClient::UploadSaveCardPromptCallback + upload_save_card_prompt_callback_; - // The callback to save the credit card locally to the device if |upload_| is - // false and the user accepts the infobar. - base::OnceClosure local_save_card_callback_; + // The callback to run once the user makes a decision with respect to the + // local credit card offer-to-save prompt (if |upload_| is false). + AutofillClient::LocalSaveCardPromptCallback local_save_card_prompt_callback_; // Weak reference to read & write |kAutofillAcceptSaveCreditCardPromptState|, PrefService* pref_service_; - // Weak reference to the Autofill LegacyStrikeDatabase. - LegacyStrikeDatabase* legacy_strike_database_; - // Did the user ever explicitly accept or dismiss this infobar? bool had_user_interaction_; @@ -113,6 +117,9 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { // The legal messages to show in the content of the infobar. LegalMessageLines legal_messages_; + // Whether the save is offered while off the record + bool is_off_the_record_; + DISALLOW_COPY_AND_ASSIGN(AutofillSaveCardInfoBarDelegateMobile); }; diff --git a/chromium/components/autofill/core/browser/autofill_subject.cc b/chromium/components/autofill/core/browser/autofill_subject.cc new file mode 100644 index 00000000000..d67961074fb --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_subject.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2019 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 "components/autofill/core/browser/autofill_subject.h" + +#include <vector> + +#include "base/callback_forward.h" +#include "base/observer_list.h" +#include "components/autofill/core/browser/autofill_observer.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; + +namespace autofill { + +AutofillSubject::AutofillSubject() = default; +AutofillSubject::~AutofillSubject() = default; + +void AutofillSubject::Attach(AutofillObserver* observer) { + observers_map_[observer->notification_type()].AddObserver(observer); +} + +void AutofillSubject::Detach(AutofillObserver* observer) { + auto it = observers_map_.find(observer->notification_type()); + if (it == observers_map_.end()) { + return; + } + it->second.RemoveObserver(observer); +} + +void AutofillSubject::Notify(NotificationType notification_type) { + auto it = observers_map_.find(notification_type); + if (it == observers_map_.end()) { + return; + } + + std::vector<AutofillObserver*> observers_to_remove; + for (AutofillObserver& observer : it->second) { + if (notification_type == observer.notification_type()) { + observer.OnNotify(); + + if (observer.detach_on_notify()) { + observers_to_remove.push_back(&observer); + } + } + } + + for (AutofillObserver* observer : observers_to_remove) { + it->second.RemoveObserver(observer); + } +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_subject.h b/chromium/components/autofill/core/browser/autofill_subject.h new file mode 100644 index 00000000000..2e4f222fa59 --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_subject.h @@ -0,0 +1,38 @@ +// Copyright 2019 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SUBJECT_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SUBJECT_H_ + +#include <map> + +#include "base/observer_list.h" +#include "components/autofill/core/browser/autofill_observer.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; + +namespace autofill { + +// Subject that can emit notifications of specific types to observers that were +// opted-in. +class AutofillSubject { + public: + AutofillSubject(); + ~AutofillSubject(); + + void Attach(AutofillObserver* observer); + void Detach(AutofillObserver* observer); + + // Will notify observers that are watching for the same |notification_type|. + // This function is O(n^2) in case all observers are auto-detaching. + void Notify(NotificationType notification_type); + + private: + std::map<NotificationType, base::ObserverList<AutofillObserver>> + observers_map_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SUBJECT_H_ diff --git a/chromium/components/autofill/core/browser/autofill_subject_unittest.cc b/chromium/components/autofill/core/browser/autofill_subject_unittest.cc new file mode 100644 index 00000000000..f1c8eca786c --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_subject_unittest.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2019 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 "components/autofill/core/browser/autofill_subject.h" + +#include "components/autofill/core/browser/autofill_observer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; + +namespace autofill { + +namespace { + +class TestAutofillObserver : public AutofillObserver { + public: + TestAutofillObserver(NotificationType notification_type, + bool detach_on_notify) + : AutofillObserver(notification_type, detach_on_notify) {} + + void OnNotify() override { was_notified_ = true; } + + void Reset() { was_notified_ = false; } + + bool IsActive() { return IsInObserverList(); } + + bool was_notified() { return was_notified_; } + + private: + bool was_notified_ = false; +}; + +} // namespace + +class AutofillSubjectTest : public testing::Test { + public: + AutofillSubjectTest() : subject_() {} + + protected: + AutofillSubject subject_; +}; + +// Tests that a basic notification works. +TEST_F(AutofillSubjectTest, Simple_Notification_NoAutoDetach) { + TestAutofillObserver observer(NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/false); + + subject_.Attach(&observer); + + EXPECT_TRUE(observer.IsActive()); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_TRUE(observer.was_notified()); + + // Still active. + EXPECT_TRUE(observer.IsActive()); + + subject_.Detach(&observer); + + observer.Reset(); + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_FALSE(observer.was_notified()); + EXPECT_FALSE(observer.IsActive()); +} + +// Tests that a basic notification with auto-detach works. +TEST_F(AutofillSubjectTest, Simple_Notification_WithAutoDetach) { + TestAutofillObserver observer(NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/true); + + subject_.Attach(&observer); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_TRUE(observer.was_notified()); + EXPECT_FALSE(observer.IsActive()); + + observer.Reset(); + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_FALSE(observer.was_notified()); + EXPECT_FALSE(observer.IsActive()); +} + +// Tests that NotificationType properly isolates notifications. +TEST_F(AutofillSubjectTest, MultipleObservers_SimpleNotification) { + TestAutofillObserver submit_observer( + NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/false); + TestAutofillObserver cleanup_observer( + NotificationType::AutocompleteCleanupDone, + /*detach_on_notify=*/false); + + subject_.Attach(&submit_observer); + subject_.Attach(&cleanup_observer); + + subject_.Notify(NotificationType::AutocompleteCleanupDone); + + EXPECT_FALSE(submit_observer.was_notified()); + EXPECT_TRUE(cleanup_observer.was_notified()); +} + +// Tests that auto-detach doesn't detach all observers. +TEST_F(AutofillSubjectTest, + MultipleObservers_SimpleNotification_OneAutoDetach) { + TestAutofillObserver detach_submit_observer( + NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/true); + TestAutofillObserver stay_submit_observer( + NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/false); + + subject_.Attach(&detach_submit_observer); + subject_.Attach(&stay_submit_observer); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_TRUE(detach_submit_observer.was_notified()); + EXPECT_TRUE(stay_submit_observer.was_notified()); + + EXPECT_FALSE(detach_submit_observer.IsActive()); + EXPECT_TRUE(stay_submit_observer.IsActive()); + + detach_submit_observer.Reset(); + stay_submit_observer.Reset(); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_FALSE(detach_submit_observer.was_notified()); + EXPECT_TRUE(stay_submit_observer.was_notified()); + + EXPECT_FALSE(detach_submit_observer.IsActive()); + EXPECT_TRUE(stay_submit_observer.IsActive()); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc index 6be48ef3369..9126d95ec29 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.cc +++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc @@ -113,7 +113,8 @@ void CreateTestAddressFormData(FormData* form, const char* unique_id) { form->name = ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); - form->button_title = ASCIIToUTF16("Submit"); + form->button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; form->origin = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); form->main_frame_origin = @@ -714,15 +715,20 @@ std::string ObfuscatedCardDigitsAsUTF8(const std::string& str) { internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16(str))); } +std::string LastYear() { + base::Time::Exploded now; + base::Time::Now().LocalExplode(&now); + return std::to_string(now.year - 1); +} std::string NextYear() { base::Time::Exploded now; base::Time::Now().LocalExplode(&now); return std::to_string(now.year + 1); } -std::string LastYear() { +std::string TenYearsFromNow() { base::Time::Exploded now; base::Time::Now().LocalExplode(&now); - return std::to_string(now.year - 1); + return std::to_string(now.year + 10); } } // namespace test diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h index 2e7aebdac03..b67a11c3655 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.h +++ b/chromium/components/autofill/core/browser/autofill_test_utils.h @@ -260,8 +260,9 @@ void GenerateTestAutofillPopup( std::string ObfuscatedCardDigitsAsUTF8(const std::string& str); -std::string NextYear(); std::string LastYear(); +std::string NextYear(); +std::string TenYearsFromNow(); } // namespace test } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc index b4ab4196270..0459e25d4ff 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc +++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc @@ -22,10 +22,12 @@ AutofillWalletDataTypeController::AutofillWalletDataTypeController( syncer::ModelType type, scoped_refptr<base::SingleThreadTaskRunner> db_thread, const base::Closure& dump_stack, + syncer::SyncService* sync_service, syncer::SyncClient* sync_client, const scoped_refptr<autofill::AutofillWebDataService>& web_data_service) : AsyncDirectoryTypeController(type, dump_stack, + sync_service, sync_client, syncer::GROUP_DB, std::move(db_thread)), @@ -34,7 +36,7 @@ AutofillWalletDataTypeController::AutofillWalletDataTypeController( currently_enabled_(IsEnabled()) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || type == syncer::AUTOFILL_WALLET_METADATA); - pref_registrar_.Init(sync_client_->GetPrefService()); + pref_registrar_.Init(sync_client->GetPrefService()); pref_registrar_.Add( autofill::prefs::kAutofillWalletImportEnabled, base::BindRepeating(&AutofillWalletDataTypeController::OnUserPrefChanged, @@ -85,16 +87,16 @@ void AutofillWalletDataTypeController::StopModels() { // cards and addresses copied from the server. This is different than other // sync cases since this type of data reflects what's on the server rather // than syncing local data between clients, so this extra step is required. - syncer::SyncService* service = sync_client_->GetSyncService(); // CanSyncFeatureStart indicates if sync is currently enabled at all. The // preferred data type indicates if wallet sync data is enabled, and // currently_enabled_ indicates if the other prefs are enabled. All of these // have to be enabled to sync wallet data. - if (!service->CanSyncFeatureStart() || - !service->GetPreferredDataTypes().Has(type()) || !currently_enabled_) { + if (!sync_service()->CanSyncFeatureStart() || + !sync_service()->GetPreferredDataTypes().Has(type()) || + !currently_enabled_) { autofill::PersonalDataManager* pdm = - sync_client_->GetPersonalDataManager(); + sync_client()->GetPersonalDataManager(); if (pdm) pdm->ClearAllServerData(); } @@ -117,8 +119,7 @@ void AutofillWalletDataTypeController::OnUserPrefChanged() { if (currently_enabled_) { // The preference was just enabled. Trigger a reconfiguration. This will do // nothing if the type isn't preferred. - syncer::SyncService* sync_service = sync_client_->GetSyncService(); - sync_service->ReenableDatatype(type()); + sync_service()->ReenableDatatype(type()); } else { DisableForPolicy(); } @@ -128,9 +129,9 @@ bool AutofillWalletDataTypeController::IsEnabled() { DCHECK(CalledOnValidThread()); // Require the user-visible pref to be enabled to sync Wallet data/metadata. - return sync_client_->GetPrefService()->GetBoolean( + return sync_client()->GetPrefService()->GetBoolean( autofill::prefs::kAutofillWalletImportEnabled) && - sync_client_->GetPrefService()->GetBoolean( + sync_client()->GetPrefService()->GetBoolean( autofill::prefs::kAutofillCreditCardEnabled); } void AutofillWalletDataTypeController::DisableForPolicy() { diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h index 481968919ce..837d293a4be 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h +++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h @@ -14,6 +14,11 @@ namespace autofill { class AutofillWebDataService; } +namespace syncer { +class SyncClient; +class SyncService; +} // namespace syncer + namespace browser_sync { // Controls syncing of either AUTOFILL_WALLET or AUTOFILL_WALLET_METADATA. @@ -26,6 +31,7 @@ class AutofillWalletDataTypeController syncer::ModelType type, scoped_refptr<base::SingleThreadTaskRunner> db_thread, const base::Closure& dump_stack, + syncer::SyncService* sync_service, syncer::SyncClient* sync_client, const scoped_refptr<autofill::AutofillWebDataService>& web_data_service); ~AutofillWalletDataTypeController() override; diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc index 7ab34935b5a..1d391861d1b 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc @@ -11,9 +11,9 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/scoped_task_environment.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" @@ -25,6 +25,7 @@ #include "components/sync/driver/data_type_controller_mock.h" #include "components/sync/driver/fake_generic_change_processor.h" #include "components/sync/driver/fake_sync_client.h" +#include "components/sync/driver/fake_sync_service.h" #include "components/sync/driver/sync_api_component_factory_mock.h" #include "components/sync/driver/sync_service.h" #include "components/sync/model/fake_syncable_service.h" @@ -94,7 +95,7 @@ class AutofillWalletDataTypeControllerTest : public testing::Test, base::ThreadTaskRunnerHandle::Get()); autofill_wallet_dtc_ = std::make_unique<AutofillWalletDataTypeController>( syncer::AUTOFILL_WALLET_DATA, base::ThreadTaskRunnerHandle::Get(), - base::DoNothing(), this, web_data_service_); + base::DoNothing(), &sync_service_, this, web_data_service_); last_type_ = syncer::UNSPECIFIED; last_error_ = syncer::SyncError(); @@ -142,8 +143,9 @@ class AutofillWalletDataTypeControllerTest : public testing::Test, last_error_ = error; } - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; TestingPrefServiceSimple prefs_; + syncer::FakeSyncService sync_service_; syncer::StartCallbackMock start_callback_; syncer::SyncApiComponentFactoryMock profile_sync_factory_; syncer::FakeSyncableService syncable_service_; diff --git a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.cc b/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.cc index e0428315739..e725f1e87c9 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.cc +++ b/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.cc @@ -10,7 +10,6 @@ #include "base/bind_helpers.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" -#include "components/sync/driver/sync_client.h" #include "components/sync/driver/sync_service.h" namespace browser_sync { @@ -18,9 +17,11 @@ namespace browser_sync { AutofillWalletModelTypeController::AutofillWalletModelTypeController( syncer::ModelType type, std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, - syncer::SyncClient* sync_client) + PrefService* pref_service, + syncer::SyncService* sync_service) : ModelTypeController(type, std::move(delegate_on_disk)), - sync_client_(sync_client) { + pref_service_(pref_service), + sync_service_(sync_service) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || type == syncer::AUTOFILL_WALLET_METADATA); currently_enabled_ = IsEnabled(); @@ -31,11 +32,13 @@ AutofillWalletModelTypeController::AutofillWalletModelTypeController( syncer::ModelType type, std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_in_memory, - syncer::SyncClient* sync_client) + PrefService* pref_service, + syncer::SyncService* sync_service) : ModelTypeController(type, std::move(delegate_on_disk), std::move(delegate_in_memory)), - sync_client_(sync_client) { + pref_service_(pref_service), + sync_service_(sync_service) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || type == syncer::AUTOFILL_WALLET_METADATA); currently_enabled_ = IsEnabled(); @@ -56,24 +59,22 @@ void AutofillWalletModelTypeController::OnUserPrefChanged() { if (currently_enabled_ == newly_enabled) { return; // No change to sync state. } - currently_enabled_ = newly_enabled; - syncer::SyncService* sync_service = sync_client_->GetSyncService(); - sync_service->ReadyForStartChanged(type()); + currently_enabled_ = newly_enabled; + sync_service_->ReadyForStartChanged(type()); } bool AutofillWalletModelTypeController::IsEnabled() const { DCHECK(CalledOnValidThread()); // Require two user-visible prefs to be enabled to sync Wallet data/metadata. - return sync_client_->GetPrefService()->GetBoolean( + return pref_service_->GetBoolean( autofill::prefs::kAutofillWalletImportEnabled) && - sync_client_->GetPrefService()->GetBoolean( - autofill::prefs::kAutofillCreditCardEnabled); + pref_service_->GetBoolean(autofill::prefs::kAutofillCreditCardEnabled); } void AutofillWalletModelTypeController::SubscribeToPrefChanges() { - pref_registrar_.Init(sync_client_->GetPrefService()); + pref_registrar_.Init(pref_service_); pref_registrar_.Add( autofill::prefs::kAutofillWalletImportEnabled, base::BindRepeating(&AutofillWalletModelTypeController::OnUserPrefChanged, diff --git a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.h b/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.h index 5d0feacd9e5..1f9fcb50815 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.h +++ b/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.h @@ -12,8 +12,10 @@ #include "components/prefs/pref_change_registrar.h" #include "components/sync/driver/model_type_controller.h" +class PrefService; + namespace syncer { -class SyncClient; +class SyncService; } namespace browser_sync { @@ -26,12 +28,14 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController { AutofillWalletModelTypeController( syncer::ModelType type, std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, - syncer::SyncClient* sync_client); + PrefService* pref_service, + syncer::SyncService* sync_service); AutofillWalletModelTypeController( syncer::ModelType type, std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_in_memory, - syncer::SyncClient* sync_client); + PrefService* pref_service, + syncer::SyncService* sync_service); ~AutofillWalletModelTypeController() override; // DataTypeController overrides. @@ -44,7 +48,8 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController { bool IsEnabled() const; void SubscribeToPrefChanges(); - syncer::SyncClient* const sync_client_; + PrefService* const pref_service_; + syncer::SyncService* const sync_service_; PrefChangeRegistrar pref_registrar_; diff --git a/chromium/components/autofill/core/browser/country_data.cc b/chromium/components/autofill/core/browser/country_data.cc index 90401b09aa4..a0c4e6a7a8f 100644 --- a/chromium/components/autofill/core/browser/country_data.cc +++ b/chromium/components/autofill/core/browser/country_data.cc @@ -7,6 +7,7 @@ #include <utility> #include "base/memory/singleton.h" +#include "base/stl_util.h" #include "components/strings/grit/components_strings.h" #include "third_party/icu/source/common/unicode/locid.h" @@ -782,7 +783,7 @@ const StaticCountryData kCountryData[] = { // based on |kCountryData|. std::vector<std::string> GetCountryCodes() { std::vector<std::string> country_codes; - country_codes.reserve(arraysize(kCountryData)); + country_codes.reserve(base::size(kCountryData)); for (const auto& static_data : kCountryData) { country_codes.push_back(static_data.country_code); } diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc index aa254d955cb..139dca405e1 100644 --- a/chromium/components/autofill/core/browser/credit_card.cc +++ b/chromium/components/autofill/core/browser/credit_card.cc @@ -332,6 +332,11 @@ bool CreditCard::SetMetadata(const AutofillMetadata metadata) { return true; } +bool CreditCard::IsDeletable() const { + return AutofillDataModel::IsDeletable() && + IsExpired(AutofillClock::Now() - kDisusedDataModelDeletionTimeDelta); +} + base::string16 CreditCard::GetRawInfo(ServerFieldType type) const { DCHECK_EQ(CREDIT_CARD, AutofillType(type).group()); switch (type) { @@ -587,8 +592,7 @@ int CreditCard::Compare(const CreditCard& credit_card) const { // The following CreditCard field types are the only types we store in the // WebDB so far, so we're only concerned with matching these types in the // credit card. - const ServerFieldType types[] = {CREDIT_CARD_NAME_FULL, CREDIT_CARD_NUMBER, - CREDIT_CARD_EXP_MONTH, + const ServerFieldType types[] = {CREDIT_CARD_NAME_FULL, CREDIT_CARD_EXP_MONTH, CREDIT_CARD_EXP_4_DIGIT_YEAR}; for (ServerFieldType type : types) { int comparison = GetRawInfo(type).compare(credit_card.GetRawInfo(type)); @@ -596,6 +600,10 @@ int CreditCard::Compare(const CreditCard& credit_card) const { return comparison; } + if (!HasSameNumberAs(credit_card)) { + return number().compare(credit_card.number()); + } + int comparison = server_id_.compare(credit_card.server_id_); if (comparison != 0) return comparison; @@ -614,11 +622,13 @@ int CreditCard::Compare(const CreditCard& credit_card) const { if (static_cast<int>(server_status_) > static_cast<int>(credit_card.server_status_)) return 1; - if (static_cast<int>(record_type_) < - static_cast<int>(credit_card.record_type_)) + + // Do not distinguish masked server cards from full server cards as this is + // not needed and not desired - we want to identify masked server card from + // sync with the (potential) full server card stored locally. + if (record_type_ == LOCAL_CARD && credit_card.record_type_ != LOCAL_CARD) return -1; - if (static_cast<int>(record_type_) > - static_cast<int>(credit_card.record_type_)) + if (record_type_ != LOCAL_CARD && credit_card.record_type_ == LOCAL_CARD) return 1; return 0; } @@ -655,8 +665,8 @@ bool CreditCard::HasSameNumberAs(const CreditCard& other) const { } bool CreditCard::operator==(const CreditCard& credit_card) const { - return guid() == credit_card.guid() && - origin() == credit_card.origin() && + return guid() == credit_card.guid() && origin() == credit_card.origin() && + record_type() == credit_card.record_type() && Compare(credit_card) == 0; } @@ -1019,7 +1029,11 @@ bool CreditCard::ShouldUpdateExpiration(const base::Time& current_time) const { // So we can compare CreditCards with EXPECT_EQ(). std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) { return os << base::UTF16ToUTF8(credit_card.Label()) << " " - << credit_card.guid() << " " << credit_card.origin() << " " + << (credit_card.record_type() == CreditCard::LOCAL_CARD + ? credit_card.guid() + : base::HexEncode(credit_card.server_id().data(), + credit_card.server_id().size())) + << " " << credit_card.origin() << " " << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME_FULL)) << " " << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE)) @@ -1027,8 +1041,13 @@ std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) { << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER)) << " " << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH)) - << " " << base::UTF16ToUTF8( - credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); + << " " + << base::UTF16ToUTF8( + credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)) + << " " << credit_card.bank_name() << " " + << " " << credit_card.record_type() << " " + << credit_card.use_count() << " " << credit_card.use_date() << " " + << credit_card.billing_address_id(); } void CreditCard::SetNameOnCardFromSeparateParts() { diff --git a/chromium/components/autofill/core/browser/credit_card.h b/chromium/components/autofill/core/browser/credit_card.h index 5c73b863c69..deff6364ddc 100644 --- a/chromium/components/autofill/core/browser/credit_card.h +++ b/chromium/components/autofill/core/browser/credit_card.h @@ -48,8 +48,8 @@ class CreditCard : public AutofillDataModel { // convert to a FULL_SERVER_CARD. MASKED_SERVER_CARD, - // A card from the Wallet server with full information. This card is not - // locally editable. + // A card from the Wallet server with full information store locally. This + // card is not locally editable. FULL_SERVER_CARD, }; @@ -111,6 +111,9 @@ class CreditCard : public AutofillDataModel { // AutofillDataModel: AutofillMetadata GetMetadata() const override; bool SetMetadata(const AutofillMetadata metadata) override; + // Returns whether the card is deletable: if it is expired and has not been + // used for longer than |kDisusedCreditCardDeletionTimeDelta|. + bool IsDeletable() const override; // FormGroup: void GetMatchingTypes(const base::string16& text, @@ -154,7 +157,8 @@ class CreditCard : public AutofillDataModel { // duplicates. The ordering is based on collation order of the textual // contents of the fields. // GUIDs, origins, labels, and unique IDs are not compared, only the values of - // the cards themselves. + // the cards themselves. A full card is equivalent to its corresponding masked + // card. int Compare(const CreditCard& credit_card) const; // Determines if |this| is a local version of the server card |other|. diff --git a/chromium/components/autofill/core/browser/credit_card_field.cc b/chromium/components/autofill/core/browser/credit_card_field.cc index a0c484b8dd9..fb1f8bf9914 100644 --- a/chromium/components/autofill/core/browser/credit_card_field.cc +++ b/chromium/components/autofill/core/browser/credit_card_field.cc @@ -85,8 +85,7 @@ std::unique_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner) { if (scanner->IsEnd()) return nullptr; - // Using 'new' to access private constructor. - auto credit_card_field = base::WrapUnique(new CreditCardField()); + auto credit_card_field = std::make_unique<CreditCardField>(); size_t saved_cursor = scanner->SaveCursor(); int nb_unknown_fields = 0; diff --git a/chromium/components/autofill/core/browser/credit_card_field.h b/chromium/components/autofill/core/browser/credit_card_field.h index 3d462507fb7..b1bbbe022d1 100644 --- a/chromium/components/autofill/core/browser/credit_card_field.h +++ b/chromium/components/autofill/core/browser/credit_card_field.h @@ -20,6 +20,7 @@ class AutofillScanner; class CreditCardField : public FormField { public: + CreditCardField(); ~CreditCardField() override; static std::unique_ptr<FormField> Parse(AutofillScanner* scanner); @@ -48,8 +49,6 @@ class CreditCardField : public FormField { // a credit card. static bool IsGiftCardField(AutofillScanner* scanner); - CreditCardField(); - // Parses the expiration month/year/date fields. Returns true if it finds // something new. bool ParseExpirationDate(AutofillScanner* scanner); diff --git a/chromium/components/autofill/core/browser/credit_card_field_unittest.cc b/chromium/components/autofill/core/browser/credit_card_field_unittest.cc index 8cc36860260..f701a390212 100644 --- a/chromium/components/autofill/core/browser/credit_card_field_unittest.cc +++ b/chromium/components/autofill/core/browser/credit_card_field_unittest.cc @@ -34,7 +34,8 @@ class CreditCardFieldTestBase { void Parse() { AutofillScanner scanner(list_); std::unique_ptr<FormField> field = CreditCardField::Parse(&scanner); - field_ = base::WrapUnique(static_cast<CreditCardField*>(field.release())); + field_ = std::unique_ptr<CreditCardField>( + static_cast<CreditCardField*>(field.release())); } void MultipleParses() { @@ -43,7 +44,8 @@ class CreditCardFieldTestBase { AutofillScanner scanner(list_); while (!scanner.IsEnd()) { field = CreditCardField::Parse(&scanner); - field_ = base::WrapUnique(static_cast<CreditCardField*>(field.release())); + field_ = std::unique_ptr<CreditCardField>( + static_cast<CreditCardField*>(field.release())); if (field_ == nullptr) { scanner.Advance(); } else { diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/credit_card_save_manager.cc index 26ec8b15c7b..cef57c082f9 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_manager.cc @@ -36,6 +36,7 @@ #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/browser/strike_database.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" @@ -82,7 +83,17 @@ CreditCardSaveManager::CreditCardSaveManager( payments_client_(payments_client), app_locale_(app_locale), personal_data_manager_(personal_data_manager), - weak_ptr_factory_(this) {} + weak_ptr_factory_(this) { + // This is to initialize StrikeDatabase is if it hasn't been already, so that + // its cache would be loaded and ready to use when the first CCSM is created. + if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + // Only init when |kAutofillSaveCreditCardUsesStrikeSystemV2| is enabled. If + // flag is off and LegacyStrikeDatabase instead of StrikeDatabase is used, + // this init will cause failure on GetStrikes(). + client_->GetStrikeDatabase(); + } +} CreditCardSaveManager::~CreditCardSaveManager() {} @@ -91,10 +102,14 @@ void CreditCardSaveManager::AttemptToOfferCardLocalSave( local_card_save_candidate_ = card; show_save_prompt_ = base::nullopt; - // Query the Autofill LegacyStrikeDatabase on if we should pop up the + // Query the Autofill StrikeDatabase on if we should pop up the // offer-to-save prompt for this card. if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem)) { + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + OnDidGetStrikesForLocalSave(GetCreditCardSaveStrikeDatabase()->GetStrikes( + base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits()))); + } else if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystem)) { LegacyStrikeDatabase* strike_database = client_->GetLegacyStrikeDatabase(); strike_database->GetStrikes( strike_database->GetKeyForCreditCardSave( @@ -231,11 +246,16 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( app_locale_, base::BindOnce(&CreditCardSaveManager::OnDidGetUploadDetails, weak_ptr_factory_.GetWeakPtr()), - payments::kUploadCardBillableServiceNumber); - // Query the Autofill LegacyStrikeDatabase on if we should pop up the + payments::kUploadCardBillableServiceNumber, + payments::PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW); + // Query the Autofill StrikeDatabase on if we should pop up the // offer-to-save prompt for this card. if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem)) { + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + OnDidGetStrikesForUploadSave(GetCreditCardSaveStrikeDatabase()->GetStrikes( + base::UTF16ToUTF8(upload_request_.card.LastFourDigits()))); + } else if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystem)) { LegacyStrikeDatabase* strike_database = client_->GetLegacyStrikeDatabase(); strike_database->GetStrikes( strike_database->GetKeyForCreditCardSave( @@ -251,12 +271,16 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( } bool CreditCardSaveManager::IsCreditCardUploadEnabled() { +#if defined(OS_IOS) // If observer_for_testing_ is set, assume we are in a browsertest and // credit card upload should be enabled by default. - return observer_for_testing_ || - ::autofill::IsCreditCardUploadEnabled( - client_->GetPrefs(), client_->GetSyncService(), - personal_data_manager_->GetAccountInfoForPaymentsServer().email); + // TODO(crbug.com/859761): Remove dependency from iOS tests on this behavior. + if (observer_for_testing_) + return true; +#endif // defined(OS_IOS) + return ::autofill::IsCreditCardUploadEnabled( + client_->GetPrefs(), client_->GetSyncService(), + personal_data_manager_->GetAccountInfoForPaymentsServer().email); } bool CreditCardSaveManager::IsUploadEnabledForNetwork( @@ -287,7 +311,8 @@ void CreditCardSaveManager::OnDidUploadCard( if (result == AutofillClient::SUCCESS) { // If the upload succeeds and we can store unmasked cards on this OS, we // will keep a copy of the card as a full server card on the device. - if (!server_id.empty() && OfferStoreUnmaskedCards() && + if (!server_id.empty() && + OfferStoreUnmaskedCards(payments_client_->is_off_the_record()) && !IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled()) { upload_request_.card.set_record_type(CreditCard::FULL_SERVER_CARD); upload_request_.card.SetServerStatus(CreditCard::OK); @@ -297,7 +322,17 @@ void CreditCardSaveManager::OnDidUploadCard( personal_data_manager_->AddFullServerCreditCard(upload_request_.card); } if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem)) { + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + // Log how many strikes the card had when it was saved. + LogStrikesPresentWhenCardSaved( + /*is_local=*/false, + GetCreditCardSaveStrikeDatabase()->GetStrikes( + base::UTF16ToUTF8(upload_request_.card.LastFourDigits()))); + // Clear all strikes for this card, in case it is later removed. + GetCreditCardSaveStrikeDatabase()->ClearStrikes( + base::UTF16ToUTF8(upload_request_.card.LastFourDigits())); + } else if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystem)) { LegacyStrikeDatabase* strike_database = client_->GetLegacyStrikeDatabase(); // Log how many strikes the card had when it was saved. @@ -315,22 +350,40 @@ void CreditCardSaveManager::OnDidUploadCard( base::DoNothing()); } } else { - if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem) && - show_save_prompt_.value()) { - // If the upload failed and the bubble was actually shown (NOT just the - // icon), count that as a strike against offering upload in the future. - LegacyStrikeDatabase* strike_database = - client_->GetLegacyStrikeDatabase(); - strike_database->AddStrike( - strike_database->GetKeyForCreditCardSave( - base::UTF16ToUTF8(upload_request_.card.LastFourDigits())), - base::BindRepeating(&CreditCardSaveManager::OnStrikeChangeComplete, - weak_ptr_factory_.GetWeakPtr())); + if (show_save_prompt_.value()) { + if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + // If the upload failed and the bubble was actually shown (NOT just the + // icon), count that as a strike against offering upload in the future. + int nth_strike_added = GetCreditCardSaveStrikeDatabase()->AddStrike( + base::UTF16ToUTF8(upload_request_.card.LastFourDigits())); + // Notify the browsertests that a strike was added. + OnStrikeChangeComplete(nth_strike_added); + } else if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystem)) { + // If the upload failed and the bubble was actually shown (NOT just the + // icon), count that as a strike against offering upload in the future. + LegacyStrikeDatabase* strike_database = + client_->GetLegacyStrikeDatabase(); + strike_database->AddStrike( + strike_database->GetKeyForCreditCardSave( + base::UTF16ToUTF8(upload_request_.card.LastFourDigits())), + base::BindRepeating(&CreditCardSaveManager::OnStrikeChangeComplete, + weak_ptr_factory_.GetWeakPtr())); + } } } } +CreditCardSaveStrikeDatabase* +CreditCardSaveManager::GetCreditCardSaveStrikeDatabase() { + if (strike_database_.get() == nullptr) { + strike_database_ = std::make_unique<CreditCardSaveStrikeDatabase>( + CreditCardSaveStrikeDatabase(client_->GetStrikeDatabase())); + } + return strike_database_.get(); +} + void CreditCardSaveManager::OnDidGetStrikesForLocalSave(const int num_strikes) { show_save_prompt_ = num_strikes < kMaxStrikesToPreventPoppingUpOfferToSavePrompt; @@ -354,14 +407,14 @@ void CreditCardSaveManager::OnDidGetStrikesForUploadSave( void CreditCardSaveManager::OnDidGetUploadDetails( AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) { + std::unique_ptr<base::Value> legal_message) { if (observer_for_testing_) observer_for_testing_->OnReceivedGetUploadDetailsResponse(); if (result == AutofillClient::SUCCESS) { // Do *not* call payments_client_->Prepare() here. We shouldn't send // credentials until the user has explicitly accepted a prompt to upload. upload_request_.context_token = context_token; - legal_message_ = std::move(legal_message); + legal_message_ = base::DictionaryValue::From(std::move(legal_message)); // Only offer upload once both Payments and the Autofill // LegacyStrikeDatabase have returned their decisions. Use presence of @@ -415,7 +468,7 @@ void CreditCardSaveManager::OfferCardLocalSave() { observer_for_testing_->OnOfferLocalSave(); client_->ConfirmSaveCreditCardLocally( local_card_save_candidate_, show_save_prompt_.value(), - base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptLocalSave, + base::BindOnce(&CreditCardSaveManager::OnUserDidDecideOnLocalSave, weak_ptr_factory_.GetWeakPtr())); // Log metrics. @@ -446,7 +499,7 @@ void CreditCardSaveManager::OfferCardUploadSave() { upload_request_.card, std::move(legal_message_), should_request_name_from_user_, should_request_expiration_date_from_user_, show_save_prompt_.value(), - base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptUpload, + base::BindOnce(&CreditCardSaveManager::OnUserDidDecideOnUploadSave, weak_ptr_factory_.GetWeakPtr())); client_->LoadRiskData( base::BindOnce(&CreditCardSaveManager::OnDidGetUploadRiskData, @@ -475,30 +528,51 @@ void CreditCardSaveManager::OfferCardUploadSave() { } } -void CreditCardSaveManager::OnUserDidAcceptLocalSave() { - if (local_card_save_candidate_.HasFirstAndLastName()) - AutofillMetrics::LogSaveCardWithFirstAndLastNameComplete(/*is_local=*/true); +void CreditCardSaveManager::OnUserDidDecideOnLocalSave( + AutofillClient::SaveCardOfferUserDecision user_decision) { + switch (user_decision) { + case AutofillClient::ACCEPTED: + if (local_card_save_candidate_.HasFirstAndLastName()) + AutofillMetrics::LogSaveCardWithFirstAndLastNameComplete( + /*is_local=*/true); + if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + // Log how many strikes the card had when it was saved. + LogStrikesPresentWhenCardSaved( + /*is_local=*/true, + GetCreditCardSaveStrikeDatabase()->GetStrikes(base::UTF16ToUTF8( + local_card_save_candidate_.LastFourDigits()))); + // Clear all strikes for this card, in case it is later removed. + GetCreditCardSaveStrikeDatabase()->ClearStrikes( + base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits())); + } else if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystem)) { + LegacyStrikeDatabase* strike_database = + client_->GetLegacyStrikeDatabase(); + // Log how many strikes the card had when it was saved. + strike_database->GetStrikes( + strike_database->GetKeyForCreditCardSave( + base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits())), + base::BindRepeating( + &CreditCardSaveManager::LogStrikesPresentWhenCardSaved, + weak_ptr_factory_.GetWeakPtr(), + /*is_local=*/true)); + // Clear all strikes for this card, in case it is later removed. + strike_database->ClearAllStrikesForKey( + strike_database->GetKeyForCreditCardSave( + base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits())), + base::DoNothing()); + } - if (base::FeatureList::IsEnabled( - features::kAutofillSaveCreditCardUsesStrikeSystem)) { - LegacyStrikeDatabase* strike_database = client_->GetLegacyStrikeDatabase(); - // Log how many strikes the card had when it was saved. - strike_database->GetStrikes( - strike_database->GetKeyForCreditCardSave( - base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits())), - base::BindRepeating( - &CreditCardSaveManager::LogStrikesPresentWhenCardSaved, - weak_ptr_factory_.GetWeakPtr(), - /*is_local=*/true)); - // Clear all strikes for this card, in case it is later removed. - strike_database->ClearAllStrikesForKey( - strike_database->GetKeyForCreditCardSave( - base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits())), - base::DoNothing()); - } + personal_data_manager_->OnAcceptedLocalCreditCardSave( + local_card_save_candidate_); + break; - personal_data_manager_->OnAcceptedLocalCreditCardSave( - local_card_save_candidate_); + case AutofillClient::DECLINED: + case AutofillClient::IGNORED: + OnUserDidIgnoreOrDeclineSave(local_card_save_candidate_.LastFourDigits()); + break; + } } void CreditCardSaveManager::LogStrikesPresentWhenCardSaved( @@ -739,21 +813,30 @@ int CreditCardSaveManager::GetDetectedValues() const { return detected_values; } -void CreditCardSaveManager::OnUserDidAcceptUpload( +void CreditCardSaveManager::OnUserDidDecideOnUploadSave( + AutofillClient::SaveCardOfferUserDecision user_decision, const AutofillClient::UserProvidedCardDetails& user_provided_card_details) { + switch (user_decision) { + case AutofillClient::ACCEPTED: // On Android, requesting cardholder name is a two step flow. #if defined(OS_ANDROID) - if (should_request_name_from_user_) { - client_->ConfirmAccountNameFixFlow( - base::BindOnce( + if (should_request_name_from_user_) { + client_->ConfirmAccountNameFixFlow(base::BindOnce( &CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow, weak_ptr_factory_.GetWeakPtr())); - } else { - OnUserDidAcceptUploadHelper(user_provided_card_details); - } + } else { + OnUserDidAcceptUploadHelper(user_provided_card_details); + } #else - OnUserDidAcceptUploadHelper(user_provided_card_details); + OnUserDidAcceptUploadHelper(user_provided_card_details); #endif + break; + + case AutofillClient::DECLINED: + case AutofillClient::IGNORED: + OnUserDidIgnoreOrDeclineSave(upload_request_.card.LastFourDigits()); + break; + } personal_data_manager_->OnUserAcceptedUpstreamOffer(); } @@ -828,9 +911,36 @@ void CreditCardSaveManager::SendUploadCardRequest() { weak_ptr_factory_.GetWeakPtr())); } +void CreditCardSaveManager::OnUserDidIgnoreOrDeclineSave( + const base::string16& card_last_four_digits) { + if (show_save_prompt_.value()) { + if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystemV2)) { + // If the user rejected or ignored save and the offer-to-save bubble or + // infobar was actually shown (NOT just the icon if on desktop), count + // that as a strike against offering upload in the future. + int nth_strike_added = GetCreditCardSaveStrikeDatabase()->AddStrike( + base::UTF16ToUTF8(card_last_four_digits)); + OnStrikeChangeComplete(nth_strike_added); + } else if (base::FeatureList::IsEnabled( + features::kAutofillSaveCreditCardUsesStrikeSystem)) { + // If the user rejected or ignored save and the offer-to-save bubble or + // infobar was actually shown (NOT just the icon if on desktop), count + // that as a strike against offering upload in the future. + LegacyStrikeDatabase* strike_database = + client_->GetLegacyStrikeDatabase(); + strike_database->AddStrike( + strike_database->GetKeyForCreditCardSave( + base::UTF16ToUTF8(card_last_four_digits)), + base::BindRepeating(&CreditCardSaveManager::OnStrikeChangeComplete, + weak_ptr_factory_.GetWeakPtr())); + } + } +} + void CreditCardSaveManager::OnStrikeChangeComplete(const int num_strikes) { if (observer_for_testing_) - observer_for_testing_->OnCCSMStrikeChangeComplete(); + observer_for_testing_->OnStrikeChangeComplete(); } AutofillMetrics::CardUploadDecisionMetric diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.h b/chromium/components/autofill/core/browser/credit_card_save_manager.h index e851ae8bfab..a1ae70e31ff 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/credit_card_save_manager.h @@ -16,6 +16,7 @@ #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/credit_card_save_strike_database.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" @@ -81,7 +82,7 @@ class CreditCardSaveManager { virtual void OnReceivedGetUploadDetailsResponse() = 0; virtual void OnSentUploadCardRequest() = 0; virtual void OnReceivedUploadCardResponse() = 0; - virtual void OnCCSMStrikeChangeComplete() = 0; + virtual void OnStrikeChangeComplete() = 0; }; // The parameters should outlive the CreditCardSaveManager. @@ -123,7 +124,11 @@ class CreditCardSaveManager { private: friend class CreditCardSaveManagerTest; friend class CreditCardSaveManagerTestObserverBridge; - friend class SaveCardBubbleViewsBrowserTestBase; + friend class TestCreditCardSaveManager; + friend class SaveCardBubbleViewsFullFormBrowserTest; + + // Returns the CreditCardSaveStrikeDatabase for |client_|. + CreditCardSaveStrikeDatabase* GetCreditCardSaveStrikeDatabase(); // Sets |show_save_prompt| and moves forward with offering credit card local // save. @@ -136,10 +141,9 @@ class CreditCardSaveManager { // Returns the legal message retrieved from Payments. On failure or not // meeting Payments's conditions for upload, |legal_message| will contain // nullptr. - void OnDidGetUploadDetails( - AutofillClient::PaymentsRpcResult result, - const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message); + void OnDidGetUploadDetails(AutofillClient::PaymentsRpcResult result, + const base::string16& context_token, + std::unique_ptr<base::Value> legal_message); // Logs the number of strikes that a card had when save succeeded. void LogStrikesPresentWhenCardSaved(bool is_local, const int num_strikes); @@ -169,18 +173,27 @@ class CreditCardSaveManager { // Autofill StrikeSystem has made its decision. void OfferCardUploadSave(); - // Clears strikes for the to-be-saved card and has |personal_data_manager_| - // save the card. - void OnUserDidAcceptLocalSave(); - - // Sets |user_did_accept_upload_prompt_| and calls SendUploadCardRequest if - // the risk data is available. Sets the cardholder name on the upload request - // if |user_provided_card_details.cardholder_name| is set. Sets the expiration - // date on the upload request if - // |user_provided_card_details.expiration_date_month| and - // |user_provided_card_details.expiration_date_year| are both set. - void OnUserDidAcceptUpload(const AutofillClient::UserProvidedCardDetails& - user_provided_card_details); + // Called once the user makes a decision with respect to the local credit card + // offer-to-save prompt. If accepted, clears strikes for the to-be-saved card + // and has |personal_data_manager_| save the card. + void OnUserDidDecideOnLocalSave( + AutofillClient::SaveCardOfferUserDecision user_decision); + + // Called once the user makes a decision with respect to the credit card + // upload offer-to-save prompt. + // If accepted: + // Sets |user_did_accept_upload_prompt_| and calls SendUploadCardRequest if + // the risk data is available. Sets the cardholder name on the upload + // request if |user_provided_card_details.cardholder_name| is set. Sets the + // expiration date on the upload request if + // |user_provided_card_details.expiration_date_month| and + // |user_provided_card_details.expiration_date_year| are both set. + // If rejected or ignored: + // Logs a strike against the current card to deter future offers to save. + void OnUserDidDecideOnUploadSave( + AutofillClient::SaveCardOfferUserDecision user_decision, + const AutofillClient::UserProvidedCardDetails& + user_provided_card_details); #if defined(OS_ANDROID) // Sets |user_did_accept_upload_prompt_| and calls SendUploadCardRequest if @@ -204,6 +217,12 @@ class CreditCardSaveManager { // Finalizes the upload request and calls PaymentsClient::UploadCard(). void SendUploadCardRequest(); + // Called when the user ignored or declined the credit card save prompt. Logs + // a strike for the given card in order to help deter future offers to save, + // provided that save was actually offered to the user. + void OnUserDidIgnoreOrDeclineSave( + const base::string16& card_last_four_digits); + // Used for browsertests. Gives the |observer_for_testing_| a notification // a strike change has been made. void OnStrikeChangeComplete(const int num_strikes); @@ -289,6 +308,8 @@ class CreditCardSaveManager { // The returned legal message from a GetUploadDetails call to Google Payments. std::unique_ptr<base::DictionaryValue> legal_message_; + std::unique_ptr<CreditCardSaveStrikeDatabase> strike_database_; + // May be null. ObserverForTest* observer_for_testing_ = nullptr; diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc index d8706dba442..ef3e151e073 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc @@ -27,6 +27,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" @@ -34,6 +35,7 @@ #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_manager.h" #include "components/autofill/core/browser/test_credit_card_save_manager.h" +#include "components/autofill/core/browser/test_credit_card_save_strike_database.h" #include "components/autofill/core/browser/test_form_data_importer.h" #include "components/autofill/core/browser/test_legacy_strike_database.h" #include "components/autofill/core/browser/test_personal_data_manager.h" @@ -99,12 +101,17 @@ class MockPersonalDataManager : public TestPersonalDataManager { class CreditCardSaveManagerTest : public testing::Test { public: void SetUp() override { - std::unique_ptr<TestLegacyStrikeDatabase> test_strike_database = + std::unique_ptr<TestLegacyStrikeDatabase> test_legacy_strike_database = std::make_unique<TestLegacyStrikeDatabase>(); - legacy_strike_database_ = test_strike_database.get(); + legacy_strike_database_ = test_legacy_strike_database.get(); autofill_client_.SetPrefs(test::PrefServiceForTesting()); + autofill_client_.set_test_legacy_strike_database( + std::move(test_legacy_strike_database)); + std::unique_ptr<TestStrikeDatabase> test_strike_database = + std::make_unique<TestStrikeDatabase>(); + strike_database_ = test_strike_database.get(); autofill_client_.set_test_strike_database(std::move(test_strike_database)); - personal_data_.Init(/*profile_database=*/autofill_client_.GetDatabase(), + personal_data_.Init(/*profile_database=*/database_, /*account_database=*/nullptr, /*pref_service=*/autofill_client_.GetPrefs(), /*identity_manager=*/nullptr, @@ -113,6 +120,9 @@ class CreditCardSaveManagerTest : public testing::Test { /*cookie_manager_sevice=*/nullptr, /*is_off_the_record=*/false); personal_data_.SetSyncServiceForTest(&sync_service_); + autocomplete_history_manager_.Init( + /*profile_database=*/database_, + /*is_off_the_record=*/false); autofill_driver_.reset(new TestAutofillDriver()); request_context_ = new net::TestURLRequestContextGetter( base::ThreadTaskRunnerHandle::Get()); @@ -133,8 +143,10 @@ class CreditCardSaveManagerTest : public testing::Test { &personal_data_, "en-US"); autofill_client_.set_test_form_data_importer( std::unique_ptr<TestFormDataImporter>(test_form_data_importer)); + autofill_client_.GetStrikeDatabase(); autofill_manager_.reset(new TestAutofillManager( - autofill_driver_.get(), &autofill_client_, &personal_data_)); + autofill_driver_.get(), &autofill_client_, &personal_data_, + &autocomplete_history_manager_)); autofill_manager_->SetExpectedObservedSubmission(true); } @@ -155,14 +167,14 @@ class CreditCardSaveManagerTest : public testing::Test { } void FormSubmitted(const FormData& form) { - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); } void UserHasAcceptedUpload( AutofillClient::UserProvidedCardDetails user_provided_card_details) { - credit_card_save_manager_->OnUserDidAcceptUpload( - user_provided_card_details); + credit_card_save_manager_->OnUserDidDecideOnUploadSave( + AutofillClient::ACCEPTED, user_provided_card_details); } // Populates |form| with data corresponding to a simple credit card form. @@ -322,7 +334,9 @@ class CreditCardSaveManagerTest : public testing::Test { std::unique_ptr<TestAutofillDriver> autofill_driver_; std::unique_ptr<TestAutofillManager> autofill_manager_; scoped_refptr<net::TestURLRequestContextGetter> request_context_; + scoped_refptr<AutofillWebDataService> database_; MockPersonalDataManager personal_data_; + MockAutocompleteHistoryManager autocomplete_history_manager_; syncer::TestSyncService sync_service_; base::test::ScopedFeatureList scoped_feature_list_; // Ends up getting owned (and destroyed) by TestFormDataImporter: @@ -331,6 +345,8 @@ class CreditCardSaveManagerTest : public testing::Test { payments::TestPaymentsClient* payments_client_; // Ends up getting owned (and destroyed) by TestAutofillClient: TestLegacyStrikeDatabase* legacy_strike_database_; + // Ends up getting owned (and destroyed) by TestAutofillClient: + TestStrikeDatabase* strike_database_; private: int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) { @@ -3946,6 +3962,63 @@ TEST_F(CreditCardSaveManagerTest, EXPECT_TRUE(payments_client_->active_experiments_in_request().empty()); } +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_ShouldAddUploadCardBillableServiceNumberInRequest) { + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Confirm that the preflight request contained + // kUploadCardBillableServiceNumber in the request. + FormSubmitted(credit_card_form); + EXPECT_EQ(payments::kUploadCardBillableServiceNumber, + payments_client_->billable_service_number_in_request()); +} + +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_ShouldAddUploadCardSourceInRequest) { + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Confirm that the preflight request contained the correct UploadCardSource. + FormSubmitted(credit_card_form); + EXPECT_EQ(payments::PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW, + payments_client_->upload_card_source_in_request()); +} + TEST_F(CreditCardSaveManagerTest, UploadCreditCard_EloDisallowed) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamDisallowElo); @@ -4200,10 +4273,10 @@ TEST_F(CreditCardSaveManagerTest, "Autofill.StrikeDatabase.StrikesPresentWhenServerCardSaved", 0); } -// Tests that a card with some strikes (but not max strikes) should still show -// the save bubble/infobar. +// Tests that a card with some strikes using LegacyStrikeDatabase (but not max +// strikes) should still show the save bubble/infobar. TEST_F(CreditCardSaveManagerTest, - LocallySaveCreditCard_NotEnoughStrikesStillShowsOfferToSave) { + LocallySaveCreditCard_NotEnoughLegacyStrikesStillShowsOfferToSave) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); credit_card_save_manager_->SetCreditCardUploadEnabled(false); @@ -4241,10 +4314,10 @@ TEST_F(CreditCardSaveManagerTest, "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", 0); } -// Tests that a card with some strikes (but not max strikes) should still show -// the save bubble/infobar. +// Tests that a card with some strikes using LegacyStrikeDatabase (but not max +// strikes) should still show the save bubble/infobar. TEST_F(CreditCardSaveManagerTest, - UploadCreditCard_NotEnoughStrikesStillShowsOfferToSave) { + UploadCreditCard_NotEnoughLegacyStrikesStillShowsOfferToSave) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); @@ -4292,9 +4365,10 @@ TEST_F(CreditCardSaveManagerTest, } #if defined(OS_ANDROID) || defined(OS_IOS) -// Tests that a card with max strikes does not offer save on mobile at all. +// Tests that a card with max strikes using LegacyStrikeDatabase does not offer +// save on mobile at all. TEST_F(CreditCardSaveManagerTest, - LocallySaveCreditCard_MaxStrikesDisallowsSave) { + LocallySaveCreditCard_MaxLegacyStrikesDisallowsSave) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); credit_card_save_manager_->SetCreditCardUploadEnabled(false); @@ -4330,8 +4404,10 @@ TEST_F(CreditCardSaveManagerTest, AutofillMetrics::SaveTypeMetric::LOCAL, 1); } -// Tests that a card with max strikes does not offer save on mobile at all. -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) { +// Tests that a card with max strikes using LegacyStrikeDatabase does not offer +// save on mobile at all. +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_MaxLegacyStrikesDisallowsSave) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); @@ -4383,10 +4459,11 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) { } #else // !defined(OS_ANDROID) && !defined(OS_IOS) -// Tests that a card with max strikes should still offer to save on Desktop via -// the omnibox icon, but that the offer-to-save bubble itself is not shown. +// Tests that a card with max strikes using LegacyStrikeDatabase should still +// offer to save on Desktop via the omnibox icon, but that the offer-to-save +// bubble itself is not shown. TEST_F(CreditCardSaveManagerTest, - LocallySaveCreditCard_MaxStrikesStillAllowsSave) { + LocallySaveCreditCard_MaxLegacyStrikesStillAllowsSave) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); credit_card_save_manager_->SetCreditCardUploadEnabled(false); @@ -4425,9 +4502,11 @@ TEST_F(CreditCardSaveManagerTest, AutofillMetrics::SaveTypeMetric::LOCAL, 1); } -// Tests that a card with max strikes should still offer to save on Desktop via -// the omnibox icon, but that the offer-to-save bubble itself is not shown. -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) { +// Tests that a card with max strikes using LegacyStrikeDatabase should still +// offer to save on Desktop via the omnibox icon, but that the offer-to-save +// bubble itself is not shown. +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_MaxLegacyStrikesStillAllowsSave) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); @@ -4476,8 +4555,10 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) { } #endif -// Tests that adding a card clears all strikes for that card. -TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_ClearStrikesOnAdd) { +// Tests that adding a card clears all LegacyStrikeDatabase strikes for that +// card. +TEST_F(CreditCardSaveManagerTest, + LocallySaveCreditCard_ClearLegacyStrikesOnAdd) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); credit_card_save_manager_->SetCreditCardUploadEnabled(false); @@ -4511,8 +4592,9 @@ TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_ClearStrikesOnAdd) { legacy_strike_database_->GetKeyForCreditCardSave("1111"))); } -// Tests that adding a card clears all strikes for that card. -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) { +// Tests that adding a card clears all LegacyStrikeDatabase strikes for that +// card. +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearLegacyStrikesOnAdd) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); @@ -4555,8 +4637,10 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) { legacy_strike_database_->GetKeyForCreditCardSave("1111"))); } -// Tests that adding a card clears all strikes for that card. -TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_NumStrikesLoggedOnAdd) { +// Tests that adding a card clears all LegacyStrikeDatabase strikes for that +// card. +TEST_F(CreditCardSaveManagerTest, + LocallySaveCreditCard_NumLegacyStrikesLoggedOnAdd) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); credit_card_save_manager_->SetCreditCardUploadEnabled(false); @@ -4593,8 +4677,10 @@ TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_NumStrikesLoggedOnAdd) { /*sample=*/2, /*count=*/1); } -// Tests that adding a card clears all strikes for that card. -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) { +// Tests that adding a card clears all LegacyStrikeDatabase strikes for that +// card. +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_NumLegacyStrikesLoggedOnAdd) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillSaveCreditCardUsesStrikeSystem); @@ -4640,6 +4726,503 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) { /*sample=*/2, /*count=*/1); } +// Tests that one LegacyStrikeDatabase strike is added when upload failed and +// bubble is shown. +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_NumLegacyStrikesLoggedOnUploadNotSuccess) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystem); + const char* const server_id = "InstrumentData:1234"; + payments_client_->SetServerIdForCardUpload(server_id); + EXPECT_EQ(0, legacy_strike_database_->GetStrikesForTesting( + legacy_strike_database_->GetKeyForCreditCardSave("1111"))); + + // If upload failed and the bubble was shown, strike count should increase + // by 1. + credit_card_save_manager_->set_show_save_prompt(true); + credit_card_save_manager_->set_upload_request_card_number( + ASCIIToUTF16("4111111111111111")); + credit_card_save_manager_->OnDidUploadCard(AutofillClient::TRY_AGAIN_FAILURE, + server_id); + EXPECT_EQ(1, legacy_strike_database_->GetStrikesForTesting( + legacy_strike_database_->GetKeyForCreditCardSave("1111"))); +} + +// Tests that a card with some strikes (but not max strikes) should still show +// the save bubble/infobar. +TEST_F(CreditCardSaveManagerTest, + LocallySaveCreditCard_NotEnoughStrikesStillShowsOfferToSave) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Add a single strike for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(1, credit_card_save_strike_database.GetStrikes("1111")); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + FormSubmitted(credit_card_form); + EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that the offer-to-save bubble was still shown because the card did + // not have too many strikes. + EXPECT_TRUE( + autofill_client_.get_offer_to_save_credit_card_bubble_was_shown()); + // Verify that no histogram entry was logged. + histogram_tester.ExpectTotalCount( + "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", 0); +} + +// Tests that a card with some strikes (but not max strikes) should still show +// the save bubble/infobar. +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_NotEnoughStrikesStillShowsOfferToSave) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Add a single strike for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(1, credit_card_save_strike_database.GetStrikes("1111")); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that the offer-to-save bubble was still shown because the card did + // not have too many strikes. + EXPECT_TRUE( + autofill_client_.get_offer_to_save_credit_card_bubble_was_shown()); + // Verify that no histogram entry was logged. + histogram_tester.ExpectTotalCount( + "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", 0); +} + +#if defined(OS_ANDROID) || defined(OS_IOS) +// Tests that a card with max strikes does not offer save on mobile at all. +TEST_F(CreditCardSaveManagerTest, + LocallySaveCreditCard_MaxStrikesDisallowsSave) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Max out strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(3, credit_card_save_strike_database.GetStrikes("1111")); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + // No form of credit card save should be shown. + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that the correct histogram entry was logged. + histogram_tester.ExpectBucketCount( + "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", + AutofillMetrics::SaveTypeMetric::LOCAL, 1); +} + +// Tests that a card with max strikes does not offer save on mobile at all. +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Max out strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(3, credit_card_save_strike_database.GetStrikes("1111")); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + // No form of credit card save should be shown. + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that the correct histogram entries were logged. + ExpectCardUploadDecision( + histogram_tester, + AutofillMetrics::UPLOAD_NOT_OFFERED_MAX_STRIKES_ON_MOBILE); + histogram_tester.ExpectBucketCount( + "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", + AutofillMetrics::SaveTypeMetric::SERVER, 1); + // Verify that the correct UKM was logged. + ExpectCardUploadDecisionUkm( + AutofillMetrics::UPLOAD_NOT_OFFERED_MAX_STRIKES_ON_MOBILE); +} + +#else // !defined(OS_ANDROID) && !defined(OS_IOS) +// Tests that a card with max strikes should still offer to save on Desktop via +// the omnibox icon, but that the offer-to-save bubble itself is not shown. +TEST_F(CreditCardSaveManagerTest, + LocallySaveCreditCard_MaxStrikesStillAllowsSave) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Max out strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(3, credit_card_save_strike_database.GetStrikes("1111")); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + FormSubmitted(credit_card_form); + EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that the offer-to-save bubble was not shown because the card had too + // many strikes. + EXPECT_FALSE( + autofill_client_.get_offer_to_save_credit_card_bubble_was_shown()); + // Verify that the correct histogram entry was logged. + histogram_tester.ExpectBucketCount( + "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", + AutofillMetrics::SaveTypeMetric::LOCAL, 1); +} + +// Tests that a card with max strikes should still offer to save on Desktop via +// the omnibox icon, but that the offer-to-save bubble itself is not shown. +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Max out strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(3, credit_card_save_strike_database.GetStrikes("1111")); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that the offer-to-save bubble was not shown because the card had too + // many strikes. + EXPECT_FALSE( + autofill_client_.get_offer_to_save_credit_card_bubble_was_shown()); + // Verify that the correct histogram entry was logged. + histogram_tester.ExpectBucketCount( + "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", + AutofillMetrics::SaveTypeMetric::SERVER, 1); +} +#endif + +// Tests that adding a card clears all strikes for that card. +TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_ClearStrikesOnAdd) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Add two strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(2, credit_card_save_strike_database.GetStrikes("1111")); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + FormSubmitted(credit_card_form); + EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that adding the card reset the strike count for that card. + EXPECT_EQ(0, credit_card_save_strike_database.GetStrikes("1111")); +} + +// Tests that adding a card clears all strikes for that card. +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Add two strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(2, credit_card_save_strike_database.GetStrikes("1111")); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that adding the card reset the strike count for that card. + EXPECT_EQ(0, credit_card_save_strike_database.GetStrikes("1111")); +} + +// Tests that adding a card clears all strikes for that card. +TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_NumStrikesLoggedOnAdd) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Add two strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(2, credit_card_save_strike_database.GetStrikes("1111")); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + FormSubmitted(credit_card_form); + EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that adding the card logged the number of strikes it had previously. + histogram_tester.ExpectUniqueSample( + "Autofill.StrikeDatabase.StrikesPresentWhenLocalCardSaved", + /*sample=*/2, /*count=*/1); +} + +// Tests that adding a card clears all strikes for that card. +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + + // Add two strikes for the card to be added. + credit_card_save_strike_database.AddStrike("1111"); + credit_card_save_strike_database.AddStrike("1111"); + EXPECT_EQ(2, credit_card_save_strike_database.GetStrikes("1111")); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ExpectUniqueFillableFormParsedUkm(); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that adding the card logged the number of strikes it had previously. + histogram_tester.ExpectUniqueSample( + "Autofill.StrikeDatabase.StrikesPresentWhenServerCardSaved", + /*sample=*/2, /*count=*/1); +} + +// Tests that one strike is added when upload failed and +// bubble is shown. +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_NumStrikesLoggedOnUploadNotSuccess) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillSaveCreditCardUsesStrikeSystemV2); + const char* const server_id = "InstrumentData:1234"; + payments_client_->SetServerIdForCardUpload(server_id); + TestCreditCardSaveStrikeDatabase credit_card_save_strike_database = + TestCreditCardSaveStrikeDatabase(strike_database_); + EXPECT_EQ(0, credit_card_save_strike_database.GetStrikes("1111")); + + // If upload failed and the bubble was shown, strike count should increase + // by 1. + credit_card_save_manager_->set_show_save_prompt(true); + credit_card_save_manager_->set_upload_request_card_number( + ASCIIToUTF16("4111111111111111")); + credit_card_save_manager_->OnDidUploadCard(AutofillClient::TRY_AGAIN_FAILURE, + server_id); + EXPECT_EQ(1, credit_card_save_strike_database.GetStrikes("1111")); +} + // Make sure that the PersonalDataManager gets notified when the user accepts // an upload offer. TEST_F(CreditCardSaveManagerTest, OnUserDidAcceptUpload_NotifiesPDM) { diff --git a/chromium/components/autofill/core/browser/credit_card_save_strike_database.cc b/chromium/components/autofill/core/browser/credit_card_save_strike_database.cc index aca26ba3589..5df822f385e 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_strike_database.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_strike_database.cc @@ -9,8 +9,10 @@ namespace autofill { CreditCardSaveStrikeDatabase::CreditCardSaveStrikeDatabase( - const base::FilePath& database_dir) - : StrikeDatabase(database_dir) {} + StrikeDatabase* strike_database) + : StrikeDatabaseIntegratorBase(strike_database) { + RemoveExpiredStrikes(); +} CreditCardSaveStrikeDatabase::~CreditCardSaveStrikeDatabase() {} @@ -22,4 +24,13 @@ int CreditCardSaveStrikeDatabase::GetMaxStrikesLimit() { return 3; } +long long CreditCardSaveStrikeDatabase::GetExpiryTimeMicros() { + // Expiry time is 6 months. + return (long long)1000000 * 60 * 60 * 24 * 180; +} + +bool CreditCardSaveStrikeDatabase::UniqueIdsRequired() { + return true; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/credit_card_save_strike_database.h b/chromium/components/autofill/core/browser/credit_card_save_strike_database.h index fab05c64d7f..537682256f1 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_strike_database.h +++ b/chromium/components/autofill/core/browser/credit_card_save_strike_database.h @@ -8,18 +8,21 @@ #include <string> #include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/strike_database_integrator_base.h" namespace autofill { -// Implementation of StrikeDatabase for credit card saves (both local and -// upload). -class CreditCardSaveStrikeDatabase : public StrikeDatabase { +// Implementation of StrikeDatabaseIntegratorBase for credit card saves (both +// local and upload). +class CreditCardSaveStrikeDatabase : public StrikeDatabaseIntegratorBase { public: - CreditCardSaveStrikeDatabase(const base::FilePath& database_dir); + CreditCardSaveStrikeDatabase(StrikeDatabase* strike_database); ~CreditCardSaveStrikeDatabase() override; std::string GetProjectPrefix() override; int GetMaxStrikesLimit() override; + long long GetExpiryTimeMicros() override; + bool UniqueIdsRequired() override; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/credit_card_save_strike_database_unittest.cc b/chromium/components/autofill/core/browser/credit_card_save_strike_database_unittest.cc index cad62581f84..6628663394c 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_strike_database_unittest.cc +++ b/chromium/components/autofill/core/browser/credit_card_save_strike_database_unittest.cc @@ -13,14 +13,17 @@ #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" +#include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/test_credit_card_save_strike_database.h" +#include "components/autofill/core/common/autofill_clock.h" #include "testing/gtest/include/gtest/gtest.h" namespace autofill { class CreditCardSaveStrikeDatabaseTest : public ::testing::Test { public: - CreditCardSaveStrikeDatabaseTest() : strike_database_(InitFilePath()) {} + CreditCardSaveStrikeDatabaseTest() + : strike_database_(new StrikeDatabase(InitFilePath())) {} protected: base::HistogramTester* GetHistogramTester() { return &histogram_tester_; } @@ -102,4 +105,34 @@ TEST_F(CreditCardSaveStrikeDatabaseTest, ClearStrikesForZeroStrikesTest) { EXPECT_EQ(0, strike_database_.GetStrikes(last_four)); } +TEST_F(CreditCardSaveStrikeDatabaseTest, RemoveExpiredStrikesTest) { + autofill::TestAutofillClock test_clock; + test_clock.SetNow(AutofillClock::Now()); + const std::string last_four1 = "1234"; + const std::string last_four2 = "9876"; + strike_database_.AddStrike(last_four1); + + // Advance clock to past the entry for |last_four1|'s expiry time. + test_clock.Advance(base::TimeDelta::FromMicroseconds( + strike_database_.GetExpiryTimeMicros() + 1)); + + strike_database_.AddStrike(last_four2); + strike_database_.RemoveExpiredStrikes(); + + // |last_four1|'s entry should have its most recent strike expire, but + // |last_four2|'s should not. + EXPECT_EQ(0, strike_database_.GetStrikes(last_four1)); + EXPECT_EQ(1, strike_database_.GetStrikes(last_four2)); + + // Advance clock to past |last_four2|'s expiry time. + test_clock.Advance(base::TimeDelta::FromMicroseconds( + strike_database_.GetExpiryTimeMicros() + 1)); + + strike_database_.RemoveExpiredStrikes(); + + // |last_four1| and |last_four2| should have no more unexpired strikes. + EXPECT_EQ(0, strike_database_.GetStrikes(last_four1)); + EXPECT_EQ(0, strike_database_.GetStrikes(last_four2)); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/credit_card_unittest.cc b/chromium/components/autofill/core/browser/credit_card_unittest.cc index 0093b822982..9552cae6cd4 100644 --- a/chromium/components/autofill/core/browser/credit_card_unittest.cc +++ b/chromium/components/autofill/core/browser/credit_card_unittest.cc @@ -15,7 +15,9 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/validation.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/form_field_data.h" #include "components/grit/components_scaled_resources.h" @@ -578,6 +580,19 @@ TEST(CreditCardTest, Compare) { b.set_origin("banana"); EXPECT_EQ(0, a.Compare(b)); + // Different types of server cards don't count. + a.set_record_type(MASKED_SERVER_CARD); + b.set_record_type(FULL_SERVER_CARD); + EXPECT_EQ(0, a.Compare(b)); + + // Local is different from server. + a.set_record_type(LOCAL_CARD); + b.set_record_type(FULL_SERVER_CARD); + EXPECT_GT(0, a.Compare(b)); + a.set_record_type(MASKED_SERVER_CARD); + b.set_record_type(LOCAL_CARD); + EXPECT_LT(0, a.Compare(b)); + // Different values produce non-zero results. test::SetCreditCardInfo(&a, "Jimmy", nullptr, nullptr, nullptr, ""); test::SetCreditCardInfo(&b, "Ringo", nullptr, nullptr, nullptr, ""); @@ -1009,6 +1024,41 @@ TEST(CreditCardTest, CreditCardVerificationCode) { EXPECT_EQ(base::string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE)); } +// Tests that the card in only deletable if it is expired before the threshold. +TEST(CreditCardTest, IsDeletable) { + // Set up an arbitrary time, as setup the current time to just above the + // threshold later than that time. This sets the year to 2007. The code + // expects valid expiration years to be between 2000 and 2999. However, + // because of the year 2018 problem, we need to pick an earlier year. + const base::Time kArbitraryTime = base::Time::FromDoubleT(1000000000); + TestAutofillClock test_clock; + test_clock.SetNow(kArbitraryTime + kDisusedDataModelDeletionTimeDelta + + base::TimeDelta::FromDays(1)); + + // Created a card that has not been used since over the deletion threshold. + CreditCard card(base::GenerateGUID(), "https://www.example.com/"); + card.set_use_date(kArbitraryTime); + + // Set the card to be expired before the threshold. + base::Time::Exploded now_exploded; + AutofillClock::Now().LocalExplode(&now_exploded); + card.SetExpirationYear(now_exploded.year - 5); + card.SetExpirationMonth(1); + ASSERT_TRUE(card.IsExpired(AutofillClock::Now() - + kDisusedDataModelDeletionTimeDelta)); + + // Make sure the card is deletable. + EXPECT_TRUE(card.IsDeletable()); + + // Set the card to not be expired. + card.SetExpirationYear(now_exploded.year + 5); + ASSERT_FALSE(card.IsExpired(AutofillClock::Now() - + kDisusedDataModelDeletionTimeDelta)); + + // Make sure the card is not deletable. + EXPECT_FALSE(card.IsDeletable()); +} + struct CreditCardMatchingTypesCase { CreditCardMatchingTypesCase(const char* value, const char* card_exp_month, diff --git a/chromium/components/autofill/core/browser/email_field.cc b/chromium/components/autofill/core/browser/email_field.cc index 3f4a351dac2..86d507ed74f 100644 --- a/chromium/components/autofill/core/browser/email_field.cc +++ b/chromium/components/autofill/core/browser/email_field.cc @@ -4,7 +4,6 @@ #include "components/autofill/core/browser/email_field.h" -#include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_scanner.h" #include "components/autofill/core/common/autofill_regex_constants.h" @@ -16,7 +15,7 @@ std::unique_ptr<FormField> EmailField::Parse(AutofillScanner* scanner) { AutofillField* field; if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe), MATCH_DEFAULT | MATCH_EMAIL, &field)) { - return base::WrapUnique(new EmailField(field)); + return std::make_unique<EmailField>(field); } return nullptr; diff --git a/chromium/components/autofill/core/browser/email_field.h b/chromium/components/autofill/core/browser/email_field.h index c47eb44174c..ea792028365 100644 --- a/chromium/components/autofill/core/browser/email_field.h +++ b/chromium/components/autofill/core/browser/email_field.h @@ -16,13 +16,12 @@ namespace autofill { class EmailField : public FormField { public: static std::unique_ptr<FormField> Parse(AutofillScanner* scanner); + explicit EmailField(const AutofillField* field); protected: void AddClassifications(FieldCandidatesMap* field_candidates) const override; private: - explicit EmailField(const AutofillField* field); - const AutofillField* field_; DISALLOW_COPY_AND_ASSIGN(EmailField); diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc index b092bfbff40..eb2f698627f 100644 --- a/chromium/components/autofill/core/browser/field_filler_unittest.cc +++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc @@ -10,8 +10,8 @@ #include "base/base_paths.h" #include "base/files/file_path.h" -#include "base/macros.h" #include "base/path_service.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -1139,10 +1139,10 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithEqualSizeSplits) { test.card_number_ = "5187654321098765"; test.total_splits_ = 4; int splits[] = {4, 4, 4, 4}; - test.splits_ = std::vector<int>(splits, splits + arraysize(splits)); + test.splits_ = std::vector<int>(splits, splits + base::size(splits)); std::string results[] = {"5187", "6543", "2109", "8765"}; test.expected_results_ = - std::vector<std::string>(results, results + arraysize(results)); + std::vector<std::string>(results, results + base::size(results)); FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr); for (size_t i = 0; i < test.total_splits_; ++i) { @@ -1181,10 +1181,10 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithUnequalSizeSplits) { test.card_number_ = "423456789012345"; test.total_splits_ = 3; int splits[] = {4, 6, 5}; - test.splits_ = std::vector<int>(splits, splits + arraysize(splits)); + test.splits_ = std::vector<int>(splits, splits + base::size(splits)); std::string results[] = {"4234", "567890", "12345"}; test.expected_results_ = - std::vector<std::string>(results, results + arraysize(results)); + std::vector<std::string>(results, results + base::size(results)); FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr); // Start executing test cases to verify parts and full credit card number. diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc index df485ac887e..03b9216973a 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.cc +++ b/chromium/components/autofill/core/browser/form_data_importer.cc @@ -487,10 +487,17 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm( base::TrimWhitespace(field->value, base::TRIM_ALL, &value); // If we don't know the type of the field, or the user hasn't entered any - // information into the field, or the field is non-focusable (hidden), then - // skip it. - if (!field->IsFieldFillable() || !field->is_focusable || value.empty()) + // information into the field, then skip it. + if (!field->IsFieldFillable() || value.empty()) continue; + // If the field is non-focusable (hidden) after the user entered information + // into it, then skip it, unless the experiment to import non-focusable + // forms is enabled. + if (!field->is_focusable && + !base::FeatureList::IsEnabled( + features::kAutofillImportNonFocusableCreditCardForms)) { + continue; + } AutofillType field_type = field->Type(); // Field was not identified as a credit card field. diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h index 412cf02e709..0a11aeb00a4 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.h +++ b/chromium/components/autofill/core/browser/form_data_importer.h @@ -145,13 +145,22 @@ class FormDataImporter { friend class AutofillMergeTest; friend class FormDataImporterTest; friend class FormDataImporterTestBase; - friend class SaveCardBubbleViewsBrowserTestBase; + friend class SaveCardBubbleViewsFullFormBrowserTest; friend class SaveCardInfobarEGTestHelper; FRIEND_TEST_ALL_PREFIXES(AutofillMergeTest, MergeProfiles); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, AllowDuplicateMaskedServerCardIfFlagEnabled); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DontDuplicateFullServerCard); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DontDuplicateMaskedServerCard); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, + ImportFormData_AddressesDisabledOneCreditCard); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, + ImportFormData_AddressCreditCardDisabled); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, + ImportFormData_HiddenCreditCardFormAfterEntered); + FRIEND_TEST_ALL_PREFIXES( + FormDataImporterTest, + ImportFormData_HiddenCreditCardFormAfterEnteredWithExpOff); FRIEND_TEST_ALL_PREFIXES( FormDataImporterTest, ImportFormData_ImportCreditCardRecordType_FullServerCard); @@ -179,10 +188,6 @@ class FormDataImporter { FormDataImporterTest, ImportFormData_SecondImportResetsCreditCardRecordType); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, - ImportFormData_AddressesDisabledOneCreditCard); - FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, - ImportFormData_AddressCreditCardDisabled); - FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard); FRIEND_TEST_ALL_PREFIXES( FormDataImporterTest, diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc index 51abba7bb0d..a205459df88 100644 --- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc @@ -18,7 +18,6 @@ #include "base/feature_list.h" #include "base/files/scoped_temp_dir.h" #include "base/guid.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" @@ -76,6 +75,7 @@ class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver { ~PersonalDataLoadedObserverMock() override {} MOCK_METHOD0(OnPersonalDataChanged, void()); + MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void()); }; template <typename T> @@ -129,10 +129,7 @@ class FormDataImporterTestBase { personal_data_manager_->AddObserver(&personal_data_observer_); personal_data_manager_->OnSyncServiceInitialized(nullptr); - base::RunLoop run_loop; - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMessageLoop(&run_loop)); - run_loop.Run(); + WaitForOnPersonalDataChanged(); } void EnableWalletCardImport() { @@ -173,8 +170,19 @@ class FormDataImporterTestBase { // Helper methods that simply forward the call to the private member (to avoid // having to friend every test that needs to access the private // PersonalDataManager::ImportAddressProfile or ImportCreditCard). - bool ImportAddressProfiles(const FormStructure& form) { - return form_data_importer_->ImportAddressProfiles(form); + void ImportAddressProfiles(bool extraction_successful, + const FormStructure& form) { + if (!extraction_successful) { + EXPECT_FALSE(form_data_importer_->ImportAddressProfiles(form)); + return; + } + + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + EXPECT_TRUE(form_data_importer_->ImportAddressProfiles(form)); + run_loop.Run(); } bool ImportCreditCard(const FormStructure& form, @@ -197,11 +205,7 @@ class FormDataImporterTestBase { personal_data_manager_->OnAcceptedLocalCreditCardSave( *imported_credit_card); - base::RunLoop run_loop; - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMessageLoop(&run_loop)); - run_loop.Run(); - + WaitForOnPersonalDataChanged(); CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetCreditCardInfo(&expected, exp_name, exp_cc_num, exp_cc_month, exp_cc_year, ""); @@ -213,15 +217,18 @@ class FormDataImporterTestBase { void WaitForOnPersonalDataChanged() { base::RunLoop run_loop; - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); run_loop.Run(); } // The temporary directory should be deleted at the end to ensure that // files are not used anymore and deletion succeeds. base::ScopedTempDir temp_dir_; - base::MessageLoopForUI message_loop_; + base::test::ScopedTaskEnvironment task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; std::unique_ptr<PrefService> prefs_; scoped_refptr<AutofillWebDataService> autofill_database_service_; scoped_refptr<WebDatabaseService> web_database_; @@ -304,9 +311,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -343,7 +348,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); } @@ -374,9 +379,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoEmails) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -407,7 +410,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); } @@ -429,7 +432,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size()); @@ -457,9 +460,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressUSA) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -486,9 +487,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGB) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -510,9 +509,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGI) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -552,9 +549,7 @@ TEST_F(FormDataImporterTest, form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr, @@ -593,9 +588,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) { form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -635,9 +628,7 @@ TEST_F(FormDataImporterTest, FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -673,9 +664,7 @@ TEST_F(FormDataImporterTest, FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com", @@ -732,9 +721,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -808,9 +795,7 @@ TEST_F(FormDataImporterTest, // Still able to do the import. FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -892,9 +877,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); // Only two are saved. AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); @@ -948,9 +931,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -996,9 +977,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); const std::vector<AutofillProfile*>& results2 = personal_data_manager_->GetProfiles(); @@ -1035,9 +1014,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr, @@ -1073,9 +1050,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); const std::vector<AutofillProfile*>& results2 = personal_data_manager_->GetProfiles(); @@ -1119,9 +1094,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -1159,9 +1132,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); const std::vector<AutofillProfile*>& results2 = personal_data_manager_->GetProfiles(); @@ -1197,7 +1168,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_InsufficientAddress) { FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure1)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure1); // Since no refresh is expected, reload the data from the database to make // sure no changes were written out. @@ -1220,10 +1191,12 @@ TEST_F(FormDataImporterTest, "Hollywood", "CA", "91601", "US", "12345678910"); EXPECT_TRUE(profile.IsVerified()); - // Add the profile to the database. + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); personal_data_manager_->AddProfile(profile); - - WaitForOnPersonalDataChanged(); + run_loop.Run(); // Simulate a form submission with conflicting info. FormData form; @@ -1251,10 +1224,7 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - // Wait for the refresh, which in this case is a no-op. - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); // Expect that no new profile is saved. const std::vector<AutofillProfile*>& results = @@ -1272,10 +1242,7 @@ TEST_F(FormDataImporterTest, FormStructure form_structure2(form); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - // Wait for the refresh, which in this case is a no-op. - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); // Expect that no new profile is saved. const std::vector<AutofillProfile*>& results2 = @@ -1314,7 +1281,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); // Since no refresh is expected, reload the data from the database to make // sure no changes were written out. @@ -1355,9 +1322,7 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -1404,7 +1369,7 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); // Since no refresh is expected, reload the data from the database to make // sure no changes were written out. @@ -2584,11 +2549,19 @@ TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); // Still returns true because the credit card import was successful. EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, /*should_return_local_card=*/false, &imported_credit_card)); + run_loop.Run(); + ASSERT_TRUE(imported_credit_card); personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card); @@ -2821,6 +2794,101 @@ TEST_F(FormDataImporterTest, DontDuplicateMaskedServerCard) { ASSERT_FALSE(imported_credit_card); } +// Tests that a credit card form that is hidden after receiving input still +// imports the card. +TEST_F(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillImportNonFocusableCreditCardForms); + + FormData form; + form.origin = GURL("https://wwww.foo.com"); + + FormFieldData field; + + test::CreateTestFormField("Name on card:", "name_on_card", "Biggie Smalls", + "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Card Number:", "card_number", "4111111111111111", + "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Exp Month:", "exp_month", "01", "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Exp Year:", "exp_year", "2999", "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + std::unique_ptr<CreditCard> imported_credit_card; + // Still returns true because the credit card import was successful. + EXPECT_TRUE(form_data_importer_->ImportFormData( + form_structure, /*profile_autofill_enabled=*/true, + /*credit_card_autofill_enabled=*/true, + /*should_return_local_card=*/false, &imported_credit_card)); + ASSERT_TRUE(imported_credit_card); + personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card); + + WaitForOnPersonalDataChanged(); + + // Test that the credit card has been saved. + CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin); + test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111", + "01", "2999", ""); + const std::vector<CreditCard*>& results = + personal_data_manager_->GetCreditCards(); + ASSERT_EQ(1U, results.size()); + EXPECT_EQ(0, expected_card.Compare(*results[0])); +} + +// Tests that a credit card form that is hidden after receiving input does not +// import the card when the experiment is off. +TEST_F(FormDataImporterTest, + ImportFormData_HiddenCreditCardFormAfterEnteredWithExpOff) { + scoped_feature_list_.InitAndDisableFeature( + features::kAutofillImportNonFocusableCreditCardForms); + + FormData form; + form.origin = GURL("https://wwww.foo.com"); + + FormFieldData field; + + test::CreateTestFormField("Name on card:", "name_on_card", "Biggie Smalls", + "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Card Number:", "card_number", "4111111111111111", + "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Exp Month:", "exp_month", "01", "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + test::CreateTestFormField("Exp Year:", "exp_year", "2999", "text", &field); + field.is_focusable = false; + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + std::unique_ptr<CreditCard> imported_credit_card; + // Returns false because the credit card import was failed. + EXPECT_FALSE(form_data_importer_->ImportFormData( + form_structure, /*profile_autofill_enabled=*/true, + /*credit_card_autofill_enabled=*/true, + /*should_return_local_card=*/false, &imported_credit_card)); + ASSERT_FALSE(imported_credit_card); +} + TEST_F(FormDataImporterTest, DontDuplicateFullServerCard) { EnableWalletCardImport(); diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc index 3032f4ee662..c715abb098f 100644 --- a/chromium/components/autofill/core/browser/form_structure.cc +++ b/chromium/components/autofill/core/browser/form_structure.cc @@ -288,6 +288,32 @@ HtmlFieldType FieldTypeFromAutocompleteAttributeValue( return HTML_TYPE_UNRECOGNIZED; } +// Helper function for explicit conversion between |ButtonTitleType| defined in +// "button_title_type.h" and "server.proto". +AutofillUploadContents_ButtonTitle_ButtonTitleType ToServerButtonTitleType( + autofill::ButtonTitleType input) { + switch (input) { + case ButtonTitleType::NONE: + return AutofillUploadContents::ButtonTitle::NONE; + case ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE: + return AutofillUploadContents::ButtonTitle::BUTTON_ELEMENT_SUBMIT_TYPE; + case ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE: + return AutofillUploadContents::ButtonTitle::BUTTON_ELEMENT_BUTTON_TYPE; + case ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE: + return AutofillUploadContents::ButtonTitle::INPUT_ELEMENT_SUBMIT_TYPE; + case ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE: + return AutofillUploadContents::ButtonTitle::INPUT_ELEMENT_BUTTON_TYPE; + case ButtonTitleType::HYPERLINK: + return AutofillUploadContents::ButtonTitle::HYPERLINK; + case ButtonTitleType::DIV: + return AutofillUploadContents::ButtonTitle::DIV; + case ButtonTitleType::SPAN: + return AutofillUploadContents::ButtonTitle::SPAN; + } + NOTREACHED(); + return AutofillUploadContents::ButtonTitle::NONE; +} + std::ostream& operator<<( std::ostream& out, const autofill::AutofillQueryResponseContents& response) { @@ -441,7 +467,7 @@ FormStructure::FormStructure(const FormData& form) : id_attribute_(form.id_attribute), name_attribute_(form.name_attribute), form_name_(form.name), - button_title_(form.button_title), + button_titles_(form.button_titles), submission_event_(SubmissionIndicatorEvent::NONE), source_url_(form.origin), target_url_(form.action), @@ -529,9 +555,7 @@ void FormStructure::DetermineHeuristicTypes() { 1 << AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT; } - if (base::FeatureList::IsEnabled( - features::kAutofillRationalizeFieldTypePredictions)) - RationalizeFieldTypePredictions(); + RationalizeFieldTypePredictions(); AutofillMetrics::LogDetermineHeuristicTypesTiming( base::TimeTicks::Now() - determine_heuristic_types_start_time); @@ -551,6 +575,7 @@ bool FormStructure::EncodeUploadRequest( upload->set_autofill_used(form_was_autofilled); upload->set_data_present(EncodeFieldTypes(available_field_types)); upload->set_passwords_revealed(passwords_were_revealed_); + upload->set_has_form_tag(is_form_tag_); if (!page_language_.empty() && randomized_encoder_ != nullptr) { upload->set_language(page_language_); } @@ -574,6 +599,11 @@ bool FormStructure::EncodeUploadRequest( upload->set_action_signature(StrToHash64Bit(target_url_.host())); if (!form_name().empty()) upload->set_form_name(base::UTF16ToUTF8(form_name())); + for (const ButtonTitleInfo& e : button_titles_) { + auto* button_title = upload->add_button_title(); + button_title->set_title(base::UTF16ToUTF8(e.first)); + button_title->set_type(ToServerButtonTitleType(e.second)); + } } if (!login_form_signature.empty()) { @@ -720,14 +750,8 @@ void FormStructure::ProcessQueryResponse( !query_response_has_no_server_data); form->UpdateAutofillCount(); - if (base::FeatureList::IsEnabled( - features::kAutofillRationalizeRepeatedServerPredictions)) - form->RationalizeRepeatedFields(form_interactions_ukm_logger); - - if (base::FeatureList::IsEnabled( - features::kAutofillRationalizeFieldTypePredictions)) - form->RationalizeFieldTypePredictions(); - + form->RationalizeRepeatedFields(form_interactions_ukm_logger); + form->RationalizeFieldTypePredictions(); form->IdentifySections(false); } @@ -942,6 +966,7 @@ void FormStructure::LogQualityMetrics( bool did_autofill_all_possible_fields = true; bool did_autofill_some_possible_fields = false; bool is_for_credit_card = IsCompleteCreditCardForm(); + bool has_upi_vpa_field = false; // Determine the correct suffix for the metric, depending on whether or // not a submission was observed. @@ -952,6 +977,7 @@ void FormStructure::LogQualityMetrics( for (size_t i = 0; i < field_count(); ++i) { auto* const field = this->field(i); if (IsUPIVirtualPaymentAddress(field->value)) { + has_upi_vpa_field = true; AutofillMetrics::LogUserHappinessMetric( AutofillMetrics::USER_DID_ENTER_UPI_VPA, field->Type().group(), security_state::SecurityLevel::SECURITY_LEVEL_COUNT); @@ -1036,8 +1062,8 @@ void FormStructure::LogQualityMetrics( } AutofillMetrics::LogAutofillFormSubmittedState( - state, is_for_credit_card, GetFormTypes(), form_parsed_timestamp_, - form_signature(), form_interactions_ukm_logger); + state, is_for_credit_card, has_upi_vpa_field, GetFormTypes(), + form_parsed_timestamp_, form_signature(), form_interactions_ukm_logger); } } diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h index ba04acb0136..218c73ed169 100644 --- a/chromium/components/autofill/core/browser/form_structure.h +++ b/chromium/components/autofill/core/browser/form_structure.h @@ -488,8 +488,8 @@ class FormStructure { // The name of the form. base::string16 form_name_; - // The title of form submission button. - base::string16 button_title_; + // The titles of form's buttons. + ButtonTitleList button_titles_; // The type of the event that was taken as an indication that the form has // been successfully submitted. diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc index 0ce878fee0c..cdc3cd526ad 100644 --- a/chromium/components/autofill/core/browser/form_structure_unittest.cc +++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc @@ -33,7 +33,6 @@ using base::ASCIIToUTF16; using autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics; using autofill::features::kAutofillEnforceMinRequiredFieldsForQuery; using autofill::features::kAutofillEnforceMinRequiredFieldsForUpload; -using autofill::features::kAutofillRationalizeRepeatedServerPredictions; namespace autofill { @@ -2445,6 +2444,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -2538,6 +2538,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) { upload.set_action_signature(15724779818122431245U); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text", nullptr, 3U, 0); @@ -2766,6 +2767,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMultipleValidities) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -2860,6 +2862,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMultipleValidities) { upload.set_action_signature(15724779818122431245U); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text", nullptr, 3U, {0, 2}); @@ -2893,6 +2896,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -2984,6 +2988,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { upload.set_password_has_numeric(true); upload.set_password_length(10u); upload.set_action_signature(15724779818122431245U); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text", nullptr, 3U); @@ -3104,6 +3109,7 @@ TEST_F(FormStructureTest, std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3183,6 +3189,7 @@ TEST_F(FormStructureTest, upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); AutofillUploadContents::Field* upload_firstname_field = upload.add_field(); test::FillUploadField(upload_firstname_field, 4224610201U, "firstname", "", @@ -3228,6 +3235,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3282,6 +3290,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text", "given-name", 3U); @@ -3310,6 +3319,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestWithPropertiesMask) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3377,6 +3387,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestWithPropertiesMask) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, nullptr, nullptr, nullptr, 3U); @@ -3408,6 +3419,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3462,6 +3474,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text", nullptr, 3U); @@ -3489,6 +3502,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3536,6 +3550,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text", nullptr, 3U); @@ -3561,6 +3576,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithCssClassesAndIds) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; FormFieldData field; field.form_control_type = "text"; @@ -3606,6 +3622,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithCssClassesAndIds) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); AutofillUploadContents::Field* firstname_field = upload.add_field(); test::FillUploadField(firstname_field, 1318412689U, nullptr, "text", nullptr, @@ -3641,6 +3658,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; // Setting the form name which we expect to see in the upload. form.name = ASCIIToUTF16("myform"); @@ -3690,6 +3708,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_FRAME_DETACHED); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text", nullptr, 3U); @@ -3716,6 +3735,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3770,6 +3790,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) { upload.set_action_signature(15724779818122431245U); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text", nullptr, 3U); @@ -3799,6 +3820,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -3861,6 +3883,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) { upload.set_passwords_revealed(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_NONE); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 3763331450U, nullptr, nullptr, nullptr, 3U); @@ -3886,6 +3909,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) { TEST_F(FormStructureTest, CheckDataPresence) { FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = true; FormFieldData field; field.form_control_type = "text"; @@ -3935,6 +3959,7 @@ TEST_F(FormStructureTest, CheckDataPresence) { upload.set_action_signature(15724779818122431245U); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_HTML_FORM_SUBMISSION); + upload.set_has_form_tag(true); test::FillUploadField(upload.add_field(), 1089846351U, "first", "text", nullptr, 1U); @@ -4164,6 +4189,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; form.origin = GURL("http://www.foo.com/"); + form.is_form_tag = false; FormFieldData field; field.form_control_type = "text"; @@ -4213,6 +4239,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { upload.set_autofill_used(false); upload.set_data_present("1440000360000008"); upload.set_passwords_revealed(false); + upload.set_has_form_tag(false); upload.set_action_signature(15724779818122431245U); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_XHR_SUCCEEDED); @@ -4330,6 +4357,29 @@ TEST_F(FormStructureTest, EncodeUploadRequest_PasswordsRevealed) { EXPECT_EQ(true, upload.passwords_revealed()); } +TEST_F(FormStructureTest, EncodeUploadRequest_IsFormTag) { + for (bool is_form_tag : {false, true}) { + SCOPED_TRACE(testing::Message() << "is_form_tag=" << is_form_tag); + + FormData form; + form.origin = GURL("http://www.foo.com/"); + FormFieldData field; + field.name = ASCIIToUTF16("email"); + form.fields.push_back(field); + + form.is_form_tag = is_form_tag; + + FormStructure form_structure(form); + form_structure.set_passwords_were_revealed(true); + AutofillUploadContents upload; + EXPECT_TRUE(form_structure.EncodeUploadRequest( + {{}} /* available_field_types */, false /* form_was_autofilled */, + std::string() /* login_form_signature */, + true /* observed_submission */, &upload)); + EXPECT_EQ(is_form_tag, upload.has_form_tag()); + } +} + TEST_F(FormStructureTest, EncodeUploadRequest_RichMetadata) { struct FieldMetadata { const char *id, *name, *label, *placeholder, *aria_label, *aria_description, @@ -5178,36 +5228,14 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); - // Test that the expiry month field is rationalized away when enabled. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(NAME_FULL, forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(2)->Type().GetStorableType()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->Type().GetStorableType()); - } - - // Sanity check that the enable/disabled works. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(NAME_FULL, forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, - forms[0]->field(2)->Type().GetStorableType()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->Type().GetStorableType()); - } + // Test that the expiry month field is rationalized away. + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + EXPECT_EQ(NAME_FULL, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(2)->Type().GetStorableType()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->Type().GetStorableType()); } TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { @@ -5240,35 +5268,13 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); - // Test that the name fields are rationalized when enabled. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(3U, forms[0]->field_count()); - EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->Type().GetStorableType()); - } - - // Sanity check that the enable/disabled works. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(3U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FIRST, - forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_NAME_LAST, - forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->Type().GetStorableType()); - } + // Test that the name fields are rationalized. + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(3U, forms[0]->field_count()); + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->Type().GetStorableType()); } TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { @@ -5313,44 +5319,18 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); - // Test that the extra month field is rationalized away when enabled. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(5U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, - forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, - forms[0]->field(2)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, - forms[0]->field(3)->Type().GetStorableType()); - EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(4)->Type().GetStorableType()); - } - - // Sanity check that the enable/disabled works. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(5U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, - forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, - forms[0]->field(2)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, - forms[0]->field(3)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, - forms[0]->field(4)->Type().GetStorableType()); - } + // Test that the extra month field is rationalized away. + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(5U, forms[0]->field_count()); + EXPECT_EQ(CREDIT_CARD_NAME_FULL, + forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(CREDIT_CARD_EXP_MONTH, + forms[0]->field(2)->Type().GetStorableType()); + EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, + forms[0]->field(3)->Type().GetStorableType()); + EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(4)->Type().GetStorableType()); } TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { @@ -5390,38 +5370,16 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); - // Test that the extra month field is rationalized away when enabled. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, - forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, - forms[0]->field(2)->Type().GetStorableType()); - EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(3)->Type().GetStorableType()); - } - - // Sanity check that the enable/disabled works. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - autofill::features::kAutofillRationalizeFieldTypePredictions); - FormStructure::ParseQueryResponse(response_string, forms, nullptr); - ASSERT_EQ(1U, forms.size()); - ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, - forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, - forms[0]->field(2)->Type().GetStorableType()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, - forms[0]->field(3)->Type().GetStorableType()); - } + // Test that the extra month field is rationalized away. + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + EXPECT_EQ(CREDIT_CARD_NAME_FULL, + forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, + forms[0]->field(2)->Type().GetStorableType()); + EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(3)->Type().GetStorableType()); } TEST_F(FormStructureTest, FindLongestCommonPrefix) { @@ -5520,10 +5478,6 @@ TEST_F(FormStructureTest, RationalizePhoneNumber_RunsOncePerSection) { // Tests that a form that has only one address predicted as // ADDRESS_HOME_STREET_ADDRESS is not modified by the address rationalization. TEST_F(FormStructureTest, RationalizeRepeatedFields_OneAddress) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -5570,10 +5524,6 @@ TEST_F(FormStructureTest, RationalizeRepeatedFields_OneAddress) { // ADDRESS_HOME_STREET_ADDRESS is modified by the address rationalization to be // ADDRESS_HOME_LINE1 and ADDRESS_HOME_LINE2 instead. TEST_F(FormStructureTest, RationalizeRepreatedFields_TwoAddresses) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -5626,10 +5576,6 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_TwoAddresses) { // ADDRESS_HOME_STREET_ADDRESS is modified by the address rationalization to be // ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2 and ADDRESS_HOME_LINE3 instead. TEST_F(FormStructureTest, RationalizeRepreatedFields_ThreeAddresses) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -5690,9 +5636,6 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_ThreeAddresses) { // This doesn't happen in real world, bc four address lines mean multiple // sections according to the heuristics. TEST_F(FormStructureTest, RationalizeRepreatedFields_FourAddresses) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -5762,10 +5705,6 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_FourAddresses) { // Tests that a form that has only one address in each section predicted as // ADDRESS_HOME_STREET_ADDRESS is not modified by the address rationalization. TEST_F(FormStructureTest, RationalizeRepreatedFields_OneAddressEachSection) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -5839,15 +5778,11 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_OneAddressEachSection) { // Tests a form that has multiple sections with multiple number of address // fields predicted as ADDRESS_HOME_STREET_ADDRESS. The last section -// doesn't happen in real world, bc it is in fact two sections according to +// doesn't happen in real world, because it is in fact two sections according to // heuristics, and is only made for testing. TEST_F( FormStructureTest, RationalizeRepreatedFields_SectionTwoAddress_SectionThreeAddress_SectionFourAddresses) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6001,10 +5936,6 @@ TEST_F( // while the sections are previously determined by the heuristics. TEST_F(FormStructureTest, RationalizeRepreatedFields_MultipleSectionsByHeuristics_OneAddressEach) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6078,10 +6009,6 @@ TEST_F(FormStructureTest, TEST_F( FormStructureTest, RationalizeRepreatedFields_MultipleSectionsByHeuristics_TwoAddress_ThreeAddress) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6171,10 +6098,6 @@ TEST_F( TEST_F(FormStructureTest, RationalizeRepreatedFields_StateCountry_NoRationalization) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6270,10 +6193,6 @@ TEST_F(FormStructureTest, } TEST_F(FormStructureTest, RationalizeRepreatedFields_CountryStateNoHeuristics) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6405,10 +6324,6 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_CountryStateNoHeuristics) { TEST_F(FormStructureTest, RationalizeRepreatedFields_StateCountryWithHeuristics) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6540,10 +6455,6 @@ TEST_F(FormStructureTest, } TEST_F(FormStructureTest, RationalizeRepreatedFields_FirstFieldRationalized) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6605,10 +6516,6 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_FirstFieldRationalized) { } TEST_F(FormStructureTest, RationalizeRepreatedFields_LastFieldRationalized) { - base::test::ScopedFeatureList feature_list; - InitFeature(&feature_list, kAutofillRationalizeRepeatedServerPredictions, - true); - FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; @@ -6681,8 +6588,8 @@ TEST_F(FormStructureTest, AllowBigForms) { FormData form; form.origin = GURL("http://foo.com"); FormFieldData field; - // Check that the form with 100 fields are processed correctly. - for (size_t i = 0; i < 100; ++i) { + // Check that the form with 250 fields are processed correctly. + for (size_t i = 0; i < 250; ++i) { field.form_control_type = "text"; field.name = ASCIIToUTF16("text") + base::NumberToString16(i); form.fields.push_back(field); diff --git a/chromium/components/autofill/core/browser/legacy_strike_database.cc b/chromium/components/autofill/core/browser/legacy_strike_database.cc index e6df31e20be..e6fbef3f7d3 100644 --- a/chromium/components/autofill/core/browser/legacy_strike_database.cc +++ b/chromium/components/autofill/core/browser/legacy_strike_database.cc @@ -12,7 +12,7 @@ #include "base/task/post_task.h" #include "base/time/time.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" -#include "components/leveldb_proto/proto_database_impl.h" +#include "components/leveldb_proto/public/proto_database_provider.h" namespace autofill { @@ -23,7 +23,7 @@ const char kKeyPrefixForCreditCardSave[] = "creditCardSave"; } // namespace LegacyStrikeDatabase::LegacyStrikeDatabase(const base::FilePath& database_dir) - : db_(std::make_unique<leveldb_proto::ProtoDatabaseImpl<StrikeData>>( + : db_(leveldb_proto::ProtoDatabaseProvider::CreateUniqueDB<StrikeData>( base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}))), diff --git a/chromium/components/autofill/core/browser/legacy_strike_database.h b/chromium/components/autofill/core/browser/legacy_strike_database.h index 57b0fe4a404..c0aca236581 100644 --- a/chromium/components/autofill/core/browser/legacy_strike_database.h +++ b/chromium/components/autofill/core/browser/legacy_strike_database.h @@ -12,7 +12,7 @@ #include "base/callback_forward.h" #include "base/memory/weak_ptr.h" #include "components/keyed_service/core/keyed_service.h" -#include "components/leveldb_proto/proto_database.h" +#include "components/leveldb_proto/public/proto_database.h" namespace autofill { class StrikeData; diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/local_card_migration_manager.cc index a10aee8ff49..764f9159b7f 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/local_card_migration_manager.cc @@ -94,9 +94,10 @@ void LocalCardMigrationManager::AttemptToOfferLocalCardMigration( base::BindOnce(&LocalCardMigrationManager::OnDidGetUploadDetails, weak_ptr_factory_.GetWeakPtr(), is_from_settings_page), payments::kMigrateCardsBillableServiceNumber, - is_from_settings_page - ? payments::PaymentsClient::MigrationSource::SETTINGS_PAGE - : payments::PaymentsClient::MigrationSource::CHECKOUT_FLOW); + is_from_settings_page ? payments::PaymentsClient::UploadCardSource:: + LOCAL_CARD_MIGRATION_SETTINGS_PAGE + : payments::PaymentsClient::UploadCardSource:: + LOCAL_CARD_MIGRATION_CHECKOUT_FLOW); } // Callback function when user agrees to migration on the intermediate dialog. @@ -161,10 +162,10 @@ void LocalCardMigrationManager::OnDidGetUploadDetails( bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) { + std::unique_ptr<base::Value> legal_message) { if (result == AutofillClient::SUCCESS) { migration_request_.context_token = context_token; - legal_message_ = std::move(legal_message); + legal_message_ = base::DictionaryValue::From(std::move(legal_message)); migration_request_.risk_data.clear(); // If we successfully received the legal docs, trigger the offer-to-migrate // dialog. If triggered from settings page, we pop-up the main prompt @@ -272,7 +273,9 @@ void LocalCardMigrationManager::ShowMainMigrationDialog() { local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_SHOWN); // Pops up a larger, modal dialog showing the local cards to be uploaded. client_->ConfirmMigrateLocalCardToCloud( - std::move(legal_message_), migratable_credit_cards_, + std::move(legal_message_), + client_->GetIdentityManager()->GetPrimaryAccountInfo().email, + migratable_credit_cards_, base::BindOnce( &LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog, weak_ptr_factory_.GetWeakPtr())); diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager.h b/chromium/components/autofill/core/browser/local_card_migration_manager.h index b2a5f9cb94f..06e5ce5832c 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/local_card_migration_manager.h @@ -123,7 +123,7 @@ class LocalCardMigrationManager { bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message); + std::unique_ptr<base::Value> legal_message); // Callback after successfully getting the migration save results. Map // migration save result to each card depending on the |save_result|. Will diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc index 341904811fb..6dd9308c48a 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc @@ -26,6 +26,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" @@ -90,7 +91,8 @@ class LocalCardMigrationManagerTest : public testing::Test { autofill_client_.set_test_form_data_importer( std::unique_ptr<TestFormDataImporter>(test_form_data_importer)); autofill_manager_.reset(new TestAutofillManager( - autofill_driver_.get(), &autofill_client_, &personal_data_)); + autofill_driver_.get(), &autofill_client_, &personal_data_, + &autocomplete_history_manager_)); autofill_manager_->SetExpectedObservedSubmission(true); } @@ -121,8 +123,8 @@ class LocalCardMigrationManagerTest : public testing::Test { } void FormSubmitted(const FormData& form) { - autofill_manager_->OnFormSubmitted( - form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now()); + autofill_manager_->OnFormSubmitted(form, false, + SubmissionSource::FORM_SUBMISSION); } void EditCreditCardFrom(FormData& credit_card_form, @@ -172,6 +174,7 @@ class LocalCardMigrationManagerTest : public testing::Test { std::unique_ptr<TestAutofillManager> autofill_manager_; scoped_refptr<net::TestURLRequestContextGetter> request_context_; TestPersonalDataManager personal_data_; + MockAutocompleteHistoryManager autocomplete_history_manager_; syncer::TestSyncService sync_service_; base::test::ScopedFeatureList scoped_feature_list_; // Ends up getting owned (and destroyed) by TestFormDataImporter: @@ -670,6 +673,99 @@ TEST_F(LocalCardMigrationManagerTest, CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT); } +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_ShouldAddMigrateCardsBillableServiceNumberInRequest) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will + // enter below. + AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1", "guid1"); + // Add another local credit card + AddLocalCreditCard(personal_data_, "Flo Master", "5555555555554444", "11", + test::NextYear().c_str(), "1", "guid2"); + + // Set up our credit card form data. + FormData credit_card_form; + test::CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "123"); + FormSubmitted(credit_card_form); + EXPECT_TRUE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); + + // Confirm that the preflight request contained + // kMigrateCardsBillableServiceNumber in the request. + EXPECT_EQ(payments::kMigrateCardsBillableServiceNumber, + payments_client_->billable_service_number_in_request()); +} + +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_ShouldAddUploadCardSourceInRequest_CheckoutFlow) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will + // enter below. + AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1", "guid1"); + // Add another local credit card + AddLocalCreditCard(personal_data_, "Flo Master", "5555555555554444", "11", + test::NextYear().c_str(), "1", "guid2"); + + // Set up our credit card form data. + FormData credit_card_form; + test::CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "123"); + FormSubmitted(credit_card_form); + EXPECT_TRUE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); + + // Confirm that the preflight request contained the correct UploadCardSource. + EXPECT_EQ(payments::PaymentsClient::UploadCardSource:: + LOCAL_CARD_MIGRATION_CHECKOUT_FLOW, + payments_client_->upload_card_source_in_request()); +} + +TEST_F(LocalCardMigrationManagerTest, + MigrateCreditCard_ShouldAddUploadCardSourceInRequest_SettingsPage) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Set the billing_customer_number Priority Preference to designate + // existence of a Payments account. + autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, + 12345); + // Add a local credit card. One migratable credit card will still trigger + // migration on settings page. + AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1", "guid1"); + + base::HistogramTester histogram_tester; + // Do the same operation as we bridge back from the settings page. + local_card_migration_manager_->GetMigratableCreditCards(); + local_card_migration_manager_->AttemptToOfferLocalCardMigration(true); + + EXPECT_FALSE(local_card_migration_manager_->IntermediatePromptWasShown()); + EXPECT_TRUE(local_card_migration_manager_->MainPromptWasShown()); + + // Confirm that the preflight request contained the correct UploadCardSource. + EXPECT_EQ(payments::PaymentsClient::UploadCardSource:: + LOCAL_CARD_MIGRATION_SETTINGS_PAGE, + payments_client_->upload_card_source_in_request()); +} + // Verify that when triggering from settings page, intermediate prompt will not // be triggered. TEST_F(LocalCardMigrationManagerTest, diff --git a/chromium/components/autofill/core/browser/local_card_migration_strike_database.cc b/chromium/components/autofill/core/browser/local_card_migration_strike_database.cc new file mode 100644 index 00000000000..6125d447a75 --- /dev/null +++ b/chromium/components/autofill/core/browser/local_card_migration_strike_database.cc @@ -0,0 +1,36 @@ +// Copyright 2019 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 "components/autofill/core/browser/local_card_migration_strike_database.h" + +#include "components/autofill/core/browser/proto/strike_data.pb.h" + +namespace autofill { + +LocalCardMigrationStrikeDatabase::LocalCardMigrationStrikeDatabase( + StrikeDatabase* strike_database) + : StrikeDatabaseIntegratorBase(strike_database) { + RemoveExpiredStrikes(); +} + +LocalCardMigrationStrikeDatabase::~LocalCardMigrationStrikeDatabase() {} + +std::string LocalCardMigrationStrikeDatabase::GetProjectPrefix() { + return "LocalCardMigration"; +} + +int LocalCardMigrationStrikeDatabase::GetMaxStrikesLimit() { + return 6; +} + +long long LocalCardMigrationStrikeDatabase::GetExpiryTimeMicros() { + // Expiry time is 1 year. + return (long long)1000000 * 60 * 60 * 24 * 365; +} + +bool LocalCardMigrationStrikeDatabase::UniqueIdsRequired() { + return false; +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/local_card_migration_strike_database.h b/chromium/components/autofill/core/browser/local_card_migration_strike_database.h new file mode 100644 index 00000000000..ab25114d903 --- /dev/null +++ b/chromium/components/autofill/core/browser/local_card_migration_strike_database.h @@ -0,0 +1,29 @@ +// Copyright 2019 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ + +#include <string> + +#include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/strike_database_integrator_base.h" + +namespace autofill { + +// Implementation of StrikeDatabaseIntegratorBase for local card migrations. +class LocalCardMigrationStrikeDatabase : public StrikeDatabaseIntegratorBase { + public: + LocalCardMigrationStrikeDatabase(StrikeDatabase* strike_database); + ~LocalCardMigrationStrikeDatabase() override; + + std::string GetProjectPrefix() override; + int GetMaxStrikesLimit() override; + long long GetExpiryTimeMicros() override; + bool UniqueIdsRequired() override; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/local_card_migration_strike_database_unittest.cc b/chromium/components/autofill/core/browser/local_card_migration_strike_database_unittest.cc new file mode 100644 index 00000000000..c7d3ad022d5 --- /dev/null +++ b/chromium/components/autofill/core/browser/local_card_migration_strike_database_unittest.cc @@ -0,0 +1,111 @@ +// Copyright 2019 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 "components/autofill/core/browser/local_card_migration_strike_database.h" + +#include <utility> +#include <vector> + +#include "base/files/scoped_temp_dir.h" +#include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/autofill/core/browser/proto/strike_data.pb.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/browser/test_local_card_migration_strike_database.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +class LocalCardMigrationStrikeDatabaseTest : public ::testing::Test { + public: + LocalCardMigrationStrikeDatabaseTest() + : strike_database_(new StrikeDatabase(InitFilePath())) {} + + protected: + base::HistogramTester* GetHistogramTester() { return &histogram_tester_; } + base::test::ScopedTaskEnvironment scoped_task_environment_; + TestLocalCardMigrationStrikeDatabase strike_database_; + + private: + static const base::FilePath InitFilePath() { + base::ScopedTempDir temp_dir_; + EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); + const base::FilePath file_path = + temp_dir_.GetPath().AppendASCII("StrikeDatabaseTest"); + return file_path; + } + + base::HistogramTester histogram_tester_; +}; + +TEST_F(LocalCardMigrationStrikeDatabaseTest, MaxStrikesLimitReachedTest) { + EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached()); + // 3 strikes added. + strike_database_.AddStrikes(3); + EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached()); + // 4 strike added, total strike count is 7. + strike_database_.AddStrikes(4); + EXPECT_EQ(true, strike_database_.IsMaxStrikesLimitReached()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, + LocalCardMigrationNthStrikeAddedHistogram) { + // 2 strikes logged. + strike_database_.AddStrikes(2); + strike_database_.RemoveStrikes(2); + // 1 strike logged. + strike_database_.AddStrike(); + // 2 strikes logged. + strike_database_.AddStrike(); + std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples( + "Autofill.StrikeDatabase.NthStrikeAdded.LocalCardMigration"); + // There should be two buckets, for strike counts of 1 and 2. + ASSERT_EQ(2U, buckets.size()); + // Bucket for 1 strike should have count of 1. + EXPECT_EQ(1, buckets[0].count); + // Bucket for 2 strikes should have count of 2. + EXPECT_EQ(2, buckets[1].count); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, + AddStrikeForZeroAndNonZeroStrikesTest) { + EXPECT_EQ(0, strike_database_.GetStrikes()); + strike_database_.AddStrike(); + EXPECT_EQ(1, strike_database_.GetStrikes()); + strike_database_.AddStrikes(2); + EXPECT_EQ(3, strike_database_.GetStrikes()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, + ClearStrikesForNonZeroStrikesTest) { + strike_database_.AddStrikes(3); + EXPECT_EQ(3, strike_database_.GetStrikes()); + strike_database_.ClearStrikes(); + EXPECT_EQ(0, strike_database_.GetStrikes()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, ClearStrikesForZeroStrikesTest) { + strike_database_.ClearStrikes(); + EXPECT_EQ(0, strike_database_.GetStrikes()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, RemoveExpiredStrikesTest) { + autofill::TestAutofillClock test_clock; + test_clock.SetNow(AutofillClock::Now()); + strike_database_.AddStrikes(2); + EXPECT_EQ(2, strike_database_.GetStrikes()); + + // Advance clock to past expiry time. + test_clock.Advance(base::TimeDelta::FromMicroseconds( + strike_database_.GetExpiryTimeMicros() + 1)); + + // One strike should be removed. + strike_database_.RemoveExpiredStrikes(); + EXPECT_EQ(1, strike_database_.GetStrikes()); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.cc new file mode 100644 index 00000000000..38da60e06ef --- /dev/null +++ b/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.cc @@ -0,0 +1,14 @@ +// 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 "components/autofill/core/browser/mock_autocomplete_history_manager.h" + +#include "components/autofill/core/browser/autocomplete_history_manager.h" + +namespace autofill { +MockAutocompleteHistoryManager::MockAutocompleteHistoryManager() = default; + +MockAutocompleteHistoryManager::~MockAutocompleteHistoryManager() = default; + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h b/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h new file mode 100644 index 00000000000..9a87d7fa745 --- /dev/null +++ b/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_MOCK_AUTOCOMPLETE_HISTORY_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_MOCK_AUTOCOMPLETE_HISTORY_MANAGER_H_ + +#include "base/memory/weak_ptr.h" +#include "components/autofill/core/browser/autocomplete_history_manager.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace autofill { + +class MockAutocompleteHistoryManager : public AutocompleteHistoryManager { + public: + MockAutocompleteHistoryManager(); + ~MockAutocompleteHistoryManager(); + + MOCK_METHOD2(Init, void(scoped_refptr<AutofillWebDataService>, bool)); + MOCK_METHOD7( + OnGetAutocompleteSuggestions, + void(int query_id, + bool is_autocomplete_enabled, + bool autoselect_first_suggestion, + const base::string16& name, + const base::string16& prefix, + const std::string& form_control_type, + base::WeakPtr<AutocompleteHistoryManager::SuggestionsHandler> + handler)); + MOCK_METHOD2(OnWillSubmitForm, + void(const FormData& form, bool is_autocomplete_enabled)); + MOCK_METHOD2(OnWebDataServiceRequestDone, + void(WebDataServiceBase::Handle, + std::unique_ptr<WDTypedResult>)); + MOCK_METHOD1(CancelPendingQueries, + void(const AutocompleteHistoryManager::SuggestionsHandler*)); + MOCK_METHOD2(OnRemoveAutocompleteEntry, + void(const base::string16&, const base::string16&)); + MOCK_METHOD1(OnAutocompleteEntrySelected, void(const base::string16&)); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_MOCK_AUTOCOMPLETE_HISTORY_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/name_field.cc b/chromium/components/autofill/core/browser/name_field.cc index 6bbe3c1bf4f..a6ea9e76ff4 100644 --- a/chromium/components/autofill/core/browser/name_field.cc +++ b/chromium/components/autofill/core/browser/name_field.cc @@ -7,7 +7,6 @@ #include <memory> #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_scanner.h" @@ -23,13 +22,12 @@ namespace { class FullNameField : public NameField { public: static std::unique_ptr<FullNameField> Parse(AutofillScanner* scanner); + explicit FullNameField(AutofillField* field); protected: void AddClassifications(FieldCandidatesMap* field_candidates) const override; private: - explicit FullNameField(AutofillField* field); - AutofillField* field_; DISALLOW_COPY_AND_ASSIGN(FullNameField); @@ -91,7 +89,7 @@ std::unique_ptr<FullNameField> FullNameField::Parse(AutofillScanner* scanner) { // "Travel Profile Name". AutofillField* field = nullptr; if (ParseField(scanner, UTF8ToUTF16(kNameRe), &field)) - return base::WrapUnique(new FullNameField(field)); + return std::make_unique<FullNameField>(field); return nullptr; } diff --git a/chromium/components/autofill/core/browser/name_field_unittest.cc b/chromium/components/autofill/core/browser/name_field_unittest.cc index b575d16410b..e6a3d22680a 100644 --- a/chromium/components/autofill/core/browser/name_field_unittest.cc +++ b/chromium/components/autofill/core/browser/name_field_unittest.cc @@ -31,7 +31,7 @@ class NameFieldTest : public testing::Test { // Downcast for tests. static std::unique_ptr<NameField> Parse(AutofillScanner* scanner) { std::unique_ptr<FormField> field = NameField::Parse(scanner); - return base::WrapUnique(static_cast<NameField*>(field.release())); + return std::unique_ptr<NameField>(static_cast<NameField*>(field.release())); } private: diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc index a71d0211bac..fc4486c4cc6 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc @@ -7,8 +7,8 @@ #include "base/command_line.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_test_utils.h" @@ -115,7 +115,7 @@ class FullCardRequestTest : public testing::Test { } private: - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; MockPersonalDataManager personal_data_; MockResultDelegate result_delegate_; MockUIDelegate ui_delegate_; diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc index 91e1a848359..ac4803ae4a3 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client.cc @@ -90,28 +90,53 @@ GURL GetRequestUrl(const std::string& path) { return GetBaseSecureUrl().Resolve(path); } -base::DictionaryValue BuildCustomerContextDictionary( - int64_t external_customer_id) { - base::DictionaryValue customer_context; - customer_context.SetString("external_customer_id", - std::to_string(external_customer_id)); +// Tries to get the string |out_value| from the |dictionary| with the given +// |key|. +// Returns true if the string value was found, false otherwise. +bool TryGetString(std::string key, + base::Value& dictionary, + std::string* out_value) { + base::Value* str_ptr = dictionary.FindKey(key); + if (str_ptr) { + *out_value = str_ptr->GetString(); + } + return str_ptr; +} + +// Tries to get the string |out_value| from the |dictionary| with the given +// |path|. +// Returns true if the string value was found, false otherwise. +bool TryGetStringByPath(std::initializer_list<base::StringPiece> path, + base::Value& dictionary, + std::string* out_value) { + base::Value* str_ptr = dictionary.FindPath(path); + if (str_ptr) { + *out_value = str_ptr->GetString(); + } + return str_ptr; +} + +base::Value BuildCustomerContextDictionary(int64_t external_customer_id) { + base::Value customer_context(base::Value::Type::DICTIONARY); + customer_context.SetKey("external_customer_id", + base::Value(std::to_string(external_customer_id))); return customer_context; } -base::DictionaryValue BuildRiskDictionary( - const std::string& encoded_risk_data) { - base::DictionaryValue risk_data; +base::Value BuildRiskDictionary(const std::string& encoded_risk_data) { + base::Value risk_data(base::Value::Type::DICTIONARY); #if defined(OS_IOS) // Browser fingerprinting is not available on iOS. Instead, we generate // RiskAdvisoryData. - risk_data.SetString("message_type", "RISK_ADVISORY_DATA"); - risk_data.SetString("encoding_type", "BASE_64_URL"); + risk_data.SetKey("message_type", base::Value("RISK_ADVISORY_DATA")); + risk_data.SetKey("encoding_type", base::Value("BASE_64_URL")); #else - risk_data.SetString("message_type", "BROWSER_NATIVE_FINGERPRINTING"); - risk_data.SetString("encoding_type", "BASE_64"); + risk_data.SetKey("message_type", + base::Value("BROWSER_NATIVE_FINGERPRINTING")); + risk_data.SetKey("encoding_type", base::Value("BASE_64")); #endif - risk_data.SetString("value", encoded_risk_data); + risk_data.SetKey("value", base::Value(encoded_risk_data)); return risk_data; } @@ -120,65 +145,63 @@ void SetStringIfNotEmpty(const AutofillDataModel& profile, const ServerFieldType& type, const std::string& app_locale, const std::string& path, - base::DictionaryValue* dictionary) { + base::Value& dictionary) { const base::string16 value = profile.GetInfo(AutofillType(type), app_locale); if (!value.empty()) - dictionary->SetString(path, value); + dictionary.SetKey(path, base::Value(value)); } void AppendStringIfNotEmpty(const AutofillProfile& profile, const ServerFieldType& type, const std::string& app_locale, - base::ListValue* list) { + base::Value& list) { const base::string16 value = profile.GetInfo(type, app_locale); if (!value.empty()) - list->AppendString(value); + list.GetList().emplace_back(value); } // Returns a dictionary with the structure expected by Payments RPCs, containing // each of the fields in |profile|, formatted according to |app_locale|. If // |include_non_location_data| is false, the name and phone number in |profile| // are not included. -std::unique_ptr<base::DictionaryValue> BuildAddressDictionary( - const AutofillProfile& profile, - const std::string& app_locale, - bool include_non_location_data) { - std::unique_ptr<base::DictionaryValue> postal_address( - new base::DictionaryValue()); +base::Value BuildAddressDictionary(const AutofillProfile& profile, + const std::string& app_locale, + bool include_non_location_data) { + base::Value postal_address(base::Value::Type::DICTIONARY); if (include_non_location_data) { SetStringIfNotEmpty(profile, NAME_FULL, app_locale, - PaymentsClient::kRecipientName, postal_address.get()); + PaymentsClient::kRecipientName, postal_address); } - std::unique_ptr<base::ListValue> address_lines(new base::ListValue()); + base::Value address_lines(base::Value::Type::LIST); AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE1, app_locale, - address_lines.get()); + address_lines); AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE2, app_locale, - address_lines.get()); + address_lines); AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE3, app_locale, - address_lines.get()); - if (!address_lines->empty()) - postal_address->Set("address_line", std::move(address_lines)); + address_lines); + if (!address_lines.GetList().empty()) + postal_address.SetKey("address_line", std::move(address_lines)); SetStringIfNotEmpty(profile, ADDRESS_HOME_CITY, app_locale, "locality_name", - postal_address.get()); + postal_address); SetStringIfNotEmpty(profile, ADDRESS_HOME_STATE, app_locale, - "administrative_area_name", postal_address.get()); + "administrative_area_name", postal_address); SetStringIfNotEmpty(profile, ADDRESS_HOME_ZIP, app_locale, - "postal_code_number", postal_address.get()); + "postal_code_number", postal_address); // Use GetRawInfo to get a country code instead of the country name: const base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY); if (!country_code.empty()) - postal_address->SetString("country_name_code", country_code); + postal_address.SetKey("country_name_code", base::Value(country_code)); - std::unique_ptr<base::DictionaryValue> address(new base::DictionaryValue()); - address->Set("postal_address", std::move(postal_address)); + base::Value address(base::Value::Type::DICTIONARY); + address.SetKey("postal_address", std::move(postal_address)); if (include_non_location_data) { SetStringIfNotEmpty(profile, PHONE_HOME_WHOLE_NUMBER, app_locale, - PaymentsClient::kPhoneNumber, address.get()); + PaymentsClient::kPhoneNumber, address); } return address; @@ -189,12 +212,11 @@ std::unique_ptr<base::DictionaryValue> BuildAddressDictionary( // name (if any) fields in |credit_card|, formatted according to |app_locale|. // |pan_field_name| is the field name for the encrypted pan. We use each credit // card's guid as the unique id. -std::unique_ptr<base::DictionaryValue> BuildCreditCardDictionary( - const CreditCard& credit_card, - const std::string& app_locale, - const std::string& pan_field_name) { - std::unique_ptr<base::DictionaryValue> card(new base::DictionaryValue()); - card->SetString("unique_id", credit_card.guid()); +base::Value BuildCreditCardDictionary(const CreditCard& credit_card, + const std::string& app_locale, + const std::string& pan_field_name) { + base::Value card(base::Value::Type::DICTIONARY); + card.SetKey("unique_id", base::Value(credit_card.guid())); const base::string16 exp_month = credit_card.GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale); @@ -202,30 +224,29 @@ std::unique_ptr<base::DictionaryValue> BuildCreditCardDictionary( AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale); int value = 0; if (base::StringToInt(exp_month, &value)) - card->SetInteger("expiration_month", value); + card.SetKey("expiration_month", base::Value(value)); if (base::StringToInt(exp_year, &value)) - card->SetInteger("expiration_year", value); + card.SetKey("expiration_year", base::Value(value)); SetStringIfNotEmpty(credit_card, CREDIT_CARD_NAME_FULL, app_locale, - "cardholder_name", card.get()); + "cardholder_name", card); - card->SetString("encrypted_pan", "__param:" + pan_field_name); + card.SetKey("encrypted_pan", base::Value("__param:" + pan_field_name)); return card; } // Populates the list of active experiments that affect either the data sent in // payments RPCs or whether the RPCs are sent or not. void SetActiveExperiments(const std::vector<const char*>& active_experiments, - base::DictionaryValue* request_dict) { + base::Value& request_dict) { if (active_experiments.empty()) return; - std::unique_ptr<base::ListValue> active_chrome_experiments( - std::make_unique<base::ListValue>()); + base::Value active_chrome_experiments(base::Value::Type::LIST); for (const char* it : active_experiments) - active_chrome_experiments->AppendString(it); + active_chrome_experiments.GetList().emplace_back(it); - request_dict->Set("active_chrome_experiments", - std::move(active_chrome_experiments)); + request_dict.SetKey("active_chrome_experiments", + std::move(active_chrome_experiments)); } class UnmaskCardRequest : public PaymentsRequest { @@ -250,32 +271,35 @@ class UnmaskCardRequest : public PaymentsRequest { } std::string GetRequestContent() override { - base::DictionaryValue request_dict; - request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc"); - request_dict.SetString("credit_card_id", request_details_.card.server_id()); + base::Value request_dict(base::Value::Type::DICTIONARY); + request_dict.SetKey("encrypted_cvc", base::Value("__param:s7e_13_cvc")); + request_dict.SetKey("credit_card_id", + base::Value(request_details_.card.server_id())); request_dict.SetKey("risk_data_encoded", BuildRiskDictionary(request_details_.risk_data)); - std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); - context->SetInteger("billable_service", kUnmaskCardBillableServiceNumber); + base::Value context(base::Value::Type::DICTIONARY); + context.SetKey("billable_service", + base::Value(kUnmaskCardBillableServiceNumber)); if (request_details_.billing_customer_number != 0) { - context->SetKey("customer_context", - BuildCustomerContextDictionary( - request_details_.billing_customer_number)); + context.SetKey("customer_context", + BuildCustomerContextDictionary( + request_details_.billing_customer_number)); } - request_dict.Set("context", std::move(context)); + request_dict.SetKey("context", std::move(context)); if (ShouldUseActiveSignedInAccount()) { - std::unique_ptr<base::DictionaryValue> chrome_user_context( - new base::DictionaryValue()); - chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); - request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + base::Value chrome_user_context(base::Value::Type::DICTIONARY); + chrome_user_context.SetKey("full_sync_enabled", + base::Value(full_sync_enabled_)); + request_dict.SetKey("chrome_user_context", + std::move(chrome_user_context)); } int value = 0; if (base::StringToInt(request_details_.user_response.exp_month, &value)) - request_dict.SetInteger("expiration_month", value); + request_dict.SetKey("expiration_month", base::Value(value)); if (base::StringToInt(request_details_.user_response.exp_year, &value)) - request_dict.SetInteger("expiration_year", value); + request_dict.SetKey("expiration_year", base::Value(value)); std::string json_request; base::JSONWriter::Write(request_dict, &json_request); @@ -289,8 +313,8 @@ class UnmaskCardRequest : public PaymentsRequest { return request_content; } - void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { - response->GetString("pan", &real_pan_); + void ParseResponse(base::Value response) override { + TryGetString("pan", response, &real_pan_); } bool IsResponseComplete() override { return !real_pan_.empty(); } @@ -318,9 +342,9 @@ class GetUploadDetailsRequest : public PaymentsRequest { const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::DictionaryValue>)> callback, + std::unique_ptr<base::Value>)> callback, const int billable_service_number, - PaymentsClient::MigrationSource migration_source) + PaymentsClient::UploadCardSource upload_card_source) : addresses_(addresses), detected_values_(detected_values), active_experiments_(active_experiments), @@ -328,7 +352,7 @@ class GetUploadDetailsRequest : public PaymentsRequest { app_locale_(app_locale), callback_(std::move(callback)), billable_service_number_(billable_service_number), - migration_source_(migration_source) {} + upload_card_source_(upload_card_source) {} ~GetUploadDetailsRequest() override {} std::string GetRequestUrlPath() override { @@ -338,20 +362,21 @@ class GetUploadDetailsRequest : public PaymentsRequest { std::string GetRequestContentType() override { return "application/json"; } std::string GetRequestContent() override { - base::DictionaryValue request_dict; - std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); - context->SetString("language_code", app_locale_); - context->SetInteger("billable_service", billable_service_number_); - request_dict.Set("context", std::move(context)); + base::Value request_dict(base::Value::Type::DICTIONARY); + base::Value context(base::Value::Type::DICTIONARY); + context.SetKey("language_code", base::Value(app_locale_)); + context.SetKey("billable_service", base::Value(billable_service_number_)); + request_dict.SetKey("context", std::move(context)); if (ShouldUseActiveSignedInAccount()) { - std::unique_ptr<base::DictionaryValue> chrome_user_context( - new base::DictionaryValue()); - chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); - request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + base::Value chrome_user_context(base::Value::Type::DICTIONARY); + chrome_user_context.SetKey("full_sync_enabled", + base::Value(full_sync_enabled_)); + request_dict.SetKey("chrome_user_context", + std::move(chrome_user_context)); } - std::unique_ptr<base::ListValue> addresses(new base::ListValue()); + base::Value addresses(base::Value::Type::LIST); for (const AutofillProfile& profile : addresses_) { // These addresses are used by Payments to (1) accurately determine the // user's country in order to show the correct legal documents and (2) to @@ -360,26 +385,42 @@ class GetUploadDetailsRequest : public PaymentsRequest { // min address is not possible). The final parameter directs // BuildAddressDictionary to omit names and phone numbers, which aren't // useful for these purposes. - addresses->Append(BuildAddressDictionary(profile, app_locale_, false)); + addresses.GetList().push_back( + BuildAddressDictionary(profile, app_locale_, false)); } - request_dict.Set("address", std::move(addresses)); + request_dict.SetKey("address", std::move(addresses)); // It's possible we may not have found name/address/CVC in the checkout // flow. The detected_values_ bitmask tells Payments what *was* found, and // Payments will decide if the provided data is enough to offer upload save. - request_dict.SetInteger("detected_values", detected_values_); + request_dict.SetKey("detected_values", base::Value(detected_values_)); - SetActiveExperiments(active_experiments_, &request_dict); + SetActiveExperiments(active_experiments_, request_dict); - switch (migration_source_) { - case PaymentsClient::MigrationSource::UNKNOWN_MIGRATION_SOURCE: - request_dict.SetString("migration_source", "UNKNOWN_MIGRATION_SOURCE"); + switch (upload_card_source_) { + case PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE: + request_dict.SetKey("upload_card_source", + base::Value("UNKNOWN_UPLOAD_CARD_SOURCE")); + break; + case PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW: + request_dict.SetKey("upload_card_source", + base::Value("UPSTREAM_CHECKOUT_FLOW")); break; - case PaymentsClient::MigrationSource::CHECKOUT_FLOW: - request_dict.SetString("migration_source", "CHECKOUT_FLOW"); + case PaymentsClient::UploadCardSource::UPSTREAM_SETTINGS_PAGE: + request_dict.SetKey("upload_card_source", + base::Value("UPSTREAM_SETTINGS_PAGE")); break; - case PaymentsClient::MigrationSource::SETTINGS_PAGE: - request_dict.SetString("migration_source", "SETTINGS_PAGE"); + case PaymentsClient::UploadCardSource::UPSTREAM_CARD_OCR: + request_dict.SetKey("upload_card_source", + base::Value("UPSTREAM_CARD_OCR")); + break; + case PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_CHECKOUT_FLOW: + request_dict.SetKey("upload_card_source", + base::Value("LOCAL_CARD_MIGRATION_CHECKOUT_FLOW")); + break; + case PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_SETTINGS_PAGE: + request_dict.SetKey("upload_card_source", + base::Value("LOCAL_CARD_MIGRATION_SETTINGS_PAGE")); break; default: NOTREACHED(); @@ -391,11 +432,15 @@ class GetUploadDetailsRequest : public PaymentsRequest { return request_content; } - void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { - response->GetString("context_token", &context_token_); - base::DictionaryValue* unowned_legal_message; - if (response->GetDictionary("legal_message", &unowned_legal_message)) - legal_message_ = unowned_legal_message->CreateDeepCopy(); + void ParseResponse(base::Value response) override { + std::string context_token_utf8; + if (TryGetString("context_token", response, &context_token_utf8)) { + context_token_ = base::UTF8ToUTF16(context_token_utf8); + } + + base::Value* dictionary_value = response.FindKey("legal_message"); + if (dictionary_value) + legal_message_ = std::make_unique<base::Value>(dictionary_value->Clone()); } bool IsResponseComplete() override { @@ -414,12 +459,12 @@ class GetUploadDetailsRequest : public PaymentsRequest { std::string app_locale_; base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::DictionaryValue>)> + std::unique_ptr<base::Value>)> callback_; base::string16 context_token_; - std::unique_ptr<base::DictionaryValue> legal_message_; + std::unique_ptr<base::Value> legal_message_; const int billable_service_number_; - PaymentsClient::MigrationSource migration_source_; + PaymentsClient::UploadCardSource upload_card_source_; }; class UploadCardRequest : public PaymentsRequest { @@ -440,41 +485,45 @@ class UploadCardRequest : public PaymentsRequest { } std::string GetRequestContent() override { - base::DictionaryValue request_dict; - request_dict.SetString("encrypted_pan", "__param:s7e_1_pan"); + base::Value request_dict(base::Value::Type::DICTIONARY); + request_dict.SetKey("encrypted_pan", base::Value("__param:s7e_1_pan")); if (!request_details_.cvc.empty()) - request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc"); + request_dict.SetKey("encrypted_cvc", base::Value("__param:s7e_13_cvc")); request_dict.SetKey("risk_data_encoded", BuildRiskDictionary(request_details_.risk_data)); const std::string& app_locale = request_details_.app_locale; - std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); - context->SetString("language_code", app_locale); - context->SetInteger("billable_service", kUploadCardBillableServiceNumber); + base::Value context(base::Value::Type::DICTIONARY); + context.SetKey("language_code", base::Value(app_locale)); + context.SetKey("billable_service", + base::Value(kUploadCardBillableServiceNumber)); if (request_details_.billing_customer_number != 0) { - context->SetKey("customer_context", - BuildCustomerContextDictionary( - request_details_.billing_customer_number)); + context.SetKey("customer_context", + BuildCustomerContextDictionary( + request_details_.billing_customer_number)); } - request_dict.Set("context", std::move(context)); + request_dict.SetKey("context", std::move(context)); if (ShouldUseActiveSignedInAccount()) { - std::unique_ptr<base::DictionaryValue> chrome_user_context( - new base::DictionaryValue()); - chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); - request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + base::Value chrome_user_context(base::Value::Type::DICTIONARY); + chrome_user_context.SetKey("full_sync_enabled", + base::Value(full_sync_enabled_)); + request_dict.SetKey("chrome_user_context", + std::move(chrome_user_context)); } SetStringIfNotEmpty(request_details_.card, CREDIT_CARD_NAME_FULL, - app_locale, "cardholder_name", &request_dict); + app_locale, "cardholder_name", request_dict); - std::unique_ptr<base::ListValue> addresses(new base::ListValue()); + base::Value addresses(base::Value::Type::LIST); for (const AutofillProfile& profile : request_details_.profiles) { - addresses->Append(BuildAddressDictionary(profile, app_locale, true)); + addresses.GetList().push_back( + BuildAddressDictionary(profile, app_locale, true)); } - request_dict.Set("address", std::move(addresses)); + request_dict.SetKey("address", std::move(addresses)); - request_dict.SetString("context_token", request_details_.context_token); + request_dict.SetKey("context_token", + base::Value(request_details_.context_token)); int value = 0; const base::string16 exp_month = request_details_.card.GetInfo( @@ -482,11 +531,11 @@ class UploadCardRequest : public PaymentsRequest { const base::string16 exp_year = request_details_.card.GetInfo( AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale); if (base::StringToInt(exp_month, &value)) - request_dict.SetInteger("expiration_month", value); + request_dict.SetKey("expiration_month", base::Value(value)); if (base::StringToInt(exp_year, &value)) - request_dict.SetInteger("expiration_year", value); + request_dict.SetKey("expiration_year", base::Value(value)); - SetActiveExperiments(request_details_.active_experiments, &request_dict); + SetActiveExperiments(request_details_.active_experiments, request_dict); const base::string16 pan = request_details_.card.GetInfo( AutofillType(CREDIT_CARD_NUMBER), app_locale); @@ -511,8 +560,8 @@ class UploadCardRequest : public PaymentsRequest { return request_content; } - void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { - response->GetString("credit_card_id", &server_id_); + void ParseResponse(base::Value response) override { + TryGetString("credit_card_id", response, &server_id_); } bool IsResponseComplete() override { return true; } @@ -549,39 +598,41 @@ class MigrateCardsRequest : public PaymentsRequest { return "application/x-www-form-urlencoded"; } - // TODO(crbug.com/877281):Refactor DictionaryValue to base::Value std::string GetRequestContent() override { - base::DictionaryValue request_dict; + base::Value request_dict(base::Value::Type::DICTIONARY); request_dict.SetKey("risk_data_encoded", BuildRiskDictionary(request_details_.risk_data)); const std::string& app_locale = request_details_.app_locale; - std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); - context->SetString("language_code", app_locale); - context->SetInteger("billable_service", kMigrateCardsBillableServiceNumber); + base::Value context(base::Value::Type::DICTIONARY); + context.SetKey("language_code", base::Value(app_locale)); + context.SetKey("billable_service", + base::Value(kMigrateCardsBillableServiceNumber)); if (request_details_.billing_customer_number != 0) { - context->SetKey("customer_context", - BuildCustomerContextDictionary( - request_details_.billing_customer_number)); + context.SetKey("customer_context", + BuildCustomerContextDictionary( + request_details_.billing_customer_number)); } - request_dict.Set("context", std::move(context)); + request_dict.SetKey("context", std::move(context)); if (ShouldUseActiveSignedInAccount()) { - std::unique_ptr<base::DictionaryValue> chrome_user_context( - new base::DictionaryValue()); - chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_); - request_dict.Set("chrome_user_context", std::move(chrome_user_context)); + base::Value chrome_user_context(base::Value::Type::DICTIONARY); + chrome_user_context.SetKey("full_sync_enabled", + base::Value(full_sync_enabled_)); + request_dict.SetKey("chrome_user_context", + std::move(chrome_user_context)); } - request_dict.SetString("context_token", request_details_.context_token); + request_dict.SetKey("context_token", + base::Value(request_details_.context_token)); std::string all_pans_data = std::string(); - std::unique_ptr<base::ListValue> migrate_cards(new base::ListValue()); + base::Value migrate_cards(base::Value::Type::LIST); for (size_t index = 0; index < migratable_credit_cards_.size(); ++index) { std::string pan_field_name = GetPanFieldName(index); // Generate credit card dictionary. - migrate_cards->Append(BuildCreditCardDictionary( + migrate_cards.GetList().push_back(BuildCreditCardDictionary( migratable_credit_cards_[index].credit_card(), app_locale, pan_field_name)); // Append pan data to the |all_pans_data|. @@ -589,7 +640,7 @@ class MigrateCardsRequest : public PaymentsRequest { GetAppendPan(migratable_credit_cards_[index].credit_card(), app_locale, pan_field_name); } - request_dict.Set("local_card", std::move(migrate_cards)); + request_dict.SetKey("local_card", std::move(migrate_cards)); std::string json_request; base::JSONWriter::Write(request_dict, &json_request); @@ -600,23 +651,26 @@ class MigrateCardsRequest : public PaymentsRequest { return request_content; } - void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { - const base::ListValue* save_result_list = nullptr; - if (!response->GetList("save_result", &save_result_list)) + void ParseResponse(base::Value response) override { + base::Value* list_ptr = response.FindKey("save_result"); + if (!list_ptr || !list_ptr->is_list()) return; save_result_ = std::make_unique<std::unordered_map<std::string, std::string>>(); - for (size_t i = 0; i < save_result_list->GetSize(); ++i) { - const base::DictionaryValue* single_card_save_result; - if (save_result_list->GetDictionary(i, &single_card_save_result)) { + + for (base::Value& result : list_ptr->GetList()) { + if (result.is_dict()) { std::string unique_id; - single_card_save_result->GetString("unique_id", &unique_id); + TryGetString("unique_id", result, &unique_id); + std::string save_result; - single_card_save_result->GetString("status", &save_result); + TryGetString("status", result, &save_result); + save_result_->insert(std::make_pair(unique_id, save_result)); } } - response->GetString("value_prop_display_text", &display_text_); + + TryGetString("value_prop_display_text", response, &display_text_); } bool IsResponseComplete() override { @@ -716,14 +770,14 @@ void PaymentsClient::GetUploadDetails( const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::DictionaryValue>)> callback, + std::unique_ptr<base::Value>)> callback, const int billable_service_number, - MigrationSource migration_source) { + UploadCardSource upload_card_source) { IssueRequest( std::make_unique<GetUploadDetailsRequest>( addresses, detected_values, active_experiments, account_info_getter_->IsSyncFeatureEnabled(), app_locale, - std::move(callback), billable_service_number, migration_source), + std::move(callback), billable_service_number, upload_card_source), false); } @@ -815,7 +869,7 @@ void PaymentsClient::OnSimpleLoaderComplete( void PaymentsClient::OnSimpleLoaderCompleteInternal(int response_code, const std::string& data) { - std::unique_ptr<base::DictionaryValue> response_dict; + base::Value response_dict(base::Value::Type::DICTIONARY); VLOG(2) << "Got data: " << data; AutofillClient::PaymentsRpcResult result = AutofillClient::SUCCESS; @@ -826,9 +880,9 @@ void PaymentsClient::OnSimpleLoaderCompleteInternal(int response_code, std::string error_code; std::unique_ptr<base::Value> message_value = base::JSONReader::Read(data); if (message_value.get() && message_value->is_dict()) { - response_dict.reset( - static_cast<base::DictionaryValue*>(message_value.release())); - response_dict->GetString("error.code", &error_code); + response_dict = + base::Value::FromUniquePtrValue(std::move(message_value)); + TryGetStringByPath({"error", "code"}, response_dict, &error_code); request_->ParseResponse(std::move(response_dict)); } diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h index eacd1047834..be0bc533999 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.h +++ b/chromium/components/autofill/core/browser/payments/payments_client.h @@ -111,15 +111,24 @@ class PaymentsClient { }; // An enum set in the GetUploadDetailsRequest indicating the source of the - // request. It should stay consistent with the same enum in Google Payments - // server code. - enum MigrationSource { - // Source unknown or unnecessary (such as during single credit card upload). - UNKNOWN_MIGRATION_SOURCE, - // Migration request comes from the checkout flow. - CHECKOUT_FLOW, - // Migration request comes from settings page. - SETTINGS_PAGE, + // request when uploading a card to Google Payments. It should stay consistent + // with the same enum in Google Payments server code. + enum UploadCardSource { + // Source unknown. + UNKNOWN_UPLOAD_CARD_SOURCE, + // Single card is being uploaded from the normal credit card offer-to-save + // prompt during a checkout flow. + UPSTREAM_CHECKOUT_FLOW, + // Single card is being uploaded from chrome://settings/payments. + UPSTREAM_SETTINGS_PAGE, + // Single card is being uploaded after being scanned by OCR. + UPSTREAM_CARD_OCR, + // 1+ cards are being uploaded from a migration request that started during + // a checkout flow. + LOCAL_CARD_MIGRATION_CHECKOUT_FLOW, + // 1+ cards are being uploaded from a migration request that was initiated + // from chrome://settings/payments. + LOCAL_CARD_MIGRATION_SETTINGS_PAGE, }; // |url_loader_factory| is reference counted so it has no lifetime or @@ -160,7 +169,7 @@ class PaymentsClient { // billable service number in the GetUploadDetails request. If the conditions // are met, the legal message will be returned via |callback|. // |active_experiments| is used by Payments server to track requests that were - // triggered by enabled features. |migration_source| is used by Payments + // triggered by enabled features. |upload_card_source| is used by Payments // server metrics to track the source of the request. virtual void GetUploadDetails( const std::vector<AutofillProfile>& addresses, @@ -169,10 +178,10 @@ class PaymentsClient { const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::DictionaryValue>)> callback, + std::unique_ptr<base::Value>)> callback, const int billable_service_number, - MigrationSource migration_source = - MigrationSource::UNKNOWN_MIGRATION_SOURCE); + UploadCardSource upload_card_source = + UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE); // The user has indicated that they would like to upload a card with the given // cvc. This request will fail server-side if a successful call to @@ -197,6 +206,8 @@ class PaymentsClient { void set_url_loader_factory_for_testing( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + bool is_off_the_record() { return is_off_the_record_; } + private: friend class PaymentsClientTest; diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc index d8bfc91b0a6..1b733047735 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc @@ -115,10 +115,9 @@ class PaymentsClientTest : public testing::Test { real_pan_ = real_pan; } - void OnDidGetUploadDetails( - AutofillClient::PaymentsRpcResult result, - const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) { + void OnDidGetUploadDetails(AutofillClient::PaymentsRpcResult result, + const base::string16& context_token, + std::unique_ptr<base::Value> legal_message) { result_ = result; legal_message_ = std::move(legal_message); } @@ -156,14 +155,14 @@ class PaymentsClientTest : public testing::Test { // Issue a GetUploadDetails request. void StartGettingUploadDetails( - PaymentsClient::MigrationSource migration_source = - PaymentsClient::MigrationSource::UNKNOWN_MIGRATION_SOURCE) { + PaymentsClient::UploadCardSource upload_card_source = + PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) { client_->GetUploadDetails( BuildTestProfiles(), kAllDetectableValues, std::vector<const char*>(), "language-LOCALE", base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails, weak_ptr_factory_.GetWeakPtr()), - /*billable_service_number=*/12345, migration_source); + /*billable_service_number=*/12345, upload_card_source); } // Issue an UploadCard request. This requires an OAuth token before starting @@ -233,7 +232,7 @@ class PaymentsClientTest : public testing::Test { AutofillClient::PaymentsRpcResult result_; std::string server_id_; std::string real_pan_; - std::unique_ptr<base::DictionaryValue> legal_message_; + std::unique_ptr<base::Value> legal_message_; std::vector<MigratableCreditCard> migratable_credit_cards_; std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; std::string display_text_; @@ -447,26 +446,61 @@ TEST_F(PaymentsClientTest, } TEST_F(PaymentsClientTest, - GetDetailsIncludesCheckoutFlowMigrationSourceInRequest) { - StartGettingUploadDetails(PaymentsClient::MigrationSource::CHECKOUT_FLOW); + GetDetailsIncludesUpstreamCheckoutFlowUploadCardSourceInRequest) { + StartGettingUploadDetails( + PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW); + + // Verify that the correct upload card source was included in the request. + EXPECT_TRUE(GetUploadData().find("UPSTREAM_CHECKOUT_FLOW") != + std::string::npos); +} + +TEST_F(PaymentsClientTest, + GetDetailsIncludesUpstreamSettingsPageUploadCardSourceInRequest) { + StartGettingUploadDetails( + PaymentsClient::UploadCardSource::UPSTREAM_SETTINGS_PAGE); - // Verify that the correct migration source was included in the request. - EXPECT_TRUE(GetUploadData().find("CHECKOUT_FLOW") != std::string::npos); + // Verify that the correct upload card source was included in the request. + EXPECT_TRUE(GetUploadData().find("UPSTREAM_SETTINGS_PAGE") != + std::string::npos); } TEST_F(PaymentsClientTest, - GetDetailsIncludesSettingsPageMigrationSourceInRequest) { - StartGettingUploadDetails(PaymentsClient::MigrationSource::SETTINGS_PAGE); + GetDetailsIncludesUpstreamCardOcrUploadCardSourceInRequest) { + StartGettingUploadDetails( + PaymentsClient::UploadCardSource::UPSTREAM_CARD_OCR); - // Verify that the correct migration source was included in the request. - EXPECT_TRUE(GetUploadData().find("SETTINGS_PAGE") != std::string::npos); + // Verify that the correct upload card source was included in the request. + EXPECT_TRUE(GetUploadData().find("UPSTREAM_CARD_OCR") != std::string::npos); +} + +TEST_F( + PaymentsClientTest, + GetDetailsIncludesLocalCardMigrationCheckoutFlowUploadCardSourceInRequest) { + StartGettingUploadDetails( + PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_CHECKOUT_FLOW); + + // Verify that the correct upload card source was included in the request. + EXPECT_TRUE(GetUploadData().find("LOCAL_CARD_MIGRATION_CHECKOUT_FLOW") != + std::string::npos); +} + +TEST_F( + PaymentsClientTest, + GetDetailsIncludesLocalCardMigrationSettingsPageUploadCardSourceInRequest) { + StartGettingUploadDetails( + PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_SETTINGS_PAGE); + + // Verify that the correct upload card source was included in the request. + EXPECT_TRUE(GetUploadData().find("LOCAL_CARD_MIGRATION_SETTINGS_PAGE") != + std::string::npos); } -TEST_F(PaymentsClientTest, GetDetailsIncludesUnknownMigrationSourceInRequest) { +TEST_F(PaymentsClientTest, GetDetailsIncludesUnknownUploadCardSourceInRequest) { StartGettingUploadDetails(); - // Verify that the absence of a migration source results in UNKNOWN. - EXPECT_TRUE(GetUploadData().find("UNKNOWN_MIGRATION_SOURCE") != + // Verify that the absence of an upload card source results in UNKNOWN. + EXPECT_TRUE(GetUploadData().find("UNKNOWN_UPLOAD_CARD_SOURCE") != std::string::npos); } diff --git a/chromium/components/autofill/core/browser/payments/payments_request.h b/chromium/components/autofill/core/browser/payments/payments_request.h index 184c9275d6d..e71d554d7de 100644 --- a/chromium/components/autofill/core/browser/payments/payments_request.h +++ b/chromium/components/autofill/core/browser/payments/payments_request.h @@ -28,8 +28,7 @@ class PaymentsRequest { virtual std::string GetRequestContent() = 0; // Parses the required elements of the HTTP response. - virtual void ParseResponse( - std::unique_ptr<base::DictionaryValue> response) = 0; + virtual void ParseResponse(base::Value response) = 0; // Returns true if all of the required elements were successfully retrieved by // a call to ParseResponse. diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.cc b/chromium/components/autofill/core/browser/payments/test_payments_client.cc index 00106156659..8bf0f86a13d 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.cc @@ -30,18 +30,19 @@ void TestPaymentsClient::GetUploadDetails( const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::DictionaryValue>)> callback, + std::unique_ptr<base::Value>)> callback, const int billable_service_number, - PaymentsClient::MigrationSource migration_source) { + PaymentsClient::UploadCardSource upload_card_source) { upload_details_addresses_ = addresses; detected_values_ = detected_values; active_experiments_ = active_experiments; - migration_source_ = migration_source; + billable_service_number_ = billable_service_number; + upload_card_source_ = upload_card_source; std::move(callback).Run(app_locale == "en-US" ? AutofillClient::SUCCESS : AutofillClient::PERMANENT_FAILURE, base::ASCIIToUTF16("this is a context token"), - std::unique_ptr<base::DictionaryValue>(nullptr)); + std::unique_ptr<base::Value>(nullptr)); } void TestPaymentsClient::UploadCard( diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.h b/chromium/components/autofill/core/browser/payments/test_payments_client.h index 231cf000ce8..01e9d008903 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.h +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.h @@ -34,10 +34,10 @@ class TestPaymentsClient : public payments::PaymentsClient { const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::DictionaryValue>)> callback, + std::unique_ptr<base::Value>)> callback, const int billable_service_number, - MigrationSource migration_source = - MigrationSource::UNKNOWN_MIGRATION_SOURCE) override; + UploadCardSource upload_card_source = + UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) override; void UploadCard( const payments::PaymentsClient::UploadRequestDetails& request_details, @@ -65,6 +65,12 @@ class TestPaymentsClient : public payments::PaymentsClient { const std::vector<const char*>& active_experiments_in_request() const { return active_experiments_; } + int billable_service_number_in_request() const { + return billable_service_number_; + } + PaymentsClient::UploadCardSource upload_card_source_in_request() const { + return upload_card_source_; + } private: std::string server_id_; @@ -73,7 +79,8 @@ class TestPaymentsClient : public payments::PaymentsClient { int detected_values_; std::string pan_first_six_; std::vector<const char*> active_experiments_; - PaymentsClient::MigrationSource migration_source_; + int billable_service_number_; + PaymentsClient::UploadCardSource upload_card_source_; std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient); diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc index acdcabd4a7d..7c66782f7a5 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager.cc @@ -13,6 +13,7 @@ #include <string> #include <utility> +#include "base/callback.h" #include "base/feature_list.h" #include "base/i18n/case_conversion.h" #include "base/i18n/timezone.h" @@ -68,27 +69,6 @@ using ::i18n::addressinput::STREET_ADDRESS; // The length of a local profile GUID. const int LOCAL_GUID_LENGTH = 36; -constexpr base::TimeDelta kDisusedProfileTimeDelta = - base::TimeDelta::FromDays(180); -constexpr base::TimeDelta kDisusedCreditCardTimeDelta = - base::TimeDelta::FromDays(180); -constexpr base::TimeDelta kDisusedCreditCardDeletionTimeDelta = - base::TimeDelta::FromDays(395); -constexpr base::TimeDelta kDisusedAddressDeletionTimeDelta = - base::TimeDelta::FromDays(395); - -// Time delta to create test data. -base::TimeDelta DeletableUseDateDelta() { - static base::TimeDelta delta = - kDisusedCreditCardDeletionTimeDelta + base::TimeDelta::FromDays(5); - return delta; -} -base::TimeDelta DeletableExpiryDateDelta() { - static base::TimeDelta delta = - kDisusedCreditCardDeletionTimeDelta + base::TimeDelta::FromDays(45); - return delta; -} - template <typename T> class FormGroupMatchesByGUIDFunctor { public: @@ -161,130 +141,6 @@ static bool CompareVotes(const std::pair<std::string, int>& a, const std::pair<std::string, int>& b) { return a.second < b.second; } - -AutofillProfile CreateBasicTestAddress(const std::string& locale) { - const base::Time use_date = - AutofillClock::Now() - base::TimeDelta::FromDays(20); - AutofillProfile profile; - profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("John McTester"), locale); - profile.SetInfo(COMPANY_NAME, base::UTF8ToUTF16("Test Inc."), locale); - profile.SetInfo(EMAIL_ADDRESS, - base::UTF8ToUTF16("jmctester@fake.chromium.org"), locale); - profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("123 Invented Street"), - locale); - profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Suite A"), locale); - profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Mountain View"), - locale); - profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("California"), locale); - profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("94043"), locale); - profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), locale); - profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0173"), - locale); - profile.set_use_date(use_date); - return profile; -} - -AutofillProfile CreateDisusedTestAddress(const std::string& locale) { - const base::Time use_date = - AutofillClock::Now() - base::TimeDelta::FromDays(185); - AutofillProfile profile; - profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("Polly Disused"), locale); - profile.SetInfo(COMPANY_NAME, - base::UTF8ToUTF16(base::StringPrintf( - "%lld Inc.", static_cast<long long>(use_date.ToTimeT()))), - locale); - profile.SetInfo(EMAIL_ADDRESS, - base::UTF8ToUTF16("polly.disused@fake.chromium.org"), locale); - profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("456 Disused Lane"), - locale); - profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Apt. B"), locale); - profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Austin"), locale); - profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("Texas"), locale); - profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("73301"), locale); - profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), locale); - profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0174"), - locale); - profile.set_use_date(use_date); - return profile; -} - -AutofillProfile CreateDisusedDeletableTestAddress(const std::string& locale) { - const base::Time use_date = - AutofillClock::Now() - base::TimeDelta::FromDays(400); - AutofillProfile profile; - profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("Polly Deletable"), locale); - profile.SetInfo(COMPANY_NAME, - base::UTF8ToUTF16(base::StringPrintf( - "%lld Inc.", static_cast<long long>(use_date.ToTimeT()))), - locale); - profile.SetInfo(EMAIL_ADDRESS, - base::UTF8ToUTF16("polly.deletable@fake.chromium.org"), - locale); - profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("459 Deletable Lane"), - locale); - profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Apt. B"), locale); - profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Austin"), locale); - profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("Texas"), locale); - profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("73301"), locale); - profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), locale); - profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0274"), - locale); - profile.set_use_date(use_date); - return profile; -} - -// Create a card expiring 500 days from now which was last used 10 days ago. -CreditCard CreateBasicTestCreditCard(const std::string& locale) { - const base::Time now = AutofillClock::Now(); - const base::Time use_date = now - base::TimeDelta::FromDays(10); - base::Time::Exploded expiry_date; - (now + base::TimeDelta::FromDays(500)).LocalExplode(&expiry_date); - - CreditCard credit_card; - credit_card.SetInfo(CREDIT_CARD_NAME_FULL, - base::UTF8ToUTF16("Alice Testerson"), locale); - credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("4545454545454545"), - locale); - credit_card.SetExpirationMonth(expiry_date.month); - credit_card.SetExpirationYear(expiry_date.year); - credit_card.set_use_date(use_date); - return credit_card; -} - -CreditCard CreateDisusedTestCreditCard(const std::string& locale) { - const base::Time now = AutofillClock::Now(); - const base::Time use_date = now - base::TimeDelta::FromDays(185); - base::Time::Exploded expiry_date; - (now - base::TimeDelta::FromDays(200)).LocalExplode(&expiry_date); - - CreditCard credit_card; - credit_card.SetInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16("Bob Disused"), - locale); - credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("4111111111111111"), - locale); - credit_card.SetExpirationMonth(expiry_date.month); - credit_card.SetExpirationYear(expiry_date.year); - credit_card.set_use_date(use_date); - return credit_card; -} - -CreditCard CreateDisusedDeletableTestCreditCard(const std::string& locale) { - const base::Time now = AutofillClock::Now(); - const base::Time use_date = now - DeletableUseDateDelta(); - base::Time::Exploded expiry_date; - (now - DeletableExpiryDateDelta()).LocalExplode(&expiry_date); - - CreditCard credit_card; - credit_card.SetInfo(CREDIT_CARD_NAME_FULL, - base::UTF8ToUTF16("Charlie Deletable"), locale); - credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("378282246310005"), - locale); - credit_card.SetExpirationMonth(expiry_date.month); - credit_card.SetExpirationYear(expiry_date.year); - credit_card.set_use_date(use_date); - return credit_card; -} - } // namespace // Helper class to abstract the switching between account and profile storage @@ -400,7 +256,8 @@ class PersonalDatabaseHelper }; PersonalDataManager::PersonalDataManager(const std::string& app_locale) - : app_locale_(app_locale) { + : app_locale_(app_locale), + test_data_creator_(kDisusedDataModelDeletionTimeDelta, app_locale_) { database_helper_ = std::make_unique<PersonalDatabaseHelper>(this); } @@ -447,6 +304,11 @@ void PersonalDataManager::Init( if (!database_helper_->GetLocalDatabase()) { return; } + + database_helper_->GetLocalDatabase()->SetAutofillProfileChangedCallback( + base::BindRepeating(&PersonalDataManager::OnAutofillProfileChanged, + weak_factory_.GetWeakPtr())); + LoadProfiles(); LoadCreditCards(); LoadPaymentsCustomerData(); @@ -454,7 +316,7 @@ void PersonalDataManager::Init( // Check if profile cleanup has already been performed this major version. is_autofill_profile_cleanup_pending_ = pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) >= - atoi(version_info::GetVersionNumber().c_str()); + CHROME_VERSION_MAJOR; DVLOG(1) << "Autofill profile cleanup " << (is_autofill_profile_cleanup_pending_ ? "needs to be" : "has already been") @@ -576,7 +438,7 @@ void PersonalDataManager::OnWebDataServiceRequestDone( // If the user has a saved unmasked server card and the experiment is // disabled, force mask all cards back to the unsaved state. - if (!OfferStoreUnmaskedCards()) + if (!OfferStoreUnmaskedCards(is_off_the_record_)) ResetFullServerCards(); } break; @@ -621,12 +483,16 @@ void PersonalDataManager::OnWebDataServiceRequestDone( } is_data_loaded_ = true; + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " refresh is done, notifying PersonalDataChanged"; NotifyPersonalDataChanged(); } } void PersonalDataManager::AutofillMultipleChanged() { has_synced_new_data_ = true; + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " has synced new data, refreshing"; Refresh(); } @@ -764,18 +630,20 @@ void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) { AutofillProfile* profile = GetProfileByGUID(data_model.guid()); if (profile) { - profile->RecordAndLogUse(); - if (profile->record_type() == AutofillProfile::LOCAL_PROFILE) { - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile); + // We can't make the change directly on the web_profiles_, the update + // should happen in the database first. + AutofillProfile updated_profile(*profile); + updated_profile.RecordAndLogUse(); + UpdateProfileInDB(updated_profile); } else if (profile->record_type() == AutofillProfile::SERVER_PROFILE) { + profile->RecordAndLogUse(); // TODO(crbug.com/864519): Update this once addresses support account // storage, and also use the server database. database_helper_->GetLocalDatabase()->UpdateServerAddressMetadata( *profile); + Refresh(); } - - Refresh(); } } @@ -786,39 +654,16 @@ void PersonalDataManager::AddProfile(const AutofillProfile& profile) { if (is_off_the_record_) return; - if (profile.IsEmpty(app_locale_)) - return; - - // Don't add an existing profile. - if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid())) - return; - if (!database_helper_->GetLocalDatabase()) return; - // Don't add a duplicate. - if (FindByContents(web_profiles_, profile)) - return; - - // Add the new profile to the web database. - database_helper_->GetLocalDatabase()->AddAutofillProfile(profile); - - // Refresh our local cache and send notifications to observers. - Refresh(); + AddProfileToDB(profile); } void PersonalDataManager::UpdateProfile(const AutofillProfile& profile) { if (is_off_the_record_) return; - AutofillProfile* existing_profile = GetProfileByGUID(profile.guid()); - if (!existing_profile) - return; - - // Don't overwrite the origin for a profile that is already stored. - if (existing_profile->EqualsSansOrigin(profile)) - return; - if (profile.IsEmpty(app_locale_)) { RemoveByGUID(profile.guid()); return; @@ -827,11 +672,7 @@ void PersonalDataManager::UpdateProfile(const AutofillProfile& profile) { if (!database_helper_->GetLocalDatabase()) return; - // Make the update. - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); - - // Refresh our local cache and send notifications to observers. - Refresh(); + UpdateProfileInDB(profile); } AutofillProfile* PersonalDataManager::GetProfileByGUID( @@ -1065,9 +906,9 @@ void PersonalDataManager::SetSyncServiceForTest( } void PersonalDataManager:: - RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne( + RemoveAutofillProfileByGUIDAndBlankCreditCardReference( const std::string& guid) { - database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid); + RemoveProfileFromDB(guid); // Reset the billing_address_id of any card that refered to this profile. for (CreditCard* credit_card : GetCreditCards()) { @@ -1090,23 +931,17 @@ void PersonalDataManager::RemoveByGUID(const std::string& guid) { if (is_off_the_record_) return; - bool is_credit_card = FindByGUID<CreditCard>(local_credit_cards_, guid); - bool is_profile = - !is_credit_card && FindByGUID<AutofillProfile>(web_profiles_, guid); - if (!is_credit_card && !is_profile) - return; - if (!database_helper_->GetLocalDatabase()) return; + bool is_credit_card = FindByGUID<CreditCard>(local_credit_cards_, guid); if (is_credit_card) { database_helper_->GetLocalDatabase()->RemoveCreditCard(guid); + // Refresh our local cache and send notifications to observers. + Refresh(); } else { - RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(guid); + RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid); } - - // Refresh our local cache and send notifications to observers. - Refresh(); } CreditCard* PersonalDataManager::GetCreditCardByGUID(const std::string& guid) { @@ -1128,7 +963,7 @@ CreditCard* PersonalDataManager::GetCreditCardByNumber( } void PersonalDataManager::GetNonEmptyTypes( - ServerFieldTypeSet* non_empty_types) { + ServerFieldTypeSet* non_empty_types) const { for (AutofillProfile* profile : GetProfiles()) profile->GetNonEmptyTypes(app_locale_, non_empty_types); for (CreditCard* card : GetCreditCards()) @@ -1147,11 +982,11 @@ std::vector<AutofillProfile*> PersonalDataManager::GetProfiles() const { return result; } -void PersonalDataManager::UpdateProfilesValidityMapsIfNeeded( +void PersonalDataManager::UpdateProfilesServerValidityMapsIfNeeded( const std::vector<AutofillProfile*>& profiles) { - if (!profile_validities_need_update_) + if (!profiles_server_validities_need_update_) return; - profile_validities_need_update_ = false; + profiles_server_validities_need_update_ = false; for (auto* profile : profiles) { profile->UpdateServerValidityMap(GetProfileValidityByGUID(profile->guid())); } @@ -1159,6 +994,10 @@ void PersonalDataManager::UpdateProfilesValidityMapsIfNeeded( void PersonalDataManager::UpdateClientValidityStates( const std::vector<AutofillProfile*>& profiles) { + if (!base::FeatureList::IsEnabled( + autofill::features::kAutofillProfileClientValidation)) + return; + if (!client_profile_validator_) return; @@ -1166,18 +1005,18 @@ void PersonalDataManager::UpdateClientValidityStates( // keep up with the validation logic. bool update_validation = pref_service_->GetInteger(prefs::kAutofillLastVersionValidated) < - atoi(version_info::GetVersionNumber().c_str()); + CHROME_VERSION_MAJOR; for (const auto* profile : profiles) { if (!profile->is_client_validity_states_updated() || update_validation) { client_profile_validator_->StartProfileValidation( profile, base::BindOnce(&PersonalDataManager::OnValidated, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); } } // Set the pref to the current major version if already not set. if (update_validation) pref_service_->SetInteger(prefs::kAutofillLastVersionValidated, - atoi(version_info::GetVersionNumber().c_str())); + CHROME_VERSION_MAJOR); } std::vector<AutofillProfile*> PersonalDataManager::GetServerProfiles() const { @@ -1230,7 +1069,6 @@ void PersonalDataManager::Refresh() { LoadProfiles(); LoadCreditCards(); LoadPaymentsCustomerData(); - profile_validities_need_update_ = true; } std::vector<AutofillProfile*> PersonalDataManager::GetProfilesToSuggest() @@ -1305,12 +1143,12 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions( if (base::FeatureList::IsEnabled( features::kAutofillSuppressDisusedAddresses)) { const base::Time min_last_used = - AutofillClock::Now() - kDisusedProfileTimeDelta; + AutofillClock::Now() - kDisusedDataModelTimeDelta; suggestion_selection::RemoveProfilesNotUsedSinceTimestamp( min_last_used, &sorted_profiles); } // We need the updated information on the validity states of the profiles. - UpdateProfilesValidityMapsIfNeeded(sorted_profiles); + UpdateProfilesServerValidityMapsIfNeeded(sorted_profiles); MaybeRemoveInvalidSuggestions(type, &sorted_profiles); } @@ -1414,7 +1252,7 @@ std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( base::FeatureList::IsEnabled( features::kAutofillSuppressDisusedCreditCards)) { const base::Time min_last_used = - AutofillClock::Now() - kDisusedCreditCardTimeDelta; + AutofillClock::Now() - kDisusedDataModelTimeDelta; RemoveExpiredCreditCardsNotUsedSinceTimestamp(AutofillClock::Now(), min_last_used, &cards); } @@ -1501,20 +1339,13 @@ void PersonalDataManager::SetPrefService(PrefService* pref_service) { } void PersonalDataManager::ClearProfileNonSettingsOrigins() { - bool has_updated = false; - for (AutofillProfile* profile : GetProfiles()) { if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) { profile->set_origin(std::string()); - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile); - has_updated = true; + UpdateProfileInDB(*profile); } } - // Refresh the local cache and send notifications to observers if a changed - // was made. - if (has_updated) - Refresh(); } void PersonalDataManager::ClearCreditCardNonSettingsOrigins() { @@ -1542,7 +1373,6 @@ void PersonalDataManager::MoveJapanCityToStreetAddress() { if (pref_service_->GetBoolean(prefs::kAutofillJapanCityFieldMigrated)) return; - bool has_updated = false; base::string16 japan_country_code = base::ASCIIToUTF16("JP"); base::string16 line_separator = base::ASCIIToUTF16("\n"); for (AutofillProfile* profile : GetProfiles()) { @@ -1558,16 +1388,10 @@ void PersonalDataManager::MoveJapanCityToStreetAddress() { profile->SetRawInfo(ADDRESS_HOME_CITY, base::string16()); // Make the update. - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile); - has_updated = true; + UpdateProfileInDB(*profile); } } - // Refresh the local cache and send notifications to observers if a change was - // made. - if (has_updated) - Refresh(); - // Set the pref so that this migration is never run again. pref_service_->SetBoolean(prefs::kAutofillJapanCityFieldMigrated, true); } @@ -1590,7 +1414,7 @@ const ProfileValidityMap& PersonalDataManager::GetProfileValidityByGUID( const std::string& guid) { static const ProfileValidityMap& empty_validity_map = ProfileValidityMap(); if (!synced_profile_validity_) { - profile_validities_need_update_ = true; + profiles_server_validities_need_update_ = true; synced_profile_validity_ = std::make_unique<UserProfileValidityMap>(); if (!synced_profile_validity_->ParseFromString( ::autofill::prefs::GetAllProfilesValidityMapsEncodedString( @@ -1607,8 +1431,7 @@ const ProfileValidityMap& PersonalDataManager::GetProfileValidityByGUID( return empty_validity_map; } -// TODO(crbug.com/618448): Refactor MergeProfile to not depend on class -// variables. +// static std::string PersonalDataManager::MergeProfile( const AutofillProfile& new_profile, std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, @@ -1744,31 +1567,25 @@ void PersonalDataManager::DedupeCreditCardToSuggest( void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) { if (is_off_the_record_) return; - - // Remove empty profiles from input. - base::EraseIf(*profiles, IsEmptyFunctor<AutofillProfile>(app_locale_)); - if (!database_helper_->GetLocalDatabase()) return; + ClearOnGoingProfileChanges(); + // Any profiles that are not in the new profile list should be removed from - // the web database. + // the web database for (const auto& it : web_profiles_) { if (!FindByGUID<AutofillProfile>(*profiles, it->guid())) - database_helper_->GetLocalDatabase()->RemoveAutofillProfile(it->guid()); - } - - // Update the web database with the existing profiles. - for (const AutofillProfile& it : *profiles) { - if (FindByGUID<AutofillProfile>(web_profiles_, it.guid())) - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(it); + RemoveProfileFromDB(it->guid()); } - // Add the new profiles to the web database. Don't add a duplicate. + // Update the web database with the new and existing profiles. for (const AutofillProfile& it : *profiles) { - if (!FindByGUID<AutofillProfile>(web_profiles_, it.guid()) && - !FindByContents(web_profiles_, it)) - database_helper_->GetLocalDatabase()->AddAutofillProfile(it); + if (FindByGUID<AutofillProfile>(web_profiles_, it.guid())) { + UpdateProfileInDB(it); + } else { + AddProfileToDB(it); + } } // Copy in the new profiles. @@ -1776,9 +1593,6 @@ void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) { for (const AutofillProfile& it : *profiles) { web_profiles_.push_back(std::make_unique<AutofillProfile>(it)); } - - // Refresh our local cache and send notifications to observers. - Refresh(); } void PersonalDataManager::SetCreditCards( @@ -1914,8 +1728,13 @@ std::string PersonalDataManager::SaveImportedProfile( } void PersonalDataManager::NotifyPersonalDataChanged() { - for (PersonalDataManagerObserver& observer : observers_) + bool profile_changes_are_on_going = ProfileChangesAreOnGoing(); + for (PersonalDataManagerObserver& observer : observers_) { observer.OnPersonalDataChanged(); + if (!profile_changes_are_on_going) { + observer.OnPersonalDataFinishedProfileTasks(); + } + } // If new data was synced, try to convert new server profiles and update // server cards. @@ -1979,7 +1798,7 @@ void PersonalDataManager::LogStoredProfileMetrics() const { const base::TimeDelta time_since_last_use = now - profile->use_date(); AutofillMetrics::LogStoredProfileDaysSinceLastUse( time_since_last_use.InDays()); - if (time_since_last_use > kDisusedProfileTimeDelta) + if (time_since_last_use > kDisusedDataModelTimeDelta) ++num_disused_profiles; } AutofillMetrics::LogStoredProfileDisusedCount(num_disused_profiles); @@ -1993,7 +1812,7 @@ void PersonalDataManager::LogStoredProfileMetrics() const { void PersonalDataManager::LogStoredCreditCardMetrics() const { if (!has_logged_stored_credit_card_metrics_) { AutofillMetrics::LogStoredCreditCardMetrics( - local_credit_cards_, server_credit_cards_, kDisusedProfileTimeDelta); + local_credit_cards_, server_credit_cards_, kDisusedDataModelTimeDelta); // Only log this info once per chrome user profile load. has_logged_stored_credit_card_metrics_ = true; @@ -2046,7 +1865,7 @@ void PersonalDataManager::EnableAutofillPrefChanged() { Refresh(); } -bool PersonalDataManager::IsKnownCard(const CreditCard& credit_card) { +bool PersonalDataManager::IsKnownCard(const CreditCard& credit_card) const { const auto stripped_pan = CreditCard::StripSeparators(credit_card.number()); for (const auto& card : local_credit_cards_) { if (stripped_pan == CreditCard::StripSeparators(card->number())) @@ -2131,6 +1950,51 @@ void PersonalDataManager::OnUserAcceptedCardsFromAccountOption() { /*opted_in=*/true); } +void PersonalDataManager::OnAutofillProfileChanged( + const AutofillProfileDeepChange& change) { + const auto& guid = change.key(); + const auto& change_type = change.type(); + const auto& profile = change.profile(); + + DCHECK(guid == profile.guid()); + + // Happens only in tests. + if (!ProfileChangesAreOnGoing(guid)) { + DVLOG(1) << "Received an unexpected response from database."; + return; + } + + const auto* existing_profile = GetProfileByGUID(guid); + const bool profile_exists = (existing_profile != nullptr); + switch (change_type) { + case AutofillProfileChange::ADD: + profiles_server_validities_need_update_ = true; + if (!profile_exists && !FindByContents(web_profiles_, profile)) { + web_profiles_.push_back(std::make_unique<AutofillProfile>(profile)); + } + break; + case AutofillProfileChange::UPDATE: + profiles_server_validities_need_update_ = true; + if (profile_exists && + !existing_profile->EqualsForUpdatePurposes(profile)) { + web_profiles_.erase( + FindElementByGUID<AutofillProfile>(web_profiles_, guid)); + web_profiles_.push_back(std::make_unique<AutofillProfile>(profile)); + } + break; + case AutofillProfileChange::REMOVE: + if (profile_exists) { + web_profiles_.erase( + FindElementByGUID<AutofillProfile>(web_profiles_, guid)); + } + break; + default: + NOTREACHED(); + } + + OnProfileChangeDone(guid); +} + void PersonalDataManager::LogServerCardLinkClicked() const { AutofillMetrics::LogServerCardLinkClicked(GetSyncSigninState()); } @@ -2249,33 +2113,39 @@ bool PersonalDataManager::ApplyDedupingRoutine() { } // Check if de-duplication has already been performed this major version. - int current_major_version = atoi(version_info::GetVersionNumber().c_str()); if (pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) >= - current_major_version) { + CHROME_VERSION_MAJOR) { DVLOG(1) << "Autofill profile de-duplication already performed for this version"; return false; } DVLOG(1) << "Starting autofill profile de-duplication."; - std::unordered_set<AutofillProfile*> profiles_to_delete; + std::unordered_set<std::string> profiles_to_delete; profiles_to_delete.reserve(web_profiles_.size()); // Create the map used to update credit card's billing addresses after the // dedupe. std::unordered_map<std::string, std::string> guids_merge_map; - DedupeProfiles(&web_profiles_, &profiles_to_delete, &guids_merge_map); + // The changes can't happen directly on the web_profiles_, but need to be + // updated in the database at first, and then updated on the web_profiles_. + // Therefore, we need a copy of web_profiles_ to keep track of the changes. + std::vector<std::unique_ptr<AutofillProfile>> new_profiles; + for (const auto& it : web_profiles_) { + new_profiles.push_back(std::make_unique<AutofillProfile>(*(it.get()))); + } + + DedupeProfiles(&new_profiles, &profiles_to_delete, &guids_merge_map); // Apply the profile changes to the database. - for (const auto& profile : web_profiles_) { - // If the profile was set to be deleted, remove it from the database. - if (profiles_to_delete.count(profile.get())) { - database_helper_->GetLocalDatabase()->RemoveAutofillProfile( - profile->guid()); + for (const auto& profile : new_profiles) { + // If the profile was set to be deleted, remove it from the database, + // otherwise update it. + if (profiles_to_delete.count(profile->guid())) { + RemoveProfileFromDB(profile->guid()); } else { - // Otherwise, update the profile in the database. - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile); + UpdateProfileInDB(*(profile.get())); } } @@ -2283,17 +2153,13 @@ bool PersonalDataManager::ApplyDedupingRoutine() { // Set the pref to the current major version. pref_service_->SetInteger(prefs::kAutofillLastVersionDeduped, - current_major_version); - - // Refresh the local cache and send notifications to observers. - Refresh(); - + CHROME_VERSION_MAJOR); return true; } void PersonalDataManager::DedupeProfiles( std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, - std::unordered_set<AutofillProfile*>* profiles_to_delete, + std::unordered_set<std::string>* profiles_to_delete, std::unordered_map<std::string, std::string>* guids_merge_map) const { AutofillMetrics::LogNumberOfProfilesConsideredForDedupe( existing_profiles->size()); @@ -2321,7 +2187,7 @@ void PersonalDataManager::DedupeProfiles( // If the profile was set to be deleted, skip it. It has already been // merged into another profile. - if (profiles_to_delete->count(profile_to_merge)) + if (profiles_to_delete->count(profile_to_merge->guid())) continue; // If we have reached the verified profiles, stop trying to merge. Verified @@ -2335,7 +2201,7 @@ void PersonalDataManager::DedupeProfiles( AutofillProfile* existing_profile = (*existing_profiles)[j].get(); // Don't try to merge a profile that was already set for deletion. - if (profiles_to_delete->count(existing_profile)) + if (profiles_to_delete->count(existing_profile->guid())) continue; // Move on if the profiles are not mergeable. @@ -2355,7 +2221,7 @@ void PersonalDataManager::DedupeProfiles( // Since |profile_to_merge| was a duplicate of |existing_profile| // and was merged successfully, it can now be deleted. - profiles_to_delete->insert(profile_to_merge); + profiles_to_delete->insert(profile_to_merge->guid()); // Now try to merge the new resulting profile with the rest of the // existing profiles. @@ -2417,6 +2283,7 @@ void PersonalDataManager::UpdateCardsBillingAddressReference( *credit_card); } } + Refresh(); } void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() { @@ -2454,7 +2321,9 @@ void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() { UpdateCardsBillingAddressReference(guids_merge_map); // Force a reload of the profiles and cards. - Refresh(); + // TODO(crbug.com/915229): Remove once the investigation is over. + if (has_converted_addresses) + DLOG(WARNING) << this << " conversion of addresses done"; } } @@ -2465,6 +2334,11 @@ bool PersonalDataManager::ConvertWalletAddressesToLocalProfiles( // If the full Sync feature isn't enabled, then do NOT convert any Wallet // addresses to local ones. if (!IsSyncFeatureEnabled()) { + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this + << " not converting as sync feature is not enabled, probably " + "due to sync_service_ being " + << sync_service_; return false; } @@ -2478,8 +2352,12 @@ bool PersonalDataManager::ConvertWalletAddressesToLocalProfiles( if (!wallet_address->has_converted()) { // Try to merge the server address into a similar local profile, or create // a new local profile if no similar profile is found. - std::string address_guid = - MergeServerAddressesIntoProfiles(*wallet_address, local_profiles); + // TODO(crbug.com/864519): Use GetAccountInfoForPaymentsServer instead of + // going to IdentityManager directly. This will be necessary to properly + // support Wallet addresses with Butter. + std::string address_guid = MergeServerAddressesIntoProfiles( + *wallet_address, local_profiles, app_locale_, + identity_manager_->GetPrimaryAccountInfo().email); // Update the map to transfer the billing address relationship from the // server address to the converted/merged local profile. @@ -2487,6 +2365,8 @@ bool PersonalDataManager::ConvertWalletAddressesToLocalProfiles( // Update the wallet addresses metadata to record the conversion. wallet_address->set_has_converted(true); + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " converting address " << *wallet_address; database_helper_->GetServerDatabase()->UpdateServerAddressMetadata( *wallet_address); @@ -2540,16 +2420,19 @@ bool PersonalDataManager::UpdateWalletCardsAlreadyConvertedBillingAddresses( return should_update_cards; } -// TODO(crbug.com/687975): Reuse MergeProfiles in this function. +// TODO(crbug.com/687975): Reuse MergeProfile in this function. +// static std::string PersonalDataManager::MergeServerAddressesIntoProfiles( const AutofillProfile& server_address, - std::vector<AutofillProfile>* existing_profiles) const { + std::vector<AutofillProfile>* existing_profiles, + const std::string& app_locale, + const std::string& primary_account_email) { // If there is already a local profile that is very similar, merge in any // missing values. Only merge with the first match. - AutofillProfileComparator comparator(app_locale_); + AutofillProfileComparator comparator(app_locale); for (auto& local_profile : *existing_profiles) { if (comparator.AreMergeable(server_address, local_profile) && - local_profile.SaveAdditionalInfo(server_address, app_locale_)) { + local_profile.SaveAdditionalInfo(server_address, app_locale)) { local_profile.set_modification_date(AutofillClock::Now()); AutofillMetrics::LogWalletAddressConversionType( AutofillMetrics::CONVERTED_ADDRESS_MERGED); @@ -2566,11 +2449,7 @@ std::string PersonalDataManager::MergeServerAddressesIntoProfiles( // Wallet addresses don't have an email address, use the one from the // currently signed-in account. - // TODO(crbug.com/864519): Use GetAccountInfoForPaymentsServer instead of - // going to IdentityManager directly. This will be necessary to properly - // support Wallet addresses with Butter. - base::string16 email = - base::UTF8ToUTF16(identity_manager_->GetPrimaryAccountInfo().email); + base::string16 email = base::UTF8ToUTF16(primary_account_email); if (!email.empty()) existing_profiles->back().SetRawInfo(EMAIL_ADDRESS, email); @@ -2580,40 +2459,6 @@ std::string PersonalDataManager::MergeServerAddressesIntoProfiles( return server_address.guid(); } -void PersonalDataManager::MaybeCreateTestAddresses() { - if (has_created_test_addresses_) - return; - - has_created_test_addresses_ = true; - if (!base::FeatureList::IsEnabled(features::kAutofillCreateDataForTest)) - return; - - AddProfile(CreateBasicTestAddress(app_locale_)); - AddProfile(CreateDisusedTestAddress(app_locale_)); - AddProfile(CreateDisusedDeletableTestAddress(app_locale_)); -} - -void PersonalDataManager::MaybeCreateTestCreditCards() { - if (has_created_test_credit_cards_) - return; - - has_created_test_credit_cards_ = true; - if (!base::FeatureList::IsEnabled(features::kAutofillCreateDataForTest)) - return; - - AddCreditCard(CreateBasicTestCreditCard(app_locale_)); - AddCreditCard(CreateDisusedTestCreditCard(app_locale_)); - AddCreditCard(CreateDisusedDeletableTestCreditCard(app_locale_)); -} - -bool PersonalDataManager::IsCreditCardDeletable(CreditCard* card) { - const base::Time deletion_threshold = - AutofillClock::Now() - kDisusedCreditCardDeletionTimeDelta; - - return card->use_date() < deletion_threshold && - card->IsExpired(deletion_threshold); -} - bool PersonalDataManager::DeleteDisusedCreditCards() { if (!base::FeatureList::IsEnabled( features::kAutofillDeleteDisusedCreditCards)) { @@ -2630,7 +2475,7 @@ bool PersonalDataManager::DeleteDisusedCreditCards() { std::vector<std::string> guid_to_delete; for (CreditCard* card : cards) { - if (IsCreditCardDeletable(card)) { + if (card->IsDeletable()) { guid_to_delete.push_back(card->guid()); } } @@ -2650,17 +2495,6 @@ bool PersonalDataManager::DeleteDisusedCreditCards() { return true; } -bool PersonalDataManager::IsAddressDeletable( - AutofillProfile* profile, - std::unordered_set<std::string> const& used_billing_address_guids) { - const base::Time deletion_threshold = - AutofillClock::Now() - kDisusedAddressDeletionTimeDelta; - - return profile->use_date() < deletion_threshold && !profile->IsVerified() && - used_billing_address_guids.find(profile->guid()) == - used_billing_address_guids.end(); -} - bool PersonalDataManager::DeleteDisusedAddresses() { if (!base::FeatureList::IsEnabled( features::kAutofillDeleteDisusedAddresses)) { @@ -2678,14 +2512,15 @@ bool PersonalDataManager::DeleteDisusedAddresses() { std::unordered_set<std::string> used_billing_address_guids; for (CreditCard* card : GetCreditCards()) { - if (!IsCreditCardDeletable(card)) { + if (!card->IsDeletable()) { used_billing_address_guids.insert(card->billing_address_id()); } } std::vector<std::string> guids_to_delete; for (AutofillProfile* profile : profiles) { - if (IsAddressDeletable(profile, used_billing_address_guids)) { + if (profile->IsDeletable() && + !used_billing_address_guids.count(profile->guid())) { guids_to_delete.push_back(profile->guid()); } } @@ -2693,7 +2528,7 @@ bool PersonalDataManager::DeleteDisusedAddresses() { size_t num_deleted_addresses = guids_to_delete.size(); for (auto const guid : guids_to_delete) { - RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(guid); + RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid); } if (num_deleted_addresses > 0) { @@ -2706,23 +2541,156 @@ bool PersonalDataManager::DeleteDisusedAddresses() { } void PersonalDataManager::ApplyAddressFixesAndCleanups() { - RemoveOrphanAutofillTableRows(); // One-time fix, otherwise NOP. - ApplyDedupingRoutine(); // Once per major version, otherwise NOP. + // One-time fix, otherwise NOP. + RemoveOrphanAutofillTableRows(); + + // Once per major version, otherwise NOP. + ApplyDedupingRoutine(); + DeleteDisusedAddresses(); - MaybeCreateTestAddresses(); // Once per user profile startup. - ClearProfileNonSettingsOrigins(); // Ran everytime it is called. - MoveJapanCityToStreetAddress(); // One-time fix, otherwise NOP. + + // If feature AutofillCreateDataForTest is enabled, and once per user profile + // startup. + test_data_creator_.MaybeAddTestProfiles(base::BindRepeating( + &PersonalDataManager::AddProfile, base::Unretained(this))); + + // Ran everytime it is called. + ClearProfileNonSettingsOrigins(); + + // One-time fix, otherwise NOP. + MoveJapanCityToStreetAddress(); } void PersonalDataManager::ApplyCardFixesAndCleanups() { DeleteDisusedCreditCards(); - MaybeCreateTestCreditCards(); // Once per user profile startup. - ClearCreditCardNonSettingsOrigins(); // Ran everytime it is called. + + // If feature AutofillCreateDataForTest is enabled, and once per user profile + // startup. + test_data_creator_.MaybeAddTestCreditCards(base::BindRepeating( + &PersonalDataManager::AddCreditCard, base::Unretained(this))); + + // Ran everytime it is called. + ClearCreditCardNonSettingsOrigins(); } void PersonalDataManager::ResetProfileValidity() { synced_profile_validity_.reset(); - profile_validities_need_update_ = true; + profiles_server_validities_need_update_ = true; +} + +void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile) { + // Add the new profile to the web database. + if (profile.IsEmpty(app_locale_)) { + NotifyPersonalDataChanged(); + return; + } + + if (!ProfileChangesAreOnGoing(profile.guid())) { + if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()) || + FindByContents(web_profiles_, profile)) { + NotifyPersonalDataChanged(); + return; + } + database_helper_->GetLocalDatabase()->AddAutofillProfile(profile); + } + ongoing_profile_changes_[profile.guid()].push( + AutofillProfileDeepChange(AutofillProfileChange::ADD, profile)); +} + +void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile) { + if (!ProfileChangesAreOnGoing(profile.guid())) { + const auto* existing_profile = GetProfileByGUID(profile.guid()); + bool profile_exists = (existing_profile != nullptr); + if (profile_exists && !existing_profile->EqualsForUpdatePurposes(profile)) { + database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); + } else { + NotifyPersonalDataChanged(); + return; + } + } + + ongoing_profile_changes_[profile.guid()].push( + AutofillProfileDeepChange(AutofillProfileChange::UPDATE, profile)); +} + +void PersonalDataManager::RemoveProfileFromDB(const std::string& guid) { + bool profile_exists = FindByGUID<AutofillProfile>(web_profiles_, guid); + if (!profile_exists && !ProfileChangesAreOnGoing(guid)) { + NotifyPersonalDataChanged(); + return; + } + + if (!ProfileChangesAreOnGoing(guid)) + database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid); + ongoing_profile_changes_[guid].push( + AutofillProfileDeepChange(AutofillProfileChange::REMOVE, guid)); +} + +void PersonalDataManager::HandleNextProfileChange(const std::string& guid) { + if (!ProfileChangesAreOnGoing(guid)) + return; + + const auto& change = ongoing_profile_changes_[guid].front(); + const auto& change_type = change.type(); + const auto* existing_profile = GetProfileByGUID(guid); + const bool profile_exists = (existing_profile != nullptr); + const auto& profile = ongoing_profile_changes_[guid].front().profile(); + + DCHECK(guid == profile.guid()); + + if (change_type == AutofillProfileChange::REMOVE) { + if (!profile_exists) { + OnProfileChangeDone(guid); + return; + } + database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid); + return; + } + + if (change_type == AutofillProfileChange::ADD) { + if (profile_exists || FindByContents(web_profiles_, profile)) { + OnProfileChangeDone(guid); + return; + } + database_helper_->GetLocalDatabase()->AddAutofillProfile(profile); + return; + } + + if (!profile_exists || existing_profile->EqualsForUpdatePurposes(profile)) { + OnProfileChangeDone(guid); + return; + } + database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); +} + +bool PersonalDataManager::ProfileChangesAreOnGoing(const std::string& guid) { + return ongoing_profile_changes_.find(guid) != + ongoing_profile_changes_.end() && + !ongoing_profile_changes_[guid].empty(); +} + +bool PersonalDataManager::ProfileChangesAreOnGoing() { + for (auto task : ongoing_profile_changes_) { + if (ProfileChangesAreOnGoing(task.first)) { + return true; + } + } + return false; +} + +void PersonalDataManager::OnProfileChangeDone(const std::string& guid) { + ongoing_profile_changes_[guid].pop(); + + if (!ProfileChangesAreOnGoing()) { + Refresh(); + } else { + NotifyPersonalDataChanged(); + HandleNextProfileChange(guid); + } +} + +void PersonalDataManager::ClearOnGoingProfileChanges() { + ongoing_profile_changes_.clear(); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h index 5e559bcbbac..754305dd365 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.h +++ b/chromium/components/autofill/core/browser/personal_data_manager.h @@ -27,6 +27,8 @@ #include "components/autofill/core/browser/proto/server.pb.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/browser/sync_utils.h" +#include "components/autofill/core/browser/test_data_creator.h" +#include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" #include "components/history/core/browser/history_service_observer.h" @@ -125,17 +127,6 @@ class PersonalDataManager : public KeyedService, bool IsSyncFeatureEnabled() const override; // GaiaCookieManagerService::Observer: - void OnAddAccountToCookieCompleted( - const std::string& account_id, - const GoogleServiceAuthError& error) override {} - void OnSetAccountsInCookieCompleted( - const GoogleServiceAuthError& error) override {} - void OnLogOutAccountsFromCookieCompleted( - const GoogleServiceAuthError& error) override {} - void OnGaiaAccountsInCookieUpdated( - const std::vector<gaia::ListedAccount>& accounts, - const std::vector<gaia::ListedAccount>& signed_out_accounts, - const GoogleServiceAuthError& error) override {} void OnGaiaCookieDeletedByUserAction() override; // Returns the current sync status. @@ -239,7 +230,7 @@ class PersonalDataManager : public KeyedService, virtual CreditCard* GetCreditCardByNumber(const std::string& number); // Gets the field types availabe in the stored address and credit card data. - void GetNonEmptyTypes(ServerFieldTypeSet* non_empty_types); + void GetNonEmptyTypes(ServerFieldTypeSet* non_empty_types) const; // Returns whether the personal data has been loaded from the web database. virtual bool IsDataLoaded() const; @@ -261,7 +252,7 @@ class PersonalDataManager : public KeyedService, virtual PaymentsCustomerData* GetPaymentsCustomerData() const; // Updates the validity states of |profiles| according to server validity map. - void UpdateProfilesValidityMapsIfNeeded( + void UpdateProfilesServerValidityMapsIfNeeded( const std::vector<AutofillProfile*>& profiles); // Updates the validity states of |profiles| according to client side @@ -336,7 +327,7 @@ class PersonalDataManager : public KeyedService, // otherwise appends |new_profile| to the end of that list. Fills // |merged_profiles| with the result. Returns the |guid| of the new or updated // profile. - std::string MergeProfile( + static std::string MergeProfile( const AutofillProfile& new_profile, std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, const std::string& app_locale, @@ -369,7 +360,7 @@ class PersonalDataManager : public KeyedService, // if the card number of |credit_card| is equal to any local card or any // unmasked server card known by the browser, or |TypeAndLastFourDigits| of // |credit_card| is equal to any masked server card known by the browser. - bool IsKnownCard(const CreditCard& credit_card); + bool IsKnownCard(const CreditCard& credit_card) const; // Check whether a card is a server card or has a duplicated server card. bool IsServerCard(const CreditCard* credit_card) const; @@ -394,6 +385,9 @@ class PersonalDataManager : public KeyedService, // Records the sync transport consent if the user is in sync transport mode. virtual void OnUserAcceptedUpstreamOffer(); + // Triggered when a profile is added/updated/removed on db. + void OnAutofillProfileChanged(const AutofillProfileDeepChange& change); + protected: // Only PersonalDataManagerFactory and certain tests can create instances of // PersonalDataManager. @@ -497,15 +491,9 @@ class PersonalDataManager : public KeyedService, std::vector<AutofillProfile>* profiles); // Sets |web_profiles_| to the contents of |profiles| and updates the web - // database by adding, updating and removing profiles. - // The relationship between this and Refresh is subtle. - // A call to |SetProfiles| could include out-of-date data that may conflict - // if we didn't refresh-to-latest before an Autofill window was opened for - // editing. |SetProfiles| is implemented to make a "best effort" to apply the - // changes, but in extremely rare edge cases it is possible not all of the - // updates in |profiles| make it to the DB. This is why SetProfiles will - // invoke Refresh after finishing, to ensure we get into a - // consistent state. See Refresh for details. + // database by adding, updating and removing profiles. |web_profiles_| need to + // be updated at the end of the function, since some tasks cannot tolerate + // database delays. virtual void SetProfiles(std::vector<AutofillProfile>* profiles); // Sets |credit_cards_| to the contents of |credit_cards| and updates the web @@ -617,7 +605,7 @@ class PersonalDataManager : public KeyedService, base::ObserverList<PersonalDataManagerObserver>::Unchecked observers_; // |profile_valditiies_need_update| whenever the profile validities are out of - bool profile_validities_need_update_ = true; + bool profiles_server_validities_need_update_ = true; private: // Saves |imported_credit_card| to the WebDB if it exists. Returns the guid of @@ -643,10 +631,6 @@ class PersonalDataManager : public KeyedService, const base::string16& field_contents, const std::vector<CreditCard*>& cards_to_suggest) const; - // Returns true if the given credit card can be deleted in a major version - // upgrade. The card will need to be local and disused, to be deletable. - bool IsCreditCardDeletable(CreditCard* card); - // Runs the routine that removes the orphan rows in the autofill tables if // it's never been done. void RemoveOrphanAutofillTableRows(); @@ -668,7 +652,7 @@ class PersonalDataManager : public KeyedService, // testing purposes. void DedupeProfiles( std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, - std::unordered_set<AutofillProfile*>* profile_guids_to_delete, + std::unordered_set<std::string>* profile_guids_to_delete, std::unordered_map<std::string, std::string>* guids_merge_map) const; // Updates the credit cards' billing address reference based on the merges @@ -709,15 +693,17 @@ class PersonalDataManager : public KeyedService, // should be sorted by decreasing frecency outside of this method, since this // will be called multiple times in a row. Returns the guid of the new or // updated profile. - std::string MergeServerAddressesIntoProfiles( + static std::string MergeServerAddressesIntoProfiles( const AutofillProfile& server_address, - std::vector<AutofillProfile>* existing_profiles) const; + std::vector<AutofillProfile>* existing_profiles, + const std::string& app_locale, + const std::string& primary_account_email); // Removes profile from web database according to |guid| and resets credit // card's billing address if that address is used by any credit cards. // The method does not refresh, this allows multiple removal with one // refreshing in the end. - void RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne( + void RemoveAutofillProfileByGUIDAndBlankCreditCardReference( const std::string& guid); // Returns true if an address can be deleted in a major version upgrade. @@ -727,16 +713,6 @@ class PersonalDataManager : public KeyedService, AutofillProfile* profile, const std::unordered_set<std::string>& used_billing_address_guids); - // If the AutofillCreateDataForTest feature is enabled, this helper creates - // autofill address data that would otherwise be difficult to create - // manually using the UI. - void MaybeCreateTestAddresses(); - - // If the AutofillCreateDataForTest feature is enabled, this helper creates - // autofill credit card data that would otherwise be difficult to create - // manually using the UI. - void MaybeCreateTestCreditCards(); - // Applies various fixes and cleanups on autofill addresses. void ApplyAddressFixesAndCleanups(); @@ -746,6 +722,25 @@ class PersonalDataManager : public KeyedService, // Resets |synced_profile_validity_|. void ResetProfileValidity(); + // Add/Update/Remove profiles on DB. + void AddProfileToDB(const AutofillProfile& profile); + void UpdateProfileInDB(const AutofillProfile& profile); + void RemoveProfileFromDB(const std::string& guid); + + // Look at the next profile change for profile with guid = |guid|, and handle + // it. + void HandleNextProfileChange(const std::string& guid); + // returns true if there is any profile change that's still on going. + bool ProfileChangesAreOnGoing(); + // returns true if there is any ongoing change for profile with guid = |guid| + // that's still on going. + bool ProfileChangesAreOnGoing(const std::string& guid); + // Remove the change from the |ongoing_profile_changes_|, handle next task or + // Refresh. + void OnProfileChangeDone(const std::string& guid); + // Clear |ongoing_profile_changes_|. + void ClearOnGoingProfileChanges(); + const std::string app_locale_; // The default country code for new addresses. @@ -772,6 +767,10 @@ class PersonalDataManager : public KeyedService, // |profile_validities_need_update| whenever this is changed. std::unique_ptr<UserProfileValidityMap> synced_profile_validity_; + // A timely ordered list of on going changes for each profile. + std::unordered_map<std::string, std::queue<AutofillProfileDeepChange>> + ongoing_profile_changes_; + // The client side profile validator. AutofillProfileValidator* client_profile_validator_ = nullptr; @@ -806,13 +805,16 @@ class PersonalDataManager : public KeyedService, // Whether new information was received from the sync server. bool has_synced_new_data_ = false; - // True if test data has been created this session. - bool has_created_test_addresses_ = false; - bool has_created_test_credit_cards_ = false; + // Used to create test data. If the AutofillCreateDataForTest feature is + // enabled, this helper creates autofill profiles and credit card data that + // would otherwise be difficult to create manually using the UI. + TestDataCreator test_data_creator_; // Whether sync should be considered on in a test. bool is_syncing_for_test_ = false; + base::WeakPtrFactory<PersonalDataManager> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(PersonalDataManager); }; diff --git a/chromium/components/autofill/core/browser/personal_data_manager_observer.h b/chromium/components/autofill/core/browser/personal_data_manager_observer.h index e948d3ff458..d09bc934f9e 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_observer.h +++ b/chromium/components/autofill/core/browser/personal_data_manager_observer.h @@ -18,6 +18,10 @@ class PersonalDataManagerObserver { // Called when there is insufficient data to fill a form. Used for testing. virtual void OnInsufficientFormData() {} + // Notifies the observer that the PersonalDataManager has no more tasks to + // handle. + virtual void OnPersonalDataFinishedProfileTasks() {} + protected: virtual ~PersonalDataManagerObserver() {} }; diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc index df1261efc1c..f06c16f345b 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc @@ -19,7 +19,6 @@ #include "base/files/scoped_temp_dir.h" #include "base/guid.h" #include "base/i18n/time_formatting.h" -#include "base/message_loop/message_loop.h" #include "base/rand_util.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" @@ -27,6 +26,7 @@ #include "base/synchronization/waitable_event.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/test/scoped_task_environment.h" #include "base/test/simple_test_clock.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -72,8 +72,8 @@ const base::Time kArbitraryTime = base::Time::FromDoubleT(25); const base::Time kSomeLaterTime = base::Time::FromDoubleT(1000); const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000); -ACTION(QuitMainMessageLoop) { - base::RunLoop::QuitCurrentWhenIdleDeprecated(); +ACTION_P(QuitMessageLoop, loop) { + loop->Quit(); } class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver { @@ -82,6 +82,7 @@ class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver { ~PersonalDataLoadedObserverMock() override {} MOCK_METHOD0(OnPersonalDataChanged, void()); + MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void()); }; class PersonalDataManagerMock : public PersonalDataManager { @@ -134,8 +135,10 @@ class PersonalDataManagerTestBase { PersonalDataManagerTestBase() { // Enable account storage by default, some tests will override this to be // false. - scoped_features_.InitAndEnableFeature( - features::kAutofillEnableAccountWalletStorage); + scoped_features_.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage, + features::kAutofillProfileClientValidation}, + /*disabled_features=*/{}); } void SetUpTest() { @@ -179,8 +182,7 @@ class PersonalDataManagerTestBase { personal_data_->pref_service_->SetInteger( prefs::kAutofillLastVersionDeduped, 0); personal_data_->pref_service_->SetInteger( - prefs::kAutofillLastVersionValidated, - atoi(version_info::GetVersionNumber().c_str())); + prefs::kAutofillLastVersionValidated, CHROME_VERSION_MAJOR); } void TearDownTest() { @@ -193,6 +195,7 @@ class PersonalDataManagerTestBase { void ResetPersonalDataManager(UserMode user_mode, bool use_sync_transport_mode) { bool is_incognito = (user_mode == USER_MODE_INCOGNITO); + personal_data_.reset(new PersonalDataManagerMock("en")); personal_data_->Init( scoped_refptr<AutofillWebDataService>(profile_database_service_), @@ -213,10 +216,7 @@ class PersonalDataManagerTestBase { personal_data_->OnSyncServiceInitialized(&sync_service_); personal_data_->OnStateChanged(&sync_service_); - // Verify that the web database has been updated and the notification sent. - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillRepeatedly(QuitMainMessageLoop()); - base::RunLoop().Run(); + WaitForOnPersonalDataChangedRepeatedly(); } void ResetPersonalDataManager(UserMode user_mode) { @@ -226,6 +226,7 @@ class PersonalDataManagerTestBase { void ResetProfiles() { std::vector<AutofillProfile> empty_profiles; personal_data_->SetProfiles(&empty_profiles); + WaitForOnPersonalDataChanged(); } bool TurnOnSyncFeature() WARN_UNUSED_RESULT { @@ -253,11 +254,7 @@ class PersonalDataManagerTestBase { test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); - - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMainMessageLoop()); - base::RunLoop().Run(); + AddProfileToPersonalDataManager(profile); ASSERT_EQ(1U, personal_data_->GetProfiles().size()); } @@ -298,10 +295,7 @@ class PersonalDataManagerTestBase { "1"); personal_data_->AddCreditCard(credit_card2); - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMainMessageLoop()); - base::RunLoop().Run(); - + WaitOnceForOnPersonalDataChanged(); ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); } @@ -318,9 +312,7 @@ class PersonalDataManagerTestBase { masked_server_card.set_server_id("masked_id"); masked_server_card.set_use_count(15); personal_data_->AddFullServerCreditCard(masked_server_card); - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMainMessageLoop()); - base::RunLoop().Run(); + WaitOnceForOnPersonalDataChanged(); ASSERT_EQ(1U, personal_data_->GetCreditCards().size()); // Cards are automatically remasked on Linux since full server cards are not @@ -349,10 +341,7 @@ class PersonalDataManagerTestBase { local_card.set_use_count(5); personal_data_->AddCreditCard(local_card); - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMainMessageLoop()); - base::RunLoop().Run(); - + WaitOnceForOnPersonalDataChanged(); EXPECT_EQ(3U, personal_data_->GetCreditCards().size()); } @@ -379,9 +368,8 @@ class PersonalDataManagerTestBase { AutofillProfile profile0(test::GetFullProfile()); profile0.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(400)); - personal_data_->AddProfile(profile0); + AddProfileToPersonalDataManager(profile0); - WaitForOnPersonalDataChanged(); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); } @@ -390,6 +378,38 @@ class PersonalDataManagerTestBase { : account_autofill_table_; } + void AddProfileToPersonalDataManager(const AutofillProfile& profile) { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + personal_data_->AddProfile(profile); + run_loop.Run(); + } + + void UpdateProfileOnPersonalDataManager(const AutofillProfile& profile) { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + + personal_data_->UpdateProfile(profile); + run_loop.Run(); + } + + void RemoveByGUIDFromPersonalDataManager(const std::string& guid) { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + + personal_data_->RemoveByGUID(guid); + run_loop.Run(); + } + void SetServerCards(const std::vector<CreditCard>& server_cards) { test::SetServerCreditCards(GetServerDataTable(), server_cards); } @@ -398,11 +418,53 @@ class PersonalDataManagerTestBase { GetServerDataTable()->SetServerProfiles(server_profiles); } + void SaveImportedProfileToPersonalDataManager( + const AutofillProfile& profile) { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + + personal_data_->SaveImportedProfile(profile); + run_loop.Run(); + } + + void ConvertWalletAddressesAndUpdateWalletCards() { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + + personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); + run_loop.Run(); + } + // Verifies that the web database has been updated and the notification sent. void WaitForOnPersonalDataChanged() { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + run_loop.Run(); + } + + void WaitOnceForOnPersonalDataChanged() { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + run_loop.Run(); + } + + // Verifies that the web database has been updated and the notification sent. + void WaitForOnPersonalDataChangedRepeatedly() { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillRepeatedly(QuitMainMessageLoop()); - base::RunLoop().Run(); + .Times(testing::AnyNumber()); + run_loop.Run(); } void ExpectOnValidated(AutofillProfile* profile) { @@ -435,7 +497,8 @@ class PersonalDataManagerTestBase { // The temporary directory should be deleted at the end to ensure that // files are not used anymore and deletion succeeds. base::ScopedTempDir temp_dir_; - base::MessageLoopForUI message_loop_; + base::test::ScopedTaskEnvironment task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; std::unique_ptr<PrefService> prefs_; identity::IdentityTestEnvironment identity_test_env_; syncer::TestSyncService sync_service_; @@ -461,11 +524,9 @@ TEST_F(PersonalDataManagerTest, AddProfile) { // Add profile0 to the database. AutofillProfile profile0(test::GetFullProfile()); profile0.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("j@s.com")); - personal_data_->AddProfile(profile0); - + AddProfileToPersonalDataManager(profile0); // Reload the database. ResetPersonalDataManager(USER_MODE_NORMAL); - // Verify the addition. const std::vector<AutofillProfile*>& results1 = personal_data_->GetProfiles(); ASSERT_EQ(1U, results1.size()); @@ -474,7 +535,8 @@ TEST_F(PersonalDataManagerTest, AddProfile) { // Add profile with identical values. Duplicates should not get saved. AutofillProfile profile0a = profile0; profile0a.set_guid(base::GenerateGUID()); - personal_data_->AddProfile(profile0a); + + AddProfileToPersonalDataManager(profile0a); // Reload the database. ResetPersonalDataManager(USER_MODE_NORMAL); @@ -492,7 +554,7 @@ TEST_F(PersonalDataManagerTest, AddProfile) { // Add the different profile. This should save as a separate profile. // Note that if this same profile was "merged" it would collapse to one // profile with a multi-valued entry for email. - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); // Reload the database. ResetPersonalDataManager(USER_MODE_NORMAL); @@ -504,17 +566,35 @@ TEST_F(PersonalDataManagerTest, AddProfile) { ExpectSameElements(profiles, personal_data_->GetProfiles()); } -// TODO(crbug.com/909730): If you add a profile and then remove it right away, -// the profile will not be removed, but it should. -TEST_F(PersonalDataManagerTest, AddRemoveProfile) { +// Adding, updating, removing operations without waiting in between. +TEST_F(PersonalDataManagerTest, AddRemoveUpdateProfileSequence) { AutofillProfile profile(test::GetFullProfile()); personal_data_->AddProfile(profile); personal_data_->RemoveByGUID(profile.guid()); - WaitForOnPersonalDataChanged(); + auto profiles = personal_data_->GetProfiles(); - ASSERT_EQ(1U, profiles.size()); // the correct size is 0. + ASSERT_EQ(0U, profiles.size()); + + personal_data_->AddProfile(profile); + personal_data_->RemoveByGUID(profile.guid()); + personal_data_->RemoveByGUID(profile.guid()); + WaitForOnPersonalDataChanged(); + profiles = personal_data_->GetProfiles(); + ASSERT_EQ(0U, profiles.size()); + + personal_data_->AddProfile(profile); + profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com")); + personal_data_->UpdateProfile(profile); + profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("newer@email.com")); + personal_data_->UpdateProfile(profile); + WaitForOnPersonalDataChanged(); + + profiles = personal_data_->GetProfiles(); + ASSERT_EQ(1U, profiles.size()); + EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS), + base::ASCIIToUTF16("newer@email.com")); } // Test that a new profile has its basic information set. @@ -526,7 +606,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_BasicInformation) { // Add a profile to the database. AutofillProfile profile(test::GetFullProfile()); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("j@s.com")); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); // Reload the database. ResetPersonalDataManager(USER_MODE_NORMAL); @@ -685,7 +765,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_Invalid) { std::vector<AutofillProfile> profiles; profiles.push_back(with_invalid); personal_data_->SetProfiles(&profiles); - + WaitForOnPersonalDataChanged(); ASSERT_EQ(1u, personal_data_->GetProfiles().size()); AutofillProfile profile = *personal_data_->GetProfiles()[0]; ASSERT_NE(without_invalid.GetRawInfo(PHONE_HOME_WHOLE_NUMBER), @@ -697,10 +777,10 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileSetModificationDate) { AutofillProfile profile(test::GetFullProfile()); EXPECT_NE(base::Time(), profile.modification_date()); - personal_data_->SaveImportedProfile(profile); + SaveImportedProfileToPersonalDataManager(profile); const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); ASSERT_EQ(1U, profiles.size()); - EXPECT_GT(base::TimeDelta::FromMilliseconds(500), + EXPECT_GT(base::TimeDelta::FromMilliseconds(1000), AutofillClock::Now() - profiles[0]->modification_date()); } @@ -721,10 +801,8 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) { "Orlando", "FL", "32801", "US", "19482937549"); // Add two test profiles to the database. - personal_data_->AddProfile(profile0); - personal_data_->AddProfile(profile1); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile0); + AddProfileToPersonalDataManager(profile1); std::vector<AutofillProfile*> profiles; profiles.push_back(&profile0); @@ -733,11 +811,9 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) { // Update, remove, and add. profile0.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("John")); - personal_data_->UpdateProfile(profile0); - personal_data_->RemoveByGUID(profile1.guid()); - personal_data_->AddProfile(profile2); - - WaitForOnPersonalDataChanged(); + UpdateProfileOnPersonalDataManager(profile0); + RemoveByGUIDFromPersonalDataManager(profile1.guid()); + AddProfileToPersonalDataManager(profile2); profiles.clear(); profiles.push_back(&profile0); @@ -783,7 +859,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) { // Update, remove, and add. credit_card0.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Joe")); personal_data_->UpdateCreditCard(credit_card0); - personal_data_->RemoveByGUID(credit_card1.guid()); + RemoveByGUIDFromPersonalDataManager(credit_card1.guid()); personal_data_->AddCreditCard(credit_card2); WaitForOnPersonalDataChanged(); @@ -811,13 +887,8 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) { credit_card3.set_record_type(CreditCard::FULL_SERVER_CARD); credit_card3.set_server_id("server_id"); - // Verify that the web database has been updated and the notification sent. - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMainMessageLoop()); - personal_data_->AddFullServerCreditCard(credit_card3); - - base::RunLoop().Run(); + WaitForOnPersonalDataChanged(); cards.push_back(&credit_card3); ExpectSameElements(cards, personal_data_->GetCreditCards()); @@ -956,7 +1027,7 @@ TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) { EXPECT_FALSE(credit_card.IsVerified()); // Add the data to the database. - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); personal_data_->AddCreditCard(credit_card); WaitForOnPersonalDataChanged(); @@ -978,7 +1049,7 @@ TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) { EXPECT_TRUE(profile.IsVerified()); EXPECT_TRUE(credit_card.IsVerified()); - personal_data_->UpdateProfile(profile); + UpdateProfileOnPersonalDataManager(profile); personal_data_->UpdateCreditCard(credit_card); // Note: No refresh, as no update is expected. @@ -997,7 +1068,7 @@ TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) { profile.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("John")); credit_card.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Joe")); - personal_data_->UpdateProfile(profile); + UpdateProfileOnPersonalDataManager(profile); personal_data_->UpdateCreditCard(credit_card); WaitForOnPersonalDataChanged(); @@ -1058,13 +1129,10 @@ TEST_F(PersonalDataManagerTest, AddFullCardAsMaskedCard) { "378282246310005" /* American Express */, "04", "2999", "1"); - // Verify that the web database has been updated and the notification sent. - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .WillOnce(QuitMainMessageLoop()); personal_data_->AddFullServerCreditCard(server_card); - base::RunLoop().Run(); + WaitForOnPersonalDataChanged(); ASSERT_EQ(1U, personal_data_->GetCreditCards().size()); EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, @@ -1078,7 +1146,13 @@ TEST_F(PersonalDataManagerTest, OfferStoreUnmaskedCards) { #elif defined(OS_LINUX) bool should_offer = false; #endif - EXPECT_EQ(should_offer, OfferStoreUnmaskedCards()); + EXPECT_EQ(should_offer, OfferStoreUnmaskedCards(/*is_off_the_record=*/false)); +} + +// Tests that OfferStoreUnmaskedCards always returns false if the user is off +// the record. +TEST_F(PersonalDataManagerTest, OfferStoreUnmaskedCards_OffTheRecord) { + EXPECT_EQ(false, OfferStoreUnmaskedCards(/*is_off_the_record=*/true)); } // Tests that UpdateServerCreditCard can be used to mask or unmask server cards. @@ -1107,8 +1181,7 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCards) { WaitForOnPersonalDataChanged(); ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); - - if (!OfferStoreUnmaskedCards()) { + if (!OfferStoreUnmaskedCards(/*is_off_the_record=*/false)) { for (CreditCard* card : personal_data_->GetCreditCards()) { EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, card->record_type()); } @@ -1124,8 +1197,6 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCards) { CreditCard* unmasked_card = &server_cards.front(); unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD); unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456")); - EXPECT_NE(0, server_cards.front().Compare( - *personal_data_->GetCreditCards().front())); personal_data_->UpdateServerCreditCard(*unmasked_card); WaitForOnPersonalDataChanged(); @@ -1136,8 +1207,6 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCards) { CreditCard* remasked_card = &server_cards.back(); remasked_card->set_record_type(CreditCard::MASKED_SERVER_CARD); remasked_card->SetNumber(base::ASCIIToUTF16("0005")); - EXPECT_NE( - 0, server_cards.back().Compare(*personal_data_->GetCreditCards().back())); personal_data_->UpdateServerCreditCard(*remasked_card); WaitForOnPersonalDataChanged(); @@ -1186,10 +1255,8 @@ TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) { "1"); // Add two test profiles to the database. - personal_data_->AddProfile(profile0); - personal_data_->AddProfile(profile1); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile0); + AddProfileToPersonalDataManager(profile1); std::vector<AutofillProfile*> profiles; profiles.push_back(&profile0); @@ -1225,9 +1292,7 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) { ""); // Add the profile0 to the db. - personal_data_->AddProfile(profile0); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile0); // Verify that we've loaded the profiles from the web database. const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles(); @@ -1238,9 +1303,7 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) { AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile1, "z", "", "", "", "", "", "", "", "", "", "", ""); - personal_data_->AddProfile(profile1); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile1); // Make sure the two profiles have different GUIDs, both valid. const std::vector<AutofillProfile*>& results3 = personal_data_->GetProfiles(); @@ -1293,9 +1356,7 @@ TEST_F(PersonalDataManagerTest, SetEmptyProfile) { ""); // Add the empty profile to the database. - personal_data_->AddProfile(profile0); - - // Note: no refresh here. + AddProfileToPersonalDataManager(profile0); // Reset the PersonalDataManager. This tests that the personal data was saved // to the web database, and that we can load the profiles from the web @@ -1336,10 +1397,8 @@ TEST_F(PersonalDataManagerTest, Refresh) { "Orlando", "FL", "32801", "US", "19482937549"); // Add the test profiles to the database. - personal_data_->AddProfile(profile0); - personal_data_->AddProfile(profile1); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile0); + AddProfileToPersonalDataManager(profile1); std::vector<AutofillProfile*> profiles; profiles.push_back(&profile0); @@ -1366,20 +1425,20 @@ TEST_F(PersonalDataManagerTest, Refresh) { profile_database_service_->RemoveAutofillProfile(profile1.guid()); profile_database_service_->RemoveAutofillProfile(profile2.guid()); - // Before telling the PDM to refresh, simulate an edit to one of the deleted - // profiles via a SetProfile update (this would happen if the Autofill window - // was open with a previous snapshot of the profiles, and something - // [e.g. sync] removed a profile from the browser. In this edge case, we will - // end up in a consistent state by dropping the write). + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + + auto results = personal_data_->GetProfiles(); + ASSERT_EQ(1U, results.size()); + EXPECT_EQ(profile0, *results[0]); + profile0.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("Mar")); - profile2.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("Jo")); - personal_data_->UpdateProfile(profile0); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); + profile_database_service_->UpdateAutofillProfile(profile0); + personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); + results = personal_data_->GetProfiles(); ASSERT_EQ(1U, results.size()); EXPECT_EQ(profile0, *results[0]); } @@ -1395,10 +1454,9 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) { EXPECT_FALSE(profile.IsVerified()); // Add the profile to the database. - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); // Make sure everything is set up correctly. - WaitForOnPersonalDataChanged(); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); AutofillProfile new_verified_profile = profile; @@ -1408,9 +1466,7 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) { base::ASCIIToUTF16("1 234 567-8910")); EXPECT_TRUE(new_verified_profile.IsVerified()); - personal_data_->SaveImportedProfile(new_verified_profile); - - WaitForOnPersonalDataChanged(); + SaveImportedProfileToPersonalDataManager(new_verified_profile); // The new profile should be merged into the existing one. const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); @@ -1469,10 +1525,9 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) { "johnwayne@me.xyz", nullptr, "123 Zoo St.", nullptr, "Hollywood", "CA", "91601", "US", "14155678910"); - personal_data_->AddProfile(profile0); + AddProfileToPersonalDataManager(profile0); // Make sure everything is set up correctly. - WaitForOnPersonalDataChanged(); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); personal_data_->GetNonEmptyTypes(&non_empty_types); @@ -1504,10 +1559,9 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) { "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "16502937549"); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); - WaitForOnPersonalDataChanged(); EXPECT_EQ(3U, personal_data_->GetProfiles().size()); personal_data_->GetNonEmptyTypes(&non_empty_types); @@ -1582,7 +1636,7 @@ TEST_F(PersonalDataManagerTest, IncognitoReadOnly) { test::SetProfileInfo(&steve_jobs, "Steven", "Paul", "Jobs", "sjobs@apple.com", "Apple Computer, Inc.", "1 Infinite Loop", "", "Cupertino", "CA", "95014", "US", "(800) 275-2273"); - personal_data_->AddProfile(steve_jobs); + AddProfileToPersonalDataManager(steve_jobs); CreditCard bill_gates(base::GenerateGUID(), test::kEmptyOrigin); test::SetCreditCardInfo(&bill_gates, "William H. Gates", "5555555555554444", @@ -1659,10 +1713,9 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) { test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", "", "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", "CA", "(800) 555-9000"); - personal_data_->AddProfile(moose); + AddProfileToPersonalDataManager(moose); // Make sure everything is set up correctly. - WaitForOnPersonalDataChanged(); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); // The value is cached and doesn't change even after adding an address. @@ -1688,7 +1741,7 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) { test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", "", "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", "CA", "(800) 555-9000"); - personal_data_->AddProfile(moose); + AddProfileToPersonalDataManager(moose); ResetPersonalDataManager(USER_MODE_NORMAL); EXPECT_EQ("CA", personal_data_->GetDefaultCountryCodeForNewAddress()); @@ -1701,38 +1754,27 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) { test::SetProfileInfo(&armadillo2, "Armin", "Dill", "Oh", "ado@example.com", "", "2 Speed Bump", "", "Lubbock", "TX", "77500", "MX", "(800) 555-9000"); - personal_data_->AddProfile(armadillo); - personal_data_->AddProfile(armadillo2); + AddProfileToPersonalDataManager(armadillo); + AddProfileToPersonalDataManager(armadillo2); ResetPersonalDataManager(USER_MODE_NORMAL); EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress()); - personal_data_->RemoveByGUID(armadillo.guid()); - personal_data_->RemoveByGUID(armadillo2.guid()); + RemoveByGUIDFromPersonalDataManager(armadillo.guid()); + RemoveByGUIDFromPersonalDataManager(armadillo2.guid()); ResetPersonalDataManager(USER_MODE_NORMAL); // Verified profiles count more. armadillo.set_origin("http://randomwebsite.com"); armadillo2.set_origin("http://randomwebsite.com"); - personal_data_->AddProfile(armadillo); - personal_data_->AddProfile(armadillo2); + AddProfileToPersonalDataManager(armadillo); + AddProfileToPersonalDataManager(armadillo2); ResetPersonalDataManager(USER_MODE_NORMAL); EXPECT_EQ("CA", personal_data_->GetDefaultCountryCodeForNewAddress()); - personal_data_->RemoveByGUID(armadillo.guid()); + RemoveByGUIDFromPersonalDataManager(armadillo.guid()); ResetPersonalDataManager(USER_MODE_NORMAL); // But unverified profiles can be a tie breaker. armadillo.set_origin(kSettingsOrigin); - personal_data_->AddProfile(armadillo); - ResetPersonalDataManager(USER_MODE_NORMAL); - EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress()); - - // Invalid country codes are ignored. - personal_data_->RemoveByGUID(armadillo.guid()); - personal_data_->RemoveByGUID(moose.guid()); - AutofillProfile space_invader(base::GenerateGUID(), kSettingsOrigin); - test::SetProfileInfo(&space_invader, "Marty", "", "Martian", "mm@example.com", - "", "1 Flying Object", "", "Valles Marineris", "", "", - "XX", ""); - personal_data_->AddProfile(moose); + AddProfileToPersonalDataManager(armadillo); ResetPersonalDataManager(USER_MODE_NORMAL); EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress()); } @@ -1742,17 +1784,14 @@ TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) { test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); // Make sure everything is set up correctly. - WaitForOnPersonalDataChanged(); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); profile.set_language_code("en"); - personal_data_->UpdateProfile(profile); - - WaitForOnPersonalDataChanged(); + UpdateProfileOnPersonalDataManager(profile); const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); ASSERT_EQ(1U, results.size()); @@ -1766,7 +1805,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions) { "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); ResetPersonalDataManager(USER_MODE_NORMAL); std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( @@ -1783,7 +1822,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_PhoneSubstring) { "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); ResetPersonalDataManager(USER_MODE_NORMAL); std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( @@ -1817,10 +1856,10 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_HideSubsets) { // For easier results verification, make sure |profile| is suggested first. profile.set_use_count(5); - personal_data_->AddProfile(profile); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - personal_data_->AddProfile(profile3); + AddProfileToPersonalDataManager(profile); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + AddProfileToPersonalDataManager(profile3); ResetPersonalDataManager(USER_MODE_NORMAL); // Simulate a form with street address, city and state. @@ -1846,7 +1885,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_SuggestionsLimit) { "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); profiles.push_back(profile); } ResetPersonalDataManager(USER_MODE_NORMAL); @@ -1880,7 +1919,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ProfilesLimit) { profile.set_use_count(12); profile.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1)); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); profiles.push_back(profile); } @@ -1892,7 +1931,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ProfilesLimit) { "Hollywood", "CA", "91601", "US", "12345678910"); profile.set_use_count(1); profile.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(7)); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); ResetPersonalDataManager(USER_MODE_NORMAL); @@ -1918,7 +1957,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) { "Hollywood", "CA", "91601", "US", "12345678910"); profile3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1)); profile3.set_use_count(5); - personal_data_->AddProfile(profile3); + AddProfileToPersonalDataManager(profile3); AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison", @@ -1927,7 +1966,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) { "Hollywood", "CA", "91601", "US", "12345678910"); profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1)); profile1.set_use_count(10); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison", @@ -1936,7 +1975,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) { "Hollywood", "CA", "91601", "US", "12345678910"); profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(15)); profile2.set_use_count(300); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); ResetPersonalDataManager(USER_MODE_NORMAL); std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( @@ -1956,21 +1995,21 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_NumberOfSuggestions) { "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile3); + AddProfileToPersonalDataManager(profile3); ResetPersonalDataManager(USER_MODE_NORMAL); @@ -1992,7 +2031,7 @@ TEST_F(PersonalDataManagerTest, "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200)); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison", @@ -2000,7 +2039,7 @@ TEST_F(PersonalDataManagerTest, "456 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20)); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); ResetPersonalDataManager(USER_MODE_NORMAL); @@ -2076,14 +2115,14 @@ TEST_F(PersonalDataManagerTest, profile1.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID, AutofillProfile::CLIENT); profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20)); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "456 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "1234567890"); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); ResetPersonalDataManager(USER_MODE_NORMAL); { @@ -2143,14 +2182,14 @@ TEST_F(PersonalDataManagerTest, autofill_profile_validity); } profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20)); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "456 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "NY", "91601", "US", "1234567890"); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); ResetPersonalDataManager(USER_MODE_NORMAL); { @@ -2198,7 +2237,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ProfileAutofillDisabled) { test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Add a different server profile. std::vector<AutofillProfile> server_profiles; @@ -2215,7 +2254,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ProfileAutofillDisabled) { // Disable Profile autofill. prefs::SetProfileAutofillEnabled(personal_data_->pref_service_, false); WaitForOnPersonalDataChanged(); - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); + ConvertWalletAddressesAndUpdateWalletCards(); // Check that profiles were saved. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -2244,7 +2283,7 @@ TEST_F(PersonalDataManagerTest, test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Add a different server profile. std::vector<AutofillProfile> server_profiles; @@ -2260,7 +2299,7 @@ TEST_F(PersonalDataManagerTest, personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); + ConvertWalletAddressesAndUpdateWalletCards(); // Expect 2 autofilled values or suggestions. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -2292,7 +2331,7 @@ TEST_F(PersonalDataManagerTest, test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Expect no profile values or suggestions were added. EXPECT_EQ(0U, personal_data_->GetProfiles().size()); @@ -3258,7 +3297,7 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) { EXPECT_EQ(1U, profile.use_count()); EXPECT_EQ(kArbitraryTime, profile.use_date()); EXPECT_EQ(kArbitraryTime, profile.modification_date()); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin); test::SetCreditCardInfo(&credit_card, "John Dillinger", @@ -3283,8 +3322,16 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) { EXPECT_EQ(1U, added_profile->use_count()); EXPECT_EQ(kArbitraryTime, added_profile->use_date()); EXPECT_EQ(kArbitraryTime, added_profile->modification_date()); + + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + personal_data_->RecordUseOf(profile); + run_loop.Run(); + CreditCard* added_card = personal_data_->GetCreditCardByGUID(credit_card.guid()); ASSERT_TRUE(added_card); @@ -3294,8 +3341,6 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) { EXPECT_EQ(kArbitraryTime, added_card->modification_date()); personal_data_->RecordUseOf(credit_card); - WaitForOnPersonalDataChanged(); - // Verify usage stats are updated. added_profile = personal_data_->GetProfileByGUID(profile.guid()); ASSERT_TRUE(added_profile); @@ -3340,7 +3385,7 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { WaitForOnPersonalDataChanged(); EXPECT_EQ(3U, personal_data_->GetCreditCards().size()); - if (!OfferStoreUnmaskedCards()) { + if (!OfferStoreUnmaskedCards(/*is_off_the_record=*/false)) { for (CreditCard* card : personal_data_->GetCreditCards()) { EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, card->record_type()); } @@ -3356,8 +3401,6 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { CreditCard* unmasked_card = &server_cards.front(); unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD); unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456")); - EXPECT_NE(0, - unmasked_card->Compare(*personal_data_->GetCreditCards().front())); personal_data_->UpdateServerCreditCard(*unmasked_card); WaitForOnPersonalDataChanged(); @@ -3453,7 +3496,7 @@ TEST_F(PersonalDataManagerTest, ClearAllServerData) { TEST_F(PersonalDataManagerTest, ClearAllLocalData) { // Add some local data. - personal_data_->AddProfile(test::GetFullProfile()); + AddProfileToPersonalDataManager(test::GetFullProfile()); personal_data_->AddCreditCard(test::GetCreditCard()); personal_data_->Refresh(); @@ -3534,7 +3577,7 @@ TEST_P(SaveImportedProfileTest, SaveImportedProfile) { base::UTF8ToUTF16(change.field_value)); } - personal_data_->SaveImportedProfile(profile2); + SaveImportedProfileToPersonalDataManager(profile2); const std::vector<AutofillProfile*>& saved_profiles = personal_data_->GetProfiles(); @@ -3854,7 +3897,7 @@ TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) { // Create the |existing_profiles| vector. std::vector<std::unique_ptr<AutofillProfile>> existing_profiles; existing_profiles.push_back(std::move(profile1)); - existing_profiles.push_back(base::WrapUnique(profile2)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2)); // Create a new imported profile with no company name. AutofillProfile imported_profile(base::GenerateGUID(), test::kEmptyOrigin); @@ -3897,7 +3940,7 @@ TEST_F(PersonalDataManagerTest, MAYBE_MergeProfile_UsageStats) { // Create the |existing_profiles| vector. std::vector<std::unique_ptr<AutofillProfile>> existing_profiles; - existing_profiles.push_back(base::WrapUnique(profile)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile)); // Change the current date. test_clock.SetNow(kSomeLaterTime); @@ -3977,18 +4020,18 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) { // Add the profiles. std::vector<std::unique_ptr<AutofillProfile>> existing_profiles; - existing_profiles.push_back(base::WrapUnique(profile1)); - existing_profiles.push_back(base::WrapUnique(profile2)); - existing_profiles.push_back(base::WrapUnique(profile3)); - existing_profiles.push_back(base::WrapUnique(profile4)); - existing_profiles.push_back(base::WrapUnique(profile5)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile1)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile3)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5)); // Enable the profile cleanup. EnableAutofillProfileCleanup(); base::HistogramTester histogram_tester; std::unordered_map<std::string, std::string> guids_merge_map; - std::unordered_set<AutofillProfile*> profiles_to_delete; + std::unordered_set<std::string> profiles_to_delete; personal_data_->DedupeProfiles(&existing_profiles, &profiles_to_delete, &guids_merge_map); // 5 profiles were considered for dedupe. @@ -4000,11 +4043,11 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) { // Profile1 should be deleted because it was sent as the profile to merge and // thus was merged into profile3 and then into profile5. - EXPECT_TRUE(profiles_to_delete.count(profile1)); + EXPECT_TRUE(profiles_to_delete.count(profile1->guid())); // Profile3 should be deleted because profile1 was merged into it and the // resulting profile was then merged into profile5. - EXPECT_TRUE(profiles_to_delete.count(profile3)); + EXPECT_TRUE(profiles_to_delete.count(profile3->guid())); // Only these two profiles should be deleted. EXPECT_EQ(2U, profiles_to_delete.size()); @@ -4062,17 +4105,18 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) { // Add the profiles. std::vector<std::unique_ptr<AutofillProfile>> existing_profiles; - existing_profiles.push_back(base::WrapUnique(profile1)); - existing_profiles.push_back(base::WrapUnique(profile2)); - existing_profiles.push_back(base::WrapUnique(profile3)); - existing_profiles.push_back(base::WrapUnique(profile4)); - existing_profiles.push_back(base::WrapUnique(profile5)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile1)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile3)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4)); + existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5)); // Enable the profile cleanup. EnableAutofillProfileCleanup(); std::unordered_map<std::string, std::string> guids_merge_map; - std::unordered_set<AutofillProfile*> profiles_to_delete; + std::unordered_set<std::string> profiles_to_delete; + personal_data_->DedupeProfiles(&existing_profiles, &profiles_to_delete, &guids_merge_map); @@ -4121,12 +4165,14 @@ TEST_F(PersonalDataManagerTest, UpdateCardsBillingAddressReference) { credit_card4->set_billing_address_id("F"); // Add the credit cards to the database. - personal_data_->local_credit_cards_.push_back(base::WrapUnique(credit_card1)); + personal_data_->local_credit_cards_.push_back( + std::unique_ptr<CreditCard>(credit_card1)); personal_data_->server_credit_cards_.push_back( - base::WrapUnique(credit_card2)); - personal_data_->local_credit_cards_.push_back(base::WrapUnique(credit_card3)); + std::unique_ptr<CreditCard>(credit_card2)); + personal_data_->local_credit_cards_.push_back( + std::unique_ptr<CreditCard>(credit_card3)); personal_data_->server_credit_cards_.push_back( - base::WrapUnique(credit_card4)); + std::unique_ptr<CreditCard>(credit_card4)); personal_data_->UpdateCardsBillingAddressReference(guids_merge_map); @@ -4229,12 +4275,12 @@ TEST_F(PersonalDataManagerTest, // Associate the third card with profile6. credit_card3.set_billing_address_id(profile6.guid()); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - personal_data_->AddProfile(profile3); - personal_data_->AddProfile(profile4); - personal_data_->AddProfile(profile5); - personal_data_->AddProfile(profile6); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + AddProfileToPersonalDataManager(profile3); + AddProfileToPersonalDataManager(profile4); + AddProfileToPersonalDataManager(profile5); + AddProfileToPersonalDataManager(profile6); personal_data_->AddCreditCard(credit_card1); personal_data_->AddCreditCard(credit_card2); personal_data_->AddCreditCard(credit_card3); @@ -4308,11 +4354,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) { profile3.set_use_count(3); profile3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(5)); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - personal_data_->AddProfile(profile3); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + AddProfileToPersonalDataManager(profile3); // Make sure the 3 profiles were saved; EXPECT_EQ(3U, personal_data_->GetProfiles().size()); @@ -4398,11 +4442,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) { profile3.set_use_count(3); profile3.set_use_date(kArbitraryTime); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - personal_data_->AddProfile(profile3); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + AddProfileToPersonalDataManager(profile3); // Make sure the 3 profiles were saved. EXPECT_EQ(3U, personal_data_->GetProfiles().size()); @@ -4464,11 +4506,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) { profile3.set_use_count(3); profile3.set_use_date(kArbitraryTime); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - personal_data_->AddProfile(profile3); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + AddProfileToPersonalDataManager(profile3); // Make sure the 3 profiles were saved. EXPECT_EQ(3U, personal_data_->GetProfiles().size()); @@ -4529,11 +4569,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) { profile3.set_use_count(3); profile3.set_use_date(kArbitraryTime); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - personal_data_->AddProfile(profile3); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + AddProfileToPersonalDataManager(profile3); // Make sure the 3 profiles were saved. EXPECT_EQ(3U, personal_data_->GetProfiles().size()); @@ -4641,15 +4679,13 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) { Barney.set_use_count(1); Barney.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(180)); - personal_data_->AddProfile(Homer1); - personal_data_->AddProfile(Homer2); - personal_data_->AddProfile(Homer3); - personal_data_->AddProfile(Homer4); - personal_data_->AddProfile(Marge1); - personal_data_->AddProfile(Marge2); - personal_data_->AddProfile(Barney); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(Homer1); + AddProfileToPersonalDataManager(Homer2); + AddProfileToPersonalDataManager(Homer3); + AddProfileToPersonalDataManager(Homer4); + AddProfileToPersonalDataManager(Marge1); + AddProfileToPersonalDataManager(Marge2); + AddProfileToPersonalDataManager(Barney); // Make sure the 7 profiles were saved; EXPECT_EQ(7U, personal_data_->GetProfiles().size()); @@ -4732,10 +4768,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_FeatureDisabled) { "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.", "", "Springfield", "IL", "91601", "", ""); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); // Make sure both profiles were saved. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -4760,9 +4794,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) { "homer.simpson@abc.com", "", "742. Evergreen Terrace", "", "Springfield", "IL", "91601", "US", ""); - personal_data_->AddProfile(profile); + AddProfileToPersonalDataManager(profile); - WaitForOnPersonalDataChanged(); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); // Enable the profile cleanup now. Otherwise it would be triggered by the @@ -4786,10 +4819,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) { "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.", "", "Springfield", "IL", "91601", "", ""); - personal_data_->AddProfile(profile1); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); - WaitForOnPersonalDataChanged(); EXPECT_EQ(2U, personal_data_->GetProfiles().size()); // Enable the profile cleanup now. Otherwise it would be triggered by the @@ -4811,8 +4843,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) { "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.", "", "Springfield", "IL", "91601", "", ""); - personal_data_->AddProfile(profile3); - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile3); // Make sure |profile3| was saved. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -4861,7 +4892,7 @@ TEST_F(PersonalDataManagerTest, "1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL", "32801", "US", "15151231234"); profile0.set_use_date(now - base::TimeDelta::FromDays(400)); - personal_data_->AddProfile(profile0); + AddProfileToPersonalDataManager(profile0); // Create unverified/disused/used-by-expired-credit-card address(deletable). AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin); @@ -4875,9 +4906,9 @@ TEST_F(PersonalDataManagerTest, "1"); credit_card0.set_use_date(now - base::TimeDelta::FromDays(400)); credit_card0.set_billing_address_id(profile1.guid()); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); personal_data_->AddCreditCard(credit_card0); - + WaitForOnPersonalDataChanged(); // Create verified/disused/not-used-by-valid-credit-card address(not // deletable). AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); @@ -4886,7 +4917,7 @@ TEST_F(PersonalDataManagerTest, "32801", "US", "15151231234"); profile2.set_origin(kSettingsOrigin); profile2.set_use_date(now - base::TimeDelta::FromDays(400)); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); // Create unverified/recently-used/not-used-by-valid-credit-card address(not // deletable). @@ -4895,7 +4926,7 @@ TEST_F(PersonalDataManagerTest, "1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL", "32801", "US", "15151231234"); profile3.set_use_date(now - base::TimeDelta::FromDays(4)); - personal_data_->AddProfile(profile3); + AddProfileToPersonalDataManager(profile3); // Create unverified/disused/used-by-valid-credit-card address(not deletable). AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin); @@ -4908,7 +4939,7 @@ TEST_F(PersonalDataManagerTest, credit_card1.SetNetworkForMaskedCard(kVisaCard); credit_card1.set_billing_address_id(profile4.guid()); credit_card1.set_use_date(now - base::TimeDelta::FromDays(1)); - personal_data_->AddProfile(profile4); + AddProfileToPersonalDataManager(profile4); personal_data_->AddCreditCard(credit_card1); WaitForOnPersonalDataChanged(); @@ -5105,7 +5136,7 @@ TEST_F(PersonalDataManagerTest, "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); local_profile.set_use_count(1); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Add a different server profile. std::vector<AutofillProfile> server_profiles; @@ -5146,15 +5177,7 @@ TEST_F(PersonalDataManagerTest, ASSERT_EQ(1U, personal_data_->GetServerProfiles().size()); ASSERT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The Wallet address should have been added as a new local profile. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -5211,7 +5234,7 @@ TEST_F(PersonalDataManagerTest, "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); local_profile.set_use_count(1); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Add a different server profile. std::vector<AutofillProfile> server_profiles; @@ -5251,15 +5274,7 @@ TEST_F(PersonalDataManagerTest, EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The Wallet address should have been merged with the existing local profile. EXPECT_EQ(1U, personal_data_->GetProfiles().size()); @@ -5368,7 +5383,7 @@ TEST_F( "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); local_profile.set_use_count(1); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Add a server profile. std::vector<AutofillProfile> server_profiles; @@ -5420,15 +5435,7 @@ TEST_F( EXPECT_EQ(2U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The first Wallet address should have been added as a new local profile and // the second one should have merged with the first. @@ -5513,10 +5520,7 @@ TEST_F( EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); - // Run the conversion. - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The Wallet address should have been converted to a new local profile. EXPECT_EQ(1U, personal_data_->GetProfiles().size()); @@ -5547,15 +5551,7 @@ TEST_F( EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The conversion should still be recorded in the Wallet address. EXPECT_TRUE(personal_data_->GetServerProfiles().back()->has_converted()); @@ -5591,7 +5587,7 @@ TEST_F(PersonalDataManagerTest, DoNotConvertWalletAddressesInEphemeralStorage) { AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz", "", "Fox", "1212 Center.", "Bld. 5", "", "", "", "", ""); - personal_data_->AddProfile(local_profile); + AddProfileToPersonalDataManager(local_profile); // Add two server profiles: The first is unique, the second is similar to the // local one but has some additional info. @@ -5684,8 +5680,8 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) { server_cards.push_back(server_card1); // Add the data to the database. - personal_data_->AddProfile(profile0); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile0); + AddProfileToPersonalDataManager(profile1); personal_data_->AddCreditCard(local_card0); personal_data_->AddCreditCard(local_card1); SetServerCards(server_cards); @@ -5701,14 +5697,14 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) { /////////////////////////////////////////////////////////////////////// // Tested method. /////////////////////////////////////////////////////////////////////// - personal_data_->RemoveByGUID(profile0.guid()); + RemoveByGUIDFromPersonalDataManager(profile0.guid()); /////////////////////////////////////////////////////////////////////// // Validation. /////////////////////////////////////////////////////////////////////// // Wait for the data to be refreshed. - WaitForOnPersonalDataChanged(); + // WaitForOnPersonalDataChanged(); // Make sure only profile0 was deleted. ASSERT_EQ(1U, personal_data_->GetProfiles().size()); @@ -5746,7 +5742,7 @@ TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics) { test::SetProfileInfo(&profile0, "Bob", "", "Doe", "", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549"); profile0.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3)); - personal_data_->AddProfile(profile0); + AddProfileToPersonalDataManager(profile0); // Add a profile used a long time (200 days) ago. AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin); @@ -5754,7 +5750,7 @@ TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics) { "1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL", "32801", "US", "15151231234"); profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200)); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); // Reload the database, which will log the stored profile counts. base::HistogramTester histogram_tester; @@ -6028,6 +6024,7 @@ TEST_F(PersonalDataManagerTest, CreateDataForTest) { // Reloading the test profile should result in test data being created. ResetPersonalDataManager(USER_MODE_NORMAL); + const std::vector<AutofillProfile*> addresses = personal_data_->GetProfiles(); const std::vector<CreditCard*> credit_cards = personal_data_->GetCreditCards(); @@ -6363,7 +6360,7 @@ TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) { "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); profile0.set_use_count(10000); - personal_data_->AddProfile(profile0); + AddProfileToPersonalDataManager(profile0); AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison", @@ -6371,7 +6368,7 @@ TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) { "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); profile1.set_use_count(1000); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(base::GenerateGUID(), "1234"); test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison", @@ -6379,7 +6376,7 @@ TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) { "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); profile2.set_use_count(100); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); // Create a profile with a settings origin. AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin); @@ -6388,14 +6385,19 @@ TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) { "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); profile3.set_use_count(10); - personal_data_->AddProfile(profile3); + AddProfileToPersonalDataManager(profile3); - WaitForOnPersonalDataChanged(); ASSERT_EQ(4U, personal_data_->GetProfiles().size()); + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(2); // The setting of profiles 0 and 2 will be cleared. + personal_data_->ClearProfileNonSettingsOrigins(); + run_loop.Run(); - WaitForOnPersonalDataChanged(); ASSERT_EQ(4U, personal_data_->GetProfiles().size()); // The first three profiles' origin should be cleared and the fourth one still @@ -6470,7 +6472,7 @@ TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { test::SetProfileInfo(&profile0, "Homer", "J", "Simpson", "homer.simpson@abc.com", "", "742. Evergreen Terrace", "", "Springfield", "IL", "91601", "US", ""); - personal_data_->AddProfile(profile0); + AddProfileToPersonalDataManager(profile0); } // A JP profile with both street address and a city. @@ -6480,7 +6482,7 @@ TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { test::SetProfileInfo(&profile1, "Homer", "J", "Simpson", "homer.simpson@abc.com", "", "742. Evergreen Terrace", "", "Springfield", "IL", "91601", "JP", ""); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); } // A JP profile with only a city. @@ -6490,7 +6492,7 @@ TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { test::SetProfileInfo(&profile2, "Homer", "J", "Simpson", "homer.simpson@abc.com", "", "", "", "Springfield", "IL", "91601", "JP", ""); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); } // A JP profile with only a street address. @@ -6500,7 +6502,7 @@ TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { test::SetProfileInfo(&profile3, "Homer", "J", "Simpson", "homer.simpson@abc.com", "", "742. Evergreen Terrace", "", "", "IL", "91601", "JP", ""); - personal_data_->AddProfile(profile3); + AddProfileToPersonalDataManager(profile3); } // A JP profile with neither a street address nor a city. @@ -6510,14 +6512,16 @@ TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { test::SetProfileInfo(&profile4, "Homer", "J", "Simpson", "homer.simpson@abc.com", "", "", "", "", "IL", "91601", "JP", ""); - personal_data_->AddProfile(profile4); + AddProfileToPersonalDataManager(profile4); } - WaitForOnPersonalDataChanged(); - + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(2); // For the Japan profiles where the city is not empty. personal_data_->MoveJapanCityToStreetAddress(); - - WaitForOnPersonalDataChanged(); + run_loop.Run(); { AutofillProfile* profile0 = personal_data_->GetProfileByGUID(guid0); @@ -6570,8 +6574,7 @@ TEST_F( "johnwayne@me.xyz", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile); // Turn off autofill profile sync. auto model_type_set = sync_service_.GetActiveDataTypes(); @@ -6730,9 +6733,7 @@ TEST_F(PersonalDataManagerTest, UseCorrectStorageForDifferentCards) { test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5", "Hollywood", "CA", "91601", "US", "12345678910"); - personal_data_->AddProfile(profile); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile); std::vector<std::unique_ptr<AutofillProfile>> profiles; // Expect that a profile is stored in the profile autofill table. @@ -6825,8 +6826,9 @@ TEST_F(PersonalDataManagerTest, RequestProfileValidity) { TEST_F(PersonalDataManagerTest, UpdateClientValidityStates) { // Create three profiles and add them to personal_data_. AutofillProfile valid_profile(test::GetFullValidProfileForCanada()); + valid_profile.set_use_date(AutofillClock::Now()); valid_profile.set_guid("00000000-0000-0000-0000-000000000001"); - personal_data_->AddProfile(valid_profile); + AddProfileToPersonalDataManager(valid_profile); AutofillProfile profile_invalid_phone_email( test::GetFullValidProfileForChina()); @@ -6834,8 +6836,10 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates) { PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("invalid phone number!")); profile_invalid_phone_email.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!")); + profile_invalid_phone_email.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(10)); profile_invalid_phone_email.set_guid("00000000-0000-0000-0000-000000000002"); - personal_data_->AddProfile(profile_invalid_phone_email); + AddProfileToPersonalDataManager(profile_invalid_phone_email); AutofillProfile profile_invalid_province(base::GenerateGUID(), test::kEmptyOrigin); @@ -6843,9 +6847,10 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates) { "alice@munro.ca", "Fox", "123 Zoo St", "unit 5", "Montreal", "CA", "H3C 2A3", "CA", "15142343254"); profile_invalid_province.set_guid("00000000-0000-0000-0000-000000000003"); - personal_data_->AddProfile(profile_invalid_province); + profile_invalid_province.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(100)); + AddProfileToPersonalDataManager(profile_invalid_province); - WaitForOnPersonalDataChanged(); ASSERT_EQ(3U, personal_data_->GetProfiles().size()); // Validate the profiles through the client validation API. @@ -6939,12 +6944,11 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates) { TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_UpdatedFlag) { // Create two profiles and add them to personal_data_. AutofillProfile profile1(test::GetFullValidProfileForCanada()); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(test::GetFullValidProfileForChina()); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); - WaitForOnPersonalDataChanged(); ASSERT_EQ(2U, personal_data_->GetProfiles().size()); // Validate the profiles through the client validation API. @@ -6987,13 +6991,11 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_AlreadyUpdated) { // Create two profiles and add them to personal_data_. AutofillProfile profile1(test::GetFullValidProfileForCanada()); profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!")); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(test::GetFullValidProfileForChina()); profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("invalid state!")); - personal_data_->AddProfile(profile2); - - WaitForOnPersonalDataChanged(); + AddProfileToPersonalDataManager(profile2); EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(0); @@ -7030,14 +7032,13 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_Version) { AutofillProfile profile1(test::GetFullValidProfileForCanada()); profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!")); profile1.set_guid("00000000-0000-0000-0000-000000000001"); - personal_data_->AddProfile(profile1); + AddProfileToPersonalDataManager(profile1); AutofillProfile profile2(test::GetFullValidProfileForChina()); profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("invalid state!")); profile2.set_guid("00000000-0000-0000-0000-000000000002"); - personal_data_->AddProfile(profile2); + AddProfileToPersonalDataManager(profile2); - WaitForOnPersonalDataChanged(); auto profiles = personal_data_->GetProfiles(); // Pretend that the validity states are updated. @@ -7071,8 +7072,7 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_Version) { AutofillProfile::CLIENT)); // Verify that the version of the last update is set to this version. - EXPECT_EQ(atoi(version_info::GetVersionNumber().c_str()), - GetLastVersionValidatedUpdate()); + EXPECT_EQ(CHROME_VERSION_MAJOR, GetLastVersionValidatedUpdate()); // Update should not update any validity state, because both the validity // state flag and the version are up to date. @@ -7086,6 +7086,26 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_Version) { AutofillProfile::CLIENT)); } +// The validation should not happen when the feature is disabled. +TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_Disabled) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndDisableFeature( + features::kAutofillProfileClientValidation); + + AutofillProfile profile1(test::GetFullValidProfileForCanada()); + AddProfileToPersonalDataManager(profile1); + + auto profiles = personal_data_->GetProfiles(); + EXPECT_FALSE(profiles[0]->is_client_validity_states_updated()); + + personal_data_->UpdateClientValidityStates(profiles); + + EXPECT_FALSE(profiles[0]->is_client_validity_states_updated()); + EXPECT_EQ(AutofillProfile::UNVALIDATED, + profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY, + AutofillProfile::CLIENT)); +} + TEST_F(PersonalDataManagerTest, GetAccountInfoForPaymentsServer) { const std::string kIdentityManagerAccountEmail = "identity_account@email.com"; const std::string kSyncServiceAccountEmail = "active_sync_account@email.com"; diff --git a/chromium/components/autofill/core/browser/phone_field.cc b/chromium/components/autofill/core/browser/phone_field.cc index 7c19aabc528..343504b5d1b 100644 --- a/chromium/components/autofill/core/browser/phone_field.cc +++ b/chromium/components/autofill/core/browser/phone_field.cc @@ -10,7 +10,7 @@ #include <utility> #include "base/logging.h" -#include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -139,12 +139,12 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner) { // The form owns the following variables, so they should not be deleted. AutofillField* parsed_fields[FIELD_MAX]; - for (size_t i = 0; i < arraysize(kPhoneFieldGrammars); ++i) { + for (size_t i = 0; i < base::size(kPhoneFieldGrammars); ++i) { memset(parsed_fields, 0, sizeof(parsed_fields)); size_t saved_cursor = scanner->SaveCursor(); // Attempt to parse according to the next grammar. - for (; i < arraysize(kPhoneFieldGrammars) && + for (; i < base::size(kPhoneFieldGrammars) && kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR; ++i) { if (!ParsePhoneField(scanner, GetRegExp(kPhoneFieldGrammars[i].regex), @@ -158,7 +158,7 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner) { } } - if (i >= arraysize(kPhoneFieldGrammars)) { + if (i >= base::size(kPhoneFieldGrammars)) { scanner->RewindTo(saved_cursor); return nullptr; // Parsing failed. } @@ -168,11 +168,11 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner) { // Proceed to the next grammar. do { ++i; - } while (i < arraysize(kPhoneFieldGrammars) && + } while (i < base::size(kPhoneFieldGrammars) && kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR); scanner->RewindTo(saved_cursor); - if (i + 1 == arraysize(kPhoneFieldGrammars)) { + if (i + 1 == base::size(kPhoneFieldGrammars)) { return nullptr; // Tried through all the possibilities - did not match. } } diff --git a/chromium/components/autofill/core/browser/phone_field_unittest.cc b/chromium/components/autofill/core/browser/phone_field_unittest.cc index d8374d09c43..96ee9c85b43 100644 --- a/chromium/components/autofill/core/browser/phone_field_unittest.cc +++ b/chromium/components/autofill/core/browser/phone_field_unittest.cc @@ -38,7 +38,8 @@ class PhoneFieldTest : public testing::Test { // Downcast for tests. static std::unique_ptr<PhoneField> Parse(AutofillScanner* scanner) { std::unique_ptr<FormField> field = PhoneField::Parse(scanner); - return base::WrapUnique(static_cast<PhoneField*>(field.release())); + return std::unique_ptr<PhoneField>( + static_cast<PhoneField*>(field.release())); } void Clear() { diff --git a/chromium/components/autofill/core/browser/phone_number_i18n.cc b/chromium/components/autofill/core/browser/phone_number_i18n.cc index 03b9bedfefa..f4e7e3ba8fb 100644 --- a/chromium/components/autofill/core/browser/phone_number_i18n.cc +++ b/chromium/components/autofill/core/browser/phone_number_i18n.cc @@ -108,7 +108,7 @@ bool IsPrintable(base::StringPiece str) { namespace i18n { -const size_t kMaxPhoneNumberSize = 1000u; +const size_t kMaxPhoneNumberSize = 40u; // Returns true if |phone_number| is a possible number. bool IsPossiblePhoneNumber( diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto index 01b3a6527ec..079c9449ffc 100644 --- a/chromium/components/autofill/core/browser/proto/server.proto +++ b/chromium/components/autofill/core/browser/proto/server.proto @@ -185,7 +185,7 @@ message AutofillRandomizedFieldMetadata { // This message contains information about the field types in a single form. // It is sent by the toolbar to contribute to the field type statistics. -// Next available id: 36 +// Next available id: 38 message AutofillUploadContents { required string client_version = 1; required fixed64 form_signature = 2; @@ -370,6 +370,32 @@ message AutofillUploadContents { // Form-level metadata observed by the client, randomized. optional AutofillRandomizedFormMetadata randomized_form_metadata = 32; + + // Information about a button's title. + message ButtonTitle { + // Text showed on the button. + optional string title = 1; + + // Describes how the button is implemented in HTML source. Corresponds to + // components/autofill/core/common/button_title_type.h + enum ButtonTitleType { + NONE = 0; + BUTTON_ELEMENT_SUBMIT_TYPE = 1; // <button type='submit'> + BUTTON_ELEMENT_BUTTON_TYPE = 2; // <button type='button'> + INPUT_ELEMENT_SUBMIT_TYPE = 3; // <input type='submit'> + INPUT_ELEMENT_BUTTON_TYPE = 4; // <input type='button'> + HYPERLINK = 5; // e.g. <a class='button'> + DIV = 6; // e.g. <div id='submit'> + SPAN = 7; // e.g. <span name='btn'> + } + optional ButtonTitleType type = 2; + } + // Titles of form's buttons. + // TODO(850606): Deprecate once randomized metadata is launched. + repeated ButtonTitle button_title = 36; + + // Whether the fields are enclosed by a <form> tag or are unowned elements. + optional bool has_form_tag = 37; } // This proto contains information about the validity of each field in an diff --git a/chromium/components/autofill/core/browser/randomized_encoder_unittest.cc b/chromium/components/autofill/core/browser/randomized_encoder_unittest.cc index dcbc1e5989d..d034c86cae0 100644 --- a/chromium/components/autofill/core/browser/randomized_encoder_unittest.cc +++ b/chromium/components/autofill/core/browser/randomized_encoder_unittest.cc @@ -4,7 +4,8 @@ #include "components/autofill/core/browser/randomized_encoder.h" -#include "base/time/time.h" +#include "base/strings/stringprintf.h" +#include "net/base/hex_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -106,7 +107,7 @@ TEST_P(RandomizedEncoderTest, Encode) { EXPECT_LT(value.length(), kMaxLengthInBytes); - TestRandomizedEncoder encoder("this is a secret", params.encoding_type); + TestRandomizedEncoder encoder("this is the seed", params.encoding_type); // Encode the output string. std::string actual_result = @@ -135,10 +136,10 @@ TEST_P(RandomizedEncoderTest, EncodeLarge) { const std::string value( "This is some text for testing purposes. It exceeds the maximum encoding " "size. This serves to validate that truncation is performed. Lots and " - " or text. Yay!"); + "lots of text. Yay!"); EXPECT_GT(value.length(), kMaxLengthInBytes); - TestRandomizedEncoder encoder("this is a secret", params.encoding_type); + TestRandomizedEncoder encoder("this is the seed", params.encoding_type); // Encode the output string. std::string actual_result = @@ -162,3 +163,164 @@ TEST_P(RandomizedEncoderTest, EncodeLarge) { INSTANTIATE_TEST_CASE_P(All, RandomizedEncoderTest, ::testing::ValuesIn(kEncodeParams)); + +namespace { + +// Data structure used to drive the decoding test cases. +struct DecodeParams { + // The number of samples for this test. + size_t num_votes; + + // The lower and upper bound of the confidence interval given |num_votes| + // samples. If fewer than (lower_bound * num_votes) samples are one then the + // bit is a zero. If more than (upper_bound * num_votes) samples are one then + // the bit is a one. + double lower_bound; + double upper_bound; +}; + +// The fundamental idea of this algorithm is to count the number of reported 1s +// and 0s from a crowdsourced set of votes and look for a threshold that gives +// us confidence that we have seen enough 1s or 0s to assume that the actual +// value is a 1 or 0. +// +// Due to the symmetriy of the problem, we can conveniently choose the following +// null-hypothesis: +// +// N0: The true value of a bit is random on each pageload. +// +// In this case, we expect a binomial distribution B(n, 0.5), for which we can +// find a confidence interval that a sample of size n ends up in this interval. +// If a sample is outside of this interval, we can assume with the given +// confidence that we can reject the null-hypothesis and assume that the actual +// value is 0 or 1. +// +// For the confidence interval, we use the Wilson Score interval. +// https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval#Wilson_score_interval +// +// The confidence intervals are calculate as: +// +// import scipy.stats as st +// import math +// +// def ConfidenceInterval(ph, n, confidence): +// """ +// Args: +// confidence: e.g. 0.95 for a 95% confidence +// ph = p hat (see Wilson Score inverval link above) +// n = number of samples +// """ +// alpha = 1 - confidence +// # for the 95% confidence interval this gives 1.96. +// z = st.norm.ppf(1 - alpha/2) +// +// base = (ph + z*z/(2*n)) / (1 + z*z/n) +// offset = z / (1 + z*z/n) * math.sqrt(ph*(1-ph)/n + z*z/(4*n*n)) +// +// return [base - offset, base + offset] +// +// Note: The string being encoded/decoded for each "sample" consists of a common +// prefix followed by the decimal value of the sample number (i.e., "foo 25"). +// Avoid test cases that skew the distribution of the appended noise to far +// from random (for example, using 0-199, more than 55% of the appended noise +// starts with the ASCII digit '1'). +const DecodeParams kDecodeParams[] = { + // 99.0 % confidence interval + {150, 0.39709349666174232, 0.60290650333825768}, + {256, 0.42052859913480434, 0.57947140086519566}, + + // 99.5% confidence interval + {150, 0.38829956746162475, 0.61170043253837525}, + {256, 0.41359977651950797, 0.58640022348049203}, +}; + +using RandomizedDecoderTest = ::testing::TestWithParam<DecodeParams>; + +// Generate a hex string representing the 128 bit value where each byte has +// value |i|. This lets us spread the seeds across the 128 bit space. +std::string Make128BitSeed(size_t i) { + EXPECT_LT(i, 256u); + return net::HexDump( + std::string(128 / kBitsPerByte, static_cast<char>(i & 0xFF))); +} + +} // namespace + +TEST_P(RandomizedDecoderTest, Decode) { + static const autofill::FormSignature form_signature = 0x8765432187654321; + static const autofill::FieldSignature field_signature = 0xDEADBEEF; + static const char data_type[] = "data_type"; + static const base::StringPiece common_prefix( + "This is the common prefix to encode and recover "); + + const size_t num_votes = GetParam().num_votes; + const double lower_bound = GetParam().lower_bound; + const double upper_bound = GetParam().upper_bound; + + // This vector represents the aggregate counts of the number of times a + // separate encoding of out sample string had a given bit encoded as a one. + std::vector<size_t> num_times_bit_is_1(/*count=*/kMaxLengthInBits, + /*value=*/0); + + // Perform |num_votes| independent encoding operations, with seeds (somewhat) + // evenly spread out across a 128-bit space. + for (size_t i = 0; i < num_votes; ++i) { + // Create a new encoder with a different secret each time. + TestRandomizedEncoder encoder( + Make128BitSeed(i), + autofill::AutofillRandomizedValue_EncodingType_ALL_BITS); + + // Encode the common prefix plus some non-constant data. + std::string encoded = + encoder.Encode(form_signature, field_signature, data_type, + base::StringPrintf("%s%zu", common_prefix.data(), i)); + + // Update |num_times_bit_is_1| for each bit in the encoded string. + for (size_t b = 0; b < kMaxLengthInBits; ++b) { + num_times_bit_is_1[b] += GetBit(encoded, b); + } + } + + // Use |num_times_bit_is_1| to reconstruct the encoded string, bit by bit, + // as well as a record of whether or not each bit in the reconstruction + // buffer was validated with sufficient confidence. + std::string output(kMaxLengthInBytes, static_cast<char>(0)); + std::vector<bool> bit_is_valid(kMaxLengthInBits); + const double threshold_for_zero = lower_bound * num_votes; + const double threshold_for_one = upper_bound * num_votes; + for (size_t b = 0; b < kMaxLengthInBits; ++b) { + if (num_times_bit_is_1[b] < threshold_for_zero) { + // bit it already zero, just mark it as valid + bit_is_valid[b] = true; + } else if (num_times_bit_is_1[b] > threshold_for_one) { + output[b / kBitsPerByte] |= (1 << (b % kBitsPerByte)); + bit_is_valid[b] = true; + } + } + + // Validation: All bits overlapping the constant prefix should be valid. + for (size_t b = 0; b < common_prefix.length() * kBitsPerByte; ++b) { + EXPECT_TRUE(bit_is_valid[b]) << "True bit found to be noise at " << b; + } + + // Validation: All of the recovered prefix bits should match the prefix. + for (size_t i = 0; i < common_prefix.length(); ++i) { + EXPECT_EQ(common_prefix[i], output[i]) << "Incorrect char at offset " << i; + } + + // Validation: Most noise bits should be invalid, but we may get some false + // positives. Instead, we expect that no noise byte will have all of its + // bits turn up as valid. + for (size_t i = common_prefix.length(); i < kMaxLengthInBytes; ++i) { + size_t num_valid_bits = 0; + for (size_t b = 0; b < kBitsPerByte; ++b) { + num_valid_bits += bit_is_valid[i * kBitsPerByte + b]; + } + EXPECT_LT(num_valid_bits, kBitsPerByte) + << "Noise byte at offset " << i << " decoded as " << output[i]; + } +} + +INSTANTIATE_TEST_CASE_P(All, + RandomizedDecoderTest, + ::testing::ValuesIn(kDecodeParams)); diff --git a/chromium/components/autofill/core/browser/search_field_unittest.cc b/chromium/components/autofill/core/browser/search_field_unittest.cc index 4c65cb00fc0..f24235145f6 100644 --- a/chromium/components/autofill/core/browser/search_field_unittest.cc +++ b/chromium/components/autofill/core/browser/search_field_unittest.cc @@ -32,7 +32,8 @@ class SearchFieldTest : public testing::Test { // Downcast for tests. static std::unique_ptr<SearchField> Parse(AutofillScanner* scanner) { std::unique_ptr<FormField> field = SearchField::Parse(scanner); - return base::WrapUnique(static_cast<SearchField*>(field.release())); + return std::unique_ptr<SearchField>( + static_cast<SearchField*>(field.release())); } private: diff --git a/chromium/components/autofill/core/browser/strike_database.cc b/chromium/components/autofill/core/browser/strike_database.cc index 6e0e8b8c36f..0e247e7d2e3 100644 --- a/chromium/components/autofill/core/browser/strike_database.cc +++ b/chromium/components/autofill/core/browser/strike_database.cc @@ -14,18 +14,18 @@ #include "base/task/post_task.h" #include "base/time/time.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" -#include "components/leveldb_proto/proto_database_impl.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/leveldb_proto/public/proto_database_provider.h" namespace autofill { namespace { const char kDatabaseClientName[] = "StrikeService"; -const char kKeyDeliminator[] = "__"; const int kMaxInitAttempts = 3; } // namespace StrikeDatabase::StrikeDatabase(const base::FilePath& database_dir) - : db_(std::make_unique<leveldb_proto::ProtoDatabaseImpl<StrikeData>>( + : db_(leveldb_proto::ProtoDatabaseProvider::CreateUniqueDB<StrikeData>( base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}))), @@ -39,36 +39,35 @@ StrikeDatabase::StrikeDatabase(const base::FilePath& database_dir) StrikeDatabase::~StrikeDatabase() {} -bool StrikeDatabase::IsMaxStrikesLimitReached(const std::string id) { - return GetStrikes(id) >= GetMaxStrikesLimit(); +int StrikeDatabase::AddStrikes(int strikes_increase, const std::string key) { + DCHECK(strikes_increase > 0); + int num_strikes = + strike_map_cache_.count(key) // Cache has entry for |key|. + ? strike_map_cache_[key].num_strikes() + strikes_increase + : strikes_increase; + SetStrikeData(key, num_strikes); + return num_strikes; } -int StrikeDatabase::AddStrike(const std::string id) { - std::string key = GetKey(id); - int num_strikes = strike_map_cache_.count(key) // Cache has entry for |key|. - ? strike_map_cache_[key].num_strikes() + 1 - : 1; - StrikeData data; - data.set_num_strikes(num_strikes); - data.set_last_update_timestamp( - base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds()); - UpdateCache(key, data); - SetProtoStrikeData(key, data, base::DoNothing()); - base::UmaHistogramCounts1000( - "Autofill.StrikeDatabase.NthStrikeAdded." + GetProjectPrefix(), - num_strikes); +int StrikeDatabase::RemoveStrikes(int strikes_decrease, const std::string key) { + DCHECK(strikes_decrease > 0); + DCHECK(strike_map_cache_.count(key)); + int num_strikes = strike_map_cache_[key].num_strikes() - strikes_decrease; + if (num_strikes < 1) { + ClearStrikes(key); + return 0; + } + SetStrikeData(key, num_strikes); return num_strikes; } -int StrikeDatabase::GetStrikes(const std::string id) { - std::string key = GetKey(id); +int StrikeDatabase::GetStrikes(const std::string key) { return strike_map_cache_.count(key) // Cache contains entry for |key|. ? strike_map_cache_[key].num_strikes() : 0; } -void StrikeDatabase::ClearStrikes(const std::string id) { - std::string key = GetKey(id); +void StrikeDatabase::ClearStrikes(const std::string key) { strike_map_cache_.erase(key); ClearAllProtoStrikesForKey(key, base::DoNothing()); } @@ -107,8 +106,13 @@ void StrikeDatabase::OnDatabaseLoadKeysAndEntries( strike_map_cache_.insert(entries->begin(), entries->end()); } -std::string StrikeDatabase::GetKey(const std::string id) { - return GetProjectPrefix() + kKeyDeliminator + id; +void StrikeDatabase::SetStrikeData(const std::string key, int num_strikes) { + StrikeData data; + data.set_num_strikes(num_strikes); + data.set_last_update_timestamp( + AutofillClock::Now().ToDeltaSinceWindowsEpoch().InMicroseconds()); + UpdateCache(key, data); + SetProtoStrikeData(key, data, base::DoNothing()); } void StrikeDatabase::GetProtoStrikes(const std::string key, diff --git a/chromium/components/autofill/core/browser/strike_database.h b/chromium/components/autofill/core/browser/strike_database.h index 5c69ace7f95..bea6da0aa80 100644 --- a/chromium/components/autofill/core/browser/strike_database.h +++ b/chromium/components/autofill/core/browser/strike_database.h @@ -13,7 +13,7 @@ #include "base/callback_forward.h" #include "base/memory/weak_ptr.h" #include "components/keyed_service/core/keyed_service.h" -#include "components/leveldb_proto/proto_database.h" +#include "components/leveldb_proto/public/proto_database.h" namespace autofill { class StrikeData; @@ -22,6 +22,10 @@ class StrikeData; // the user. Projects can earn strikes in a number of ways; for instance, if a // user ignores or declines a prompt, or if a user accepts a prompt but the task // fails. +// This class is a Singleton which contains StrikeData information for all +// projects. It should not be used directly, but rather by implementing the +// StrikeDatabaseIntegratorBase (which contains a pointer to StrikeDatabase) +// for specific projects. class StrikeDatabase : public KeyedService { public: using ClearStrikesCallback = base::RepeatingCallback<void(bool success)>; @@ -43,19 +47,23 @@ class StrikeDatabase : public KeyedService { explicit StrikeDatabase(const base::FilePath& database_dir); ~StrikeDatabase() override; - bool IsMaxStrikesLimitReached(const std::string id); + // Increases in-memory cache by |strikes_increase| and updates underlying + // ProtoDatabase. + int AddStrikes(int strikes_increase, const std::string key); - // Increments in-memory cache and updates underlying ProtoDatabase. - int AddStrike(const std::string id); + // Removes |strikes_decrease| in-memory cache strikes, updates + // last_update_timestamp, and updates underlying ProtoDatabase. + int RemoveStrikes(int strikes_decrease, const std::string key); // Returns strike count from in-memory cache. - int GetStrikes(const std::string id); + int GetStrikes(const std::string key); // Removes all database entries from in-memory cache and underlying // ProtoDatabase. - void ClearStrikes(const std::string id); + void ClearStrikes(const std::string key); protected: + friend class StrikeDatabaseIntegratorBase; // Constructor for testing that does not initialize a ProtoDatabase. StrikeDatabase(); @@ -80,6 +88,10 @@ class StrikeDatabase : public KeyedService { StrikeDatabaseEmptyOnAutofillRemoveEverything); FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, GetKeyForCreditCardSaveTest); + FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, + GetIdForCreditCardSaveTest); + FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, + RemoveExpiredStrikesOnLoadTest); friend class StrikeDatabaseTest; friend class StrikeDatabaseTester; @@ -89,16 +101,9 @@ class StrikeDatabase : public KeyedService { bool success, std::unique_ptr<std::map<std::string, StrikeData>> entries); - // Returns a prefix unique to each project, which will be used to create - // database key. - virtual std::string GetProjectPrefix() = 0; - - // Returns the maximum number of strikes after which the project's Autofill - // opportunity stops being offered. - virtual int GetMaxStrikesLimit() = 0; - - // Generates key based on project-specific string identifier. - std::string GetKey(const std::string id); + // Updates the StrikeData for |key| in the cache and ProtoDatabase to have + // |num_stikes|, and the current time as timestamp. + void SetStrikeData(const std::string key, int num_strikes); // Passes the number of strikes for |key| to |outer_callback|. In the case // that the database fails to retrieve the strike update or if no entry is diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_base.cc b/chromium/components/autofill/core/browser/strike_database_integrator_base.cc new file mode 100644 index 00000000000..f6438197ffd --- /dev/null +++ b/chromium/components/autofill/core/browser/strike_database_integrator_base.cc @@ -0,0 +1,92 @@ +// 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 "components/autofill/core/browser/strike_database_integrator_base.h" + +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/metrics/histogram_functions.h" +#include "base/task/post_task.h" +#include "base/time/time.h" +#include "components/autofill/core/browser/proto/strike_data.pb.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/leveldb_proto/public/proto_database_provider.h" + +namespace autofill { + +namespace { +const char kKeyDeliminator[] = "__"; +} // namespace + +StrikeDatabaseIntegratorBase::StrikeDatabaseIntegratorBase( + StrikeDatabase* strike_database) + : strike_database_(strike_database) {} + +StrikeDatabaseIntegratorBase::~StrikeDatabaseIntegratorBase() {} + +bool StrikeDatabaseIntegratorBase::IsMaxStrikesLimitReached( + const std::string id) { + CheckIdUniqueness(id); + return GetStrikes(id) >= GetMaxStrikesLimit(); +} + +int StrikeDatabaseIntegratorBase::AddStrike(const std::string id) { + CheckIdUniqueness(id); + return AddStrikes(1, id); +} + +int StrikeDatabaseIntegratorBase::AddStrikes(int strikes_increase, + const std::string id) { + CheckIdUniqueness(id); + int num_strikes = strike_database_->AddStrikes(strikes_increase, GetKey(id)); + base::UmaHistogramCounts1000( + "Autofill.StrikeDatabase.NthStrikeAdded." + GetProjectPrefix(), + num_strikes); + return num_strikes; +} + +int StrikeDatabaseIntegratorBase::RemoveStrike(const std::string id) { + CheckIdUniqueness(id); + return strike_database_->RemoveStrikes(1, GetKey(id)); +} + +int StrikeDatabaseIntegratorBase::RemoveStrikes(int strikes_decrease, + const std::string id) { + CheckIdUniqueness(id); + return strike_database_->RemoveStrikes(strikes_decrease, GetKey(id)); +} + +int StrikeDatabaseIntegratorBase::GetStrikes(const std::string id) { + CheckIdUniqueness(id); + return strike_database_->GetStrikes(GetKey(id)); +} + +void StrikeDatabaseIntegratorBase::ClearStrikes(const std::string id) { + CheckIdUniqueness(id); + strike_database_->ClearStrikes(GetKey(id)); +} + +void StrikeDatabaseIntegratorBase::RemoveExpiredStrikes() { + std::vector<std::string> expired_keys; + for (auto entry : strike_database_->strike_map_cache_) { + if (AutofillClock::Now().ToDeltaSinceWindowsEpoch().InMicroseconds() - + entry.second.last_update_timestamp() > + GetExpiryTimeMicros()) { + if (strike_database_->GetStrikes(entry.first) > 0) + expired_keys.push_back(entry.first); + } + } + for (std::string key : expired_keys) + strike_database_->RemoveStrikes(1, key); +} + +std::string StrikeDatabaseIntegratorBase::GetKey(const std::string id) { + return GetProjectPrefix() + kKeyDeliminator + id; +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_base.h b/chromium/components/autofill/core/browser/strike_database_integrator_base.h new file mode 100644 index 00000000000..9f207da9d94 --- /dev/null +++ b/chromium/components/autofill/core/browser/strike_database_integrator_base.h @@ -0,0 +1,102 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_BASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_BASE_H_ + +#include "components/autofill/core/browser/strike_database.h" + +namespace autofill { + +namespace { +static const char kSharedId[] = "shared_id"; +} // namespace + +// Contains virtual functions for per-project implementations of StrikeDatabase +// to interface from, as well as a pointer to StrikeDatabase. This class is +// seperated from StrikeDatabase since we only want StrikeDatabase's cache to +// be loaded once per browser session. +class StrikeDatabaseIntegratorBase { + public: + StrikeDatabaseIntegratorBase(StrikeDatabase* strike_database); + virtual ~StrikeDatabaseIntegratorBase(); + + // Returns whether or not strike count for |id| has reached the strike limit + // set by GetMaxStrikesLimit(). + bool IsMaxStrikesLimitReached(const std::string id = kSharedId); + + // Increments in-memory cache and updates underlying ProtoDatabase. + int AddStrike(const std::string id = kSharedId); + + // Increases in-memory cache by |strikes_increase| and updates underlying + // ProtoDatabase. + int AddStrikes(int strikes_increase, const std::string id = kSharedId); + + // Removes an in-memory cache strike, updates last_update_timestamp, and + // updates underlying ProtoDatabase. + int RemoveStrike(const std::string id = kSharedId); + + // Removes |strikes_decrease| in-memory cache strikes, updates + // |last_update_timestamp|, and updates underlying ProtoDatabase. + int RemoveStrikes(int strikes_decrease, const std::string id = kSharedId); + + // Returns strike count from in-memory cache. + int GetStrikes(const std::string id = kSharedId); + + // Removes all database entries from in-memory cache and underlying + // ProtoDatabase. + void ClearStrikes(const std::string id = kSharedId); + + protected: + // Removes all strikes in which it has been longer than GetExpiryTimeMicros() + // past |last_update_timestamp|. + void RemoveExpiredStrikes(); + + private: + FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest, + StrikeDatabaseEmptyOnAutofillRemoveEverything); + FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, + GetKeyForCreditCardSaveTest); + FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, + GetIdForCreditCardSaveTest); + FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, + RemoveExpiredStrikesTest); + FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationStrikeDatabaseTest, + RemoveExpiredStrikesTest); + friend class StrikeDatabaseTest; + friend class StrikeDatabaseTester; + + StrikeDatabase* strike_database_; + + // For projects in which strikes don't have unique identifiers, the + // id suffix is set to |kSharedId|. This makes sure that projects requiring + // unique IDs always specify |id| instead of relying on the default shared + // value, while projects where unique IDs are unnecessary always fall back to + // the default shared value. + void CheckIdUniqueness(std::string id) { + DCHECK(UniqueIdsRequired() == (id != kSharedId)); + } + + // Generates key based on project-specific string identifier. + std::string GetKey(const std::string id); + + // Returns a prefix unique to each project, which will be used to create + // database key. + virtual std::string GetProjectPrefix() = 0; + + // Returns the maximum number of strikes after which the project's Autofill + // opportunity stops being offered. + virtual int GetMaxStrikesLimit() = 0; + + // Returns the time after which the most recent strike should expire. + virtual long long GetExpiryTimeMicros() = 0; + + // Returns whether or not a unique string identifier is required for every + // strike in this project. + virtual bool UniqueIdsRequired() = 0; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_BASE_H_ diff --git a/chromium/components/autofill/core/browser/strike_database_unittest.cc b/chromium/components/autofill/core/browser/strike_database_unittest.cc index 07ea6bbe91a..57075bb0bac 100644 --- a/chromium/components/autofill/core/browser/strike_database_unittest.cc +++ b/chromium/components/autofill/core/browser/strike_database_unittest.cc @@ -45,20 +45,6 @@ class TestStrikeDatabase : public StrikeDatabase { private: DISALLOW_COPY_AND_ASSIGN(TestStrikeDatabase); - - // Do not use. This virtual function needed to be implemented but - // TestStrikeDatabase is not a project class. - std::string GetProjectPrefix() override { - NOTIMPLEMENTED(); - return " "; - } - - // Do not use. This virtual function needed to be implemented but - // TestStrikeDatabase is not a project class. - int GetMaxStrikesLimit() override { - NOTIMPLEMENTED(); - return 0; - } }; } // anonymous namespace diff --git a/chromium/components/autofill/core/browser/suggestion_selection.cc b/chromium/components/autofill/core/browser/suggestion_selection.cc index ca3daa9691a..354c174d5b0 100644 --- a/chromium/components/autofill/core/browser/suggestion_selection.cc +++ b/chromium/components/autofill/core/browser/suggestion_selection.cc @@ -51,11 +51,11 @@ base::string16 GetInfoInOneLine(const AutofillProfile* profile, // As of November 2018, 50 profiles should be more than enough to cover at least // 99% of all times the dropdown is shown. -extern const size_t kMaxSuggestedProfilesCount = 50; +constexpr size_t kMaxSuggestedProfilesCount = 50; // As of November 2018, displaying 10 suggestions cover at least 99% of the // indices clicked by our users. The suggestions will also refine as they type. -extern const size_t kMaxUniqueSuggestionsCount = 10; +constexpr size_t kMaxUniqueSuggestionsCount = 10; std::vector<Suggestion> GetPrefixMatchedSuggestions( const AutofillType& type, @@ -201,4 +201,4 @@ void RemoveProfilesNotUsedSinceTimestamp( } } // namespace suggestion_selection -} // namespace autofill
\ No newline at end of file +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_autofill_async_observer.cc b/chromium/components/autofill/core/browser/test_autofill_async_observer.cc new file mode 100644 index 00000000000..d0f3133ad93 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_autofill_async_observer.cc @@ -0,0 +1,28 @@ +// Copyright (c) 2019 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 "components/autofill/core/browser/test_autofill_async_observer.h" + +#include "base/run_loop.h" + +namespace autofill { +namespace test { + +TestAutofillAsyncObserver::TestAutofillAsyncObserver( + NotificationType notification_type, + bool detach_on_notify) + : AutofillObserver(notification_type, detach_on_notify), run_loop_() {} + +TestAutofillAsyncObserver::~TestAutofillAsyncObserver() = default; + +void TestAutofillAsyncObserver::OnNotify() { + run_loop_.Quit(); +} + +void TestAutofillAsyncObserver::Wait() { + run_loop_.Run(); +} + +} // namespace test +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_autofill_async_observer.h b/chromium/components/autofill/core/browser/test_autofill_async_observer.h new file mode 100644 index 00000000000..17afb414084 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_autofill_async_observer.h @@ -0,0 +1,42 @@ +// Copyright 2019 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_ASYNC_OBSERVER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_ASYNC_OBSERVER_H_ + +#include "base/observer_list_types.h" +#include "base/run_loop.h" +#include "components/autofill/core/browser/autofill_observer.h" + +namespace autofill { +namespace test { + +// Observer which allows to block a thread (wait) until it gets notified with a +// specific NotificationType. Blocks the thread via a base::RunLoop. +// This is a very useful mechanism for browsers tests. +class TestAutofillAsyncObserver : public AutofillObserver { + public: + // |notification_type| is the notification type that this observer observes. + // |detach_on_notify| will let the AutofillSubject know that this + // observer only wants to watch for the first notification of that type. + TestAutofillAsyncObserver(NotificationType notification_type, + bool detach_on_notify = false); + + ~TestAutofillAsyncObserver() override; + + // Invoked by the watched AutofillSubject, this will effectively quit the + // current run loop. + void OnNotify() override; + + // Blocks the thread until the expected notification occurs. + void Wait(); + + private: + base::RunLoop run_loop_; +}; + +} // namespace test +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_ASYNC_OBSERVER_H_ diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc index acf9c148bf2..b26056019a3 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.cc +++ b/chromium/components/autofill/core/browser/test_autofill_client.cc @@ -21,8 +21,9 @@ PersonalDataManager* TestAutofillClient::GetPersonalDataManager() { return &test_personal_data_manager_; } -scoped_refptr<AutofillWebDataService> TestAutofillClient::GetDatabase() { - return scoped_refptr<AutofillWebDataService>(nullptr); +AutocompleteHistoryManager* +TestAutofillClient::GetAutocompleteHistoryManager() { + return &mock_autocomplete_history_manager_; } PrefService* TestAutofillClient::GetPrefs() { @@ -49,6 +50,10 @@ LegacyStrikeDatabase* TestAutofillClient::GetLegacyStrikeDatabase() { return test_legacy_strike_database_.get(); } +StrikeDatabase* TestAutofillClient::GetStrikeDatabase() { + return test_strike_database_.get(); +} + ukm::UkmRecorder* TestAutofillClient::GetUkmRecorder() { return ukm::UkmRecorder::Get(); } @@ -61,10 +66,6 @@ ukm::SourceId TestAutofillClient::GetUkmSourceId() { return source_id_; } -void TestAutofillClient::InitializeUKMSources() { - UpdateSourceURL(GetUkmRecorder(), source_id_, form_origin_); -} - AddressNormalizer* TestAutofillClient::GetAddressNormalizer() { return &test_address_normalizer_; } @@ -92,6 +93,7 @@ void TestAutofillClient::ShowLocalCardMigrationDialog( void TestAutofillClient::ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { // If |migration_card_selection_| hasn't been preset by tests, default to @@ -120,10 +122,10 @@ void TestAutofillClient::ConfirmSaveAutofillProfile( void TestAutofillClient::ConfirmSaveCreditCardLocally( const CreditCard& card, bool show_prompt, - base::OnceClosure callback) { + LocalSaveCardPromptCallback callback) { confirm_save_credit_card_locally_called_ = true; offer_to_save_credit_card_bubble_was_shown_ = show_prompt; - std::move(callback).Run(); + std::move(callback).Run(AutofillClient::ACCEPTED); } #if defined(OS_ANDROID) @@ -140,9 +142,9 @@ void TestAutofillClient::ConfirmSaveCreditCardToCloud( bool should_request_name_from_user, bool should_request_expiration_date_from_user, bool show_prompt, - UserAcceptedUploadCallback callback) { + UploadSaveCardPromptCallback callback) { offer_to_save_credit_card_bubble_was_shown_ = show_prompt; - std::move(callback).Run({}); + std::move(callback).Run(AutofillClient::ACCEPTED, {}); } void TestAutofillClient::ConfirmCreditCardFillAssist( @@ -151,11 +153,6 @@ void TestAutofillClient::ConfirmCreditCardFillAssist( std::move(callback).Run(); } -void TestAutofillClient::LoadRiskData( - base::OnceCallback<void(const std::string&)> callback) { - std::move(callback).Run("some risk data"); -} - bool TestAutofillClient::HasCreditCardScanFeature() { return false; } @@ -193,8 +190,6 @@ void TestAutofillClient::DidFillOrPreviewField( const base::string16& profile_full_name) { } -void TestAutofillClient::DidInteractWithNonsecureCreditCardInput() {} - bool TestAutofillClient::IsContextSecure() { // Simplified secure context check for tests. return form_origin_.SchemeIs("https"); @@ -204,12 +199,21 @@ bool TestAutofillClient::ShouldShowSigninPromo() { return false; } -void TestAutofillClient::ExecuteCommand(int id) {} - bool TestAutofillClient::AreServerCardsSupported() { return true; } +void TestAutofillClient::ExecuteCommand(int id) {} + +void TestAutofillClient::LoadRiskData( + base::OnceCallback<void(const std::string&)> callback) { + std::move(callback).Run("some risk data"); +} + +void TestAutofillClient::InitializeUKMSources() { + UpdateSourceURL(GetUkmRecorder(), source_id_, form_origin_); +} + void TestAutofillClient::set_form_origin(const GURL& url) { form_origin_ = url; // Also reset source_id_. diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h index 656a2732e1b..c2237b15534 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.h +++ b/chromium/components/autofill/core/browser/test_autofill_client.h @@ -15,11 +15,13 @@ #include "base/macros.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/test_address_normalizer.h" #include "components/autofill/core/browser/test_form_data_importer.h" #include "components/autofill/core/browser/test_legacy_strike_database.h" #include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/browser/test_strike_database.h" #include "components/prefs/pref_service.h" #include "components/ukm/test_ukm_recorder.h" #include "services/identity/public/cpp/identity_test_environment.h" @@ -32,15 +34,16 @@ class TestAutofillClient : public AutofillClient { TestAutofillClient(); ~TestAutofillClient() override; - // AutofillClient implementation. + // AutofillClient: PersonalDataManager* GetPersonalDataManager() override; - scoped_refptr<AutofillWebDataService> GetDatabase() override; + AutocompleteHistoryManager* GetAutocompleteHistoryManager() override; PrefService* GetPrefs() override; syncer::SyncService* GetSyncService() override; identity::IdentityManager* GetIdentityManager() override; FormDataImporter* GetFormDataImporter() override; payments::PaymentsClient* GetPaymentsClient() override; LegacyStrikeDatabase* GetLegacyStrikeDatabase() override; + StrikeDatabase* GetStrikeDatabase() override; ukm::UkmRecorder* GetUkmRecorder() override; ukm::SourceId GetUkmSourceId() override; AddressNormalizer* GetAddressNormalizer() override; @@ -54,6 +57,7 @@ class TestAutofillClient : public AutofillClient { base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override; void ShowLocalCardMigrationResults( @@ -63,25 +67,23 @@ class TestAutofillClient : public AutofillClient { MigrationDeleteCardCallback delete_local_card_callback) override; void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; - void ConfirmSaveCreditCardLocally(const CreditCard& card, - bool show_prompt, - base::OnceClosure callback) override; + void ConfirmSaveCreditCardLocally( + const CreditCard& card, + bool show_prompt, + LocalSaveCardPromptCallback callback) override; #if defined(OS_ANDROID) void ConfirmAccountNameFixFlow( base::OnceCallback<void(const base::string16&)> callback) override; #endif // defined(OS_ANDROID) - void ConfirmSaveCreditCardToCloud( const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, bool should_request_name_from_user, bool should_request_expiration_date_from_user, bool show_prompt, - UserAcceptedUploadCallback callback) override; + UploadSaveCardPromptCallback callback) override; void ConfirmCreditCardFillAssist(const CreditCard& card, base::OnceClosure callback) override; - void LoadRiskData( - base::OnceCallback<void(const std::string&)> callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowAutofillPopup( @@ -100,7 +102,6 @@ class TestAutofillClient : public AutofillClient { const std::vector<autofill::FormStructure*>& forms) override; void DidFillOrPreviewField(const base::string16& autofilled_value, const base::string16& profile_full_name) override; - void DidInteractWithNonsecureCreditCardInput() override; // By default, TestAutofillClient will report that the context is // secure. This can be adjusted by calling set_form_origin() with an // http:// URL. @@ -108,6 +109,11 @@ class TestAutofillClient : public AutofillClient { bool ShouldShowSigninPromo() override; bool AreServerCardsSupported() override; void ExecuteCommand(int id) override; + + // RiskDataLoader: + void LoadRiskData( + base::OnceCallback<void(const std::string&)> callback) override; + // Initializes UKM source from form_origin_. This needs to be called // in unittests after calling Purge for ukm recorder to re-initialize // sources. @@ -117,9 +123,14 @@ class TestAutofillClient : public AutofillClient { prefs_ = std::move(prefs); } + void set_test_legacy_strike_database( + std::unique_ptr<TestLegacyStrikeDatabase> test_legacy_strike_database) { + test_legacy_strike_database_ = std::move(test_legacy_strike_database); + } + void set_test_strike_database( - std::unique_ptr<TestLegacyStrikeDatabase> test_strike_database) { - test_legacy_strike_database_ = std::move(test_strike_database); + std::unique_ptr<TestStrikeDatabase> test_strike_database) { + test_strike_database_ = std::move(test_strike_database); } void set_test_payments_client( @@ -150,6 +161,10 @@ class TestAutofillClient : public AutofillClient { return offer_to_save_credit_card_bubble_was_shown_.value(); } + MockAutocompleteHistoryManager* GetMockAutocompleteHistoryManager() { + return &mock_autocomplete_history_manager_; + } + void set_migration_card_selections( const std::vector<std::string>& migration_card_selection) { migration_card_selection_ = migration_card_selection; @@ -166,10 +181,12 @@ class TestAutofillClient : public AutofillClient { syncer::SyncService* test_sync_service_ = nullptr; TestAddressNormalizer test_address_normalizer_; TestPersonalDataManager test_personal_data_manager_; + MockAutocompleteHistoryManager mock_autocomplete_history_manager_; // NULL by default. std::unique_ptr<PrefService> prefs_; std::unique_ptr<TestLegacyStrikeDatabase> test_legacy_strike_database_; + std::unique_ptr<TestStrikeDatabase> test_strike_database_; std::unique_ptr<payments::PaymentsClient> payments_client_; std::unique_ptr<FormDataImporter> form_data_importer_; GURL form_origin_; diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc index 4ffa86aed6f..23e869b9916 100644 --- a/chromium/components/autofill/core/browser/test_autofill_driver.cc +++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc @@ -78,18 +78,6 @@ gfx::RectF TestAutofillDriver::TransformBoundingBoxToViewportCoordinates( return bounding_box; } -void TestAutofillDriver::DidInteractWithCreditCardForm() { - did_interact_with_credit_card_form_ = true; -} - -void TestAutofillDriver::ClearDidInteractWithCreditCardForm() { - did_interact_with_credit_card_form_ = false; -} - -bool TestAutofillDriver::GetDidInteractWithCreditCardForm() const { - return did_interact_with_credit_card_form_; -} - void TestAutofillDriver::SetIsIncognito(bool is_incognito) { is_incognito_ = is_incognito; } diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h index dd742de0c38..e04c11db813 100644 --- a/chromium/components/autofill/core/browser/test_autofill_driver.h +++ b/chromium/components/autofill/core/browser/test_autofill_driver.h @@ -44,15 +44,10 @@ class TestAutofillDriver : public AutofillDriver { void PopupHidden() override; gfx::RectF TransformBoundingBoxToViewportCoordinates( const gfx::RectF& bounding_box) override; - void DidInteractWithCreditCardForm() override; // Methods unique to TestAutofillDriver that tests can use to specialize // functionality. - void ClearDidInteractWithCreditCardForm(); - - bool GetDidInteractWithCreditCardForm() const; - void SetIsIncognito(bool is_incognito); void SetIsInMainFrame(bool is_in_main_frame); @@ -68,7 +63,6 @@ class TestAutofillDriver : public AutofillDriver { scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; bool is_incognito_ = false; bool is_in_main_frame_ = false; - bool did_interact_with_credit_card_form_ = false; DISALLOW_COPY_AND_ASSIGN(TestAutofillDriver); }; diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.cc b/chromium/components/autofill/core/browser/test_autofill_manager.cc index 8898d9326bf..a398f1f92e7 100644 --- a/chromium/components/autofill/core/browser/test_autofill_manager.cc +++ b/chromium/components/autofill/core/browser/test_autofill_manager.cc @@ -7,6 +7,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/mock_autocomplete_history_manager.h" #include "components/autofill/core/browser/test_form_structure.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -14,10 +15,15 @@ namespace autofill { -TestAutofillManager::TestAutofillManager(AutofillDriver* driver, - AutofillClient* client, - TestPersonalDataManager* personal_data) - : AutofillManager(driver, client, personal_data), +TestAutofillManager::TestAutofillManager( + AutofillDriver* driver, + AutofillClient* client, + TestPersonalDataManager* personal_data, + MockAutocompleteHistoryManager* autocomplete_history_manager) + : AutofillManager(driver, + client, + personal_data, + autocomplete_history_manager), personal_data_(personal_data) {} TestAutofillManager::~TestAutofillManager() {} @@ -44,11 +50,10 @@ void TestAutofillManager::UploadFormData(const FormStructure& submitted_form, bool TestAutofillManager::MaybeStartVoteUploadProcess( std::unique_ptr<FormStructure> form_structure, - const base::TimeTicks& timestamp, bool observed_submission) { run_loop_ = std::make_unique<base::RunLoop>(); - if (AutofillManager::MaybeStartVoteUploadProcess( - std::move(form_structure), timestamp, observed_submission)) { + if (AutofillManager::MaybeStartVoteUploadProcess(std::move(form_structure), + observed_submission)) { run_loop_->Run(); return true; } diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.h b/chromium/components/autofill/core/browser/test_autofill_manager.h index 64e00d905bc..edd6ad02f0e 100644 --- a/chromium/components/autofill/core/browser/test_autofill_manager.h +++ b/chromium/components/autofill/core/browser/test_autofill_manager.h @@ -22,12 +22,15 @@ class AutofillClient; class AutofillDriver; class FormStructure; class TestPersonalDataManager; +class MockAutocompleteHistoryManager; class TestAutofillManager : public AutofillManager { public: - TestAutofillManager(AutofillDriver* driver, - AutofillClient* client, - TestPersonalDataManager* personal_data); + TestAutofillManager( + AutofillDriver* driver, + AutofillClient* client, + TestPersonalDataManager* personal_data, + MockAutocompleteHistoryManager* autocomplete_history_manager); ~TestAutofillManager() override; // AutofillManager overrides. @@ -38,7 +41,6 @@ class TestAutofillManager : public AutofillManager { bool observed_submission) override; bool MaybeStartVoteUploadProcess( std::unique_ptr<FormStructure> form_structure, - const base::TimeTicks& timestamp, bool observed_submission) override; void UploadFormDataAsyncCallback(const FormStructure* submitted_form, const base::TimeTicks& interaction_time, diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.h b/chromium/components/autofill/core/browser/test_autofill_provider.h index a9e620793c3..8c69b47e99e 100644 --- a/chromium/components/autofill/core/browser/test_autofill_provider.h +++ b/chromium/components/autofill/core/browser/test_autofill_provider.h @@ -36,8 +36,7 @@ class TestAutofillProvider : public AutofillProvider { void OnFormSubmitted(AutofillHandlerProxy* handler, const FormData& form, bool known_success, - SubmissionSource source, - base::TimeTicks timestamp) override {} + SubmissionSource source) override {} void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override; void OnFocusOnFormField(AutofillHandlerProxy* handler, const FormData& form, diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc b/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc index ab8a64099d2..21007fe0eb0 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc @@ -33,6 +33,15 @@ bool TestCreditCardSaveManager::CreditCardWasUploaded() { return credit_card_was_uploaded_; } +void TestCreditCardSaveManager::set_show_save_prompt(bool show_save_prompt) { + show_save_prompt_ = show_save_prompt; +} + +void TestCreditCardSaveManager::set_upload_request_card_number( + const base::string16& credit_card_number) { + upload_request_.card.SetNumber(credit_card_number); +} + void TestCreditCardSaveManager::OnDidUploadCard( AutofillClient::PaymentsRpcResult result, const std::string& server_id) { diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_manager.h b/chromium/components/autofill/core/browser/test_credit_card_save_manager.h index cc157fc47fa..c01c302f7b8 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/test_credit_card_save_manager.h @@ -34,6 +34,10 @@ class TestCreditCardSaveManager : public CreditCardSaveManager { // Returns whether OnDidUploadCard() was called. bool CreditCardWasUploaded(); + void set_show_save_prompt(bool show_save_prompt); + + void set_upload_request_card_number(const base::string16& credit_card_number); + private: void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, const std::string& server_id) override; @@ -41,6 +45,12 @@ class TestCreditCardSaveManager : public CreditCardSaveManager { bool credit_card_upload_enabled_ = false; bool credit_card_was_uploaded_ = false; + FRIEND_TEST_ALL_PREFIXES( + CreditCardSaveManagerTest, + UploadCreditCard_NumLegacyStrikesLoggedOnUploadNotSuccess); + FRIEND_TEST_ALL_PREFIXES(CreditCardSaveManagerTest, + UploadCreditCard_NumStrikesLoggedOnUploadNotSuccess); + DISALLOW_COPY_AND_ASSIGN(TestCreditCardSaveManager); }; diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.cc b/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.cc index da24bb69ed9..ebeb05ae93c 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.cc +++ b/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.cc @@ -7,9 +7,7 @@ namespace autofill { TestCreditCardSaveStrikeDatabase::TestCreditCardSaveStrikeDatabase( - const base::FilePath& database_dir) - : CreditCardSaveStrikeDatabase(database_dir) { - database_initialized_ = true; -} + StrikeDatabase* strike_database) + : CreditCardSaveStrikeDatabase(strike_database) {} } // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.h b/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.h index 21c33a52404..070337c3510 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.h +++ b/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.h @@ -11,7 +11,7 @@ namespace autofill { class TestCreditCardSaveStrikeDatabase : public CreditCardSaveStrikeDatabase { public: - TestCreditCardSaveStrikeDatabase(const base::FilePath& database_dir); + TestCreditCardSaveStrikeDatabase(StrikeDatabase* strike_database); }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_data_creator.cc b/chromium/components/autofill/core/browser/test_data_creator.cc new file mode 100644 index 00000000000..5ef889268d5 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_data_creator.cc @@ -0,0 +1,204 @@ +// 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 "components/autofill/core/browser/test_data_creator.h" + +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_features.h" + +namespace autofill { + +namespace { +// Time delta to create test data. +base::TimeDelta DeletableUseDateDelta( + const base::TimeDelta& cc_deletion_delta) { + static base::TimeDelta delta = + cc_deletion_delta + base::TimeDelta::FromDays(5); + return delta; +} +base::TimeDelta DeletableExpiryDateDelta( + const base::TimeDelta& cc_deletion_delta) { + static base::TimeDelta delta = + cc_deletion_delta + base::TimeDelta::FromDays(45); + return delta; +} +} // namespace + +TestDataCreator::TestDataCreator(base::TimeDelta cc_deletion_delta, + std::string app_locale) + : cc_deletion_delta_(cc_deletion_delta), app_locale_(app_locale) {} + +void TestDataCreator::MaybeAddTestProfiles( + const base::RepeatingCallback<void(const AutofillProfile&)>& + add_profile_callback) { + if (has_created_test_addresses_ || + !base::FeatureList::IsEnabled(features::kAutofillCreateDataForTest)) + return; + + has_created_test_addresses_ = true; + + for (const auto& profile : GetTestProfiles()) { + add_profile_callback.Run(profile); + } + + DLOG(WARNING) << this << " added fake autofill profiles."; +} + +void TestDataCreator::MaybeAddTestCreditCards( + const base::RepeatingCallback<void(const CreditCard&)>& add_cc_callback) { + if (has_created_test_credit_cards_ || + !base::FeatureList::IsEnabled(features::kAutofillCreateDataForTest)) + return; + + has_created_test_credit_cards_ = true; + + for (const auto& credit_card : GetTestCreditCards()) { + add_cc_callback.Run(credit_card); + } + + DLOG(WARNING) << this << " added fake credit cards."; +} + +std::vector<AutofillProfile> TestDataCreator::GetTestProfiles() { + return {CreateBasicTestAddress(), CreateDisusedTestAddress(), + CreateDisusedDeletableTestAddress()}; +} + +std::vector<CreditCard> TestDataCreator::GetTestCreditCards() { + return {CreateBasicTestCreditCard(), CreateDisusedTestCreditCard(), + CreateDisusedDeletableTestCreditCard()}; +} + +AutofillProfile TestDataCreator::CreateBasicTestAddress() { + const base::Time use_date = + AutofillClock::Now() - base::TimeDelta::FromDays(20); + AutofillProfile profile; + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("John McTester"), app_locale_); + profile.SetInfo(COMPANY_NAME, base::UTF8ToUTF16("Test Inc."), app_locale_); + profile.SetInfo(EMAIL_ADDRESS, + base::UTF8ToUTF16("jmctester@fake.chromium.org"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("123 Invented Street"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Suite A"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Mountain View"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("California"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("94043"), app_locale_); + profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), app_locale_); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0173"), + app_locale_); + profile.set_use_date(use_date); + return profile; +} + +AutofillProfile TestDataCreator::CreateDisusedTestAddress() { + const base::Time use_date = + AutofillClock::Now() - base::TimeDelta::FromDays(185); + AutofillProfile profile; + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("Polly Disused"), app_locale_); + profile.SetInfo(COMPANY_NAME, + base::UTF8ToUTF16(base::StringPrintf( + "%lld Inc.", static_cast<long long>(use_date.ToTimeT()))), + app_locale_); + profile.SetInfo(EMAIL_ADDRESS, + base::UTF8ToUTF16("polly.disused@fake.chromium.org"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("456 Disused Lane"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Apt. B"), app_locale_); + profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Austin"), app_locale_); + profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("Texas"), app_locale_); + profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("73301"), app_locale_); + profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), app_locale_); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0174"), + app_locale_); + profile.set_use_date(use_date); + return profile; +} + +AutofillProfile TestDataCreator::CreateDisusedDeletableTestAddress() { + const base::Time use_date = + AutofillClock::Now() - base::TimeDelta::FromDays(400); + AutofillProfile profile; + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("Polly Deletable"), app_locale_); + profile.SetInfo(COMPANY_NAME, + base::UTF8ToUTF16(base::StringPrintf( + "%lld Inc.", static_cast<long long>(use_date.ToTimeT()))), + app_locale_); + profile.SetInfo(EMAIL_ADDRESS, + base::UTF8ToUTF16("polly.deletable@fake.chromium.org"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("459 Deletable Lane"), + app_locale_); + profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Apt. B"), app_locale_); + profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Austin"), app_locale_); + profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("Texas"), app_locale_); + profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("73301"), app_locale_); + profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), app_locale_); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0274"), + app_locale_); + profile.set_use_date(use_date); + return profile; +} + +// Create a card expiring 500 days from now which was last used 10 days ago. +CreditCard TestDataCreator::CreateBasicTestCreditCard() { + const base::Time now = AutofillClock::Now(); + const base::Time use_date = now - base::TimeDelta::FromDays(10); + base::Time::Exploded expiry_date; + (now + base::TimeDelta::FromDays(500)).LocalExplode(&expiry_date); + + CreditCard credit_card; + credit_card.SetInfo(CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16("Alice Testerson"), app_locale_); + credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("4545454545454545"), + app_locale_); + credit_card.SetExpirationMonth(expiry_date.month); + credit_card.SetExpirationYear(expiry_date.year); + credit_card.set_use_date(use_date); + return credit_card; +} + +CreditCard TestDataCreator::CreateDisusedTestCreditCard() { + const base::Time now = AutofillClock::Now(); + const base::Time use_date = now - base::TimeDelta::FromDays(185); + base::Time::Exploded expiry_date; + (now - base::TimeDelta::FromDays(200)).LocalExplode(&expiry_date); + + CreditCard credit_card; + credit_card.SetInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16("Bob Disused"), + app_locale_); + credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("4111111111111111"), + app_locale_); + credit_card.SetExpirationMonth(expiry_date.month); + credit_card.SetExpirationYear(expiry_date.year); + credit_card.set_use_date(use_date); + return credit_card; +} + +CreditCard TestDataCreator::CreateDisusedDeletableTestCreditCard() { + const base::Time now = AutofillClock::Now(); + const base::Time use_date = now - DeletableUseDateDelta(cc_deletion_delta_); + base::Time::Exploded expiry_date; + (now - DeletableExpiryDateDelta(cc_deletion_delta_)) + .LocalExplode(&expiry_date); + + CreditCard credit_card; + credit_card.SetInfo(CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16("Charlie Deletable"), app_locale_); + credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("378282246310005"), + app_locale_); + credit_card.SetExpirationMonth(expiry_date.month); + credit_card.SetExpirationYear(expiry_date.year); + credit_card.set_use_date(use_date); + return credit_card; +} +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_data_creator.h b/chromium/components/autofill/core/browser/test_data_creator.h new file mode 100644 index 00000000000..5a34c163b56 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_data_creator.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_DATA_CREATOR_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_DATA_CREATOR_H_ + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/credit_card.h" + +namespace autofill { + +class TestDataCreator { + public: + TestDataCreator(base::TimeDelta cc_deletion_delta, std::string app_locale); + + void MaybeAddTestProfiles( + const base::RepeatingCallback<void(const AutofillProfile&)>& + add_profile_callback); + void MaybeAddTestCreditCards( + const base::RepeatingCallback<void(const CreditCard&)>& add_cc_callback); + + private: + std::vector<AutofillProfile> GetTestProfiles(); + std::vector<CreditCard> GetTestCreditCards(); + + AutofillProfile CreateBasicTestAddress(); + AutofillProfile CreateDisusedTestAddress(); + AutofillProfile CreateDisusedDeletableTestAddress(); + + CreditCard CreateBasicTestCreditCard(); + CreditCard CreateDisusedTestCreditCard(); + CreditCard CreateDisusedDeletableTestCreditCard(); + + // Minimum amount of time since last use for a credit card to be considered + // "disused". + base::TimeDelta cc_deletion_delta_; + + std::string app_locale_; + + // True if test data has been created this session. + bool has_created_test_addresses_ = false; + bool has_created_test_credit_cards_ = false; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_DATA_CREATOR_H_
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc b/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc index ef295c9693d..cc72aed5cf6 100644 --- a/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc @@ -62,7 +62,7 @@ void TestLocalCardMigrationManager::OnDidGetUploadDetails( bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) { + std::unique_ptr<base::Value> legal_message) { if (result == AutofillClient::SUCCESS) { local_card_migration_was_triggered_ = true; LocalCardMigrationManager::OnDidGetUploadDetails( diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_manager.h b/chromium/components/autofill/core/browser/test_local_card_migration_manager.h index 7daa8c6b388..97e4518eb15 100644 --- a/chromium/components/autofill/core/browser/test_local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/test_local_card_migration_manager.h @@ -55,7 +55,7 @@ class TestLocalCardMigrationManager : public LocalCardMigrationManager { bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::DictionaryValue> legal_message) override; + std::unique_ptr<base::Value> legal_message) override; bool local_card_migration_was_triggered_ = false; diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_strike_database.cc b/chromium/components/autofill/core/browser/test_local_card_migration_strike_database.cc new file mode 100644 index 00000000000..cc212712538 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_local_card_migration_strike_database.cc @@ -0,0 +1,13 @@ +// Copyright 2019 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 "components/autofill/core/browser/test_local_card_migration_strike_database.h" + +namespace autofill { + +TestLocalCardMigrationStrikeDatabase::TestLocalCardMigrationStrikeDatabase( + StrikeDatabase* strike_database) + : LocalCardMigrationStrikeDatabase(strike_database) {} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_strike_database.h b/chromium/components/autofill/core/browser/test_local_card_migration_strike_database.h new file mode 100644 index 00000000000..c1cac181ceb --- /dev/null +++ b/chromium/components/autofill/core/browser/test_local_card_migration_strike_database.h @@ -0,0 +1,20 @@ +// Copyright 2019 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ + +#include "components/autofill/core/browser/local_card_migration_strike_database.h" + +namespace autofill { + +class TestLocalCardMigrationStrikeDatabase + : public LocalCardMigrationStrikeDatabase { + public: + TestLocalCardMigrationStrikeDatabase(StrikeDatabase* strike_database); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc index 664b6904b4b..9a6e5c35765 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc @@ -14,6 +14,11 @@ TestPersonalDataManager::TestPersonalDataManager() TestPersonalDataManager::~TestPersonalDataManager() {} +void TestPersonalDataManager::OnSyncServiceInitialized( + syncer::SyncService* sync_service) { + sync_service_initialized_ = true; +} + void TestPersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) { CreditCard* credit_card = GetCreditCardWithGUID(data_model.guid().c_str()); if (credit_card) diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h index 86ea84a5c10..ae3a7cdb449 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.h +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h @@ -27,7 +27,7 @@ class TestPersonalDataManager : public PersonalDataManager { // PersonalDataManager overrides. These functions are overridden as needed // for various tests, whether to skip calls to uncreated databases/services, // or to make things easier in general to toggle. - void OnSyncServiceInitialized(syncer::SyncService* sync_service) override {} + void OnSyncServiceInitialized(syncer::SyncService* sync_service) override; void RecordUseOf(const AutofillDataModel& data_model) override; std::string SaveImportedProfile( const AutofillProfile& imported_profile) override; @@ -90,6 +90,8 @@ class TestPersonalDataManager : public PersonalDataManager { return num_times_save_imported_credit_card_called_; } + bool sync_service_initialized() const { return sync_service_initialized_; } + void SetAutofillEnabled(bool autofill_enabled) { autofill_enabled_ = autofill_enabled; } @@ -127,6 +129,7 @@ class TestPersonalDataManager : public PersonalDataManager { base::Optional<bool> autofill_credit_card_enabled_; base::Optional<bool> autofill_wallet_import_enabled_; bool sync_feature_enabled_ = false; + bool sync_service_initialized_ = false; AccountInfo account_info_; DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager); diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc index 69818085c4a..7a3c321db04 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc +++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc @@ -205,7 +205,7 @@ bool CardUnmaskPromptControllerImpl::CanStoreLocally() const { return false; if (card_.record_type() == CreditCard::LOCAL_CARD) return false; - return OfferStoreUnmaskedCards(); + return OfferStoreUnmaskedCards(is_off_the_record_); } bool CardUnmaskPromptControllerImpl::GetStoreLocallyStartState() const { diff --git a/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h index 03e7b7bca96..f2dcc17dd9c 100644 --- a/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h +++ b/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h @@ -29,6 +29,7 @@ class LocalCardMigrationDialogController { virtual const std::vector<MigratableCreditCard>& GetCardList() const = 0; virtual const LegalMessageLines& GetLegalMessageLines() const = 0; virtual const base::string16& GetTipMessage() const = 0; + virtual const std::string& GetUserEmail() const = 0; virtual void OnSaveButtonClicked( const std::vector<std::string>& selected_cards_guids) = 0; virtual void OnCancelButtonClicked() = 0; diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc index 299fe00083c..bce4371b0de 100644 --- a/chromium/components/autofill/core/browser/validation.cc +++ b/chromium/components/autofill/core/browser/validation.cc @@ -43,6 +43,13 @@ bool IsValidCreditCardExpirationDate(int year, return true; } +bool IsValidCreditCardExpirationYear(int year, const base::Time& now) { + base::Time::Exploded now_exploded; + now.LocalExplode(&now_exploded); + + return year >= now_exploded.year; +} + bool IsValidCreditCardNumber(const base::string16& text) { base::string16 number = CreditCard::StripSeparators(text); diff --git a/chromium/components/autofill/core/browser/validation.h b/chromium/components/autofill/core/browser/validation.h index 65873edfb4a..5c7dccf1a65 100644 --- a/chromium/components/autofill/core/browser/validation.h +++ b/chromium/components/autofill/core/browser/validation.h @@ -40,6 +40,10 @@ bool IsValidCreditCardExpirationDate(int year, int month, const base::Time& now); +// Returns true if |year| describes a year later than or equal to |now|'s year. +// |year| must have 4 digits. +bool IsValidCreditCardExpirationYear(int year, const base::Time& now); + // Returns true if |text| looks like a valid credit card number. // Uses the Luhn formula to validate the number. bool IsValidCreditCardNumber(const base::string16& text); diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc index 664b9e74879..1eebf032d16 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc @@ -17,6 +17,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/model_type_change_processor.h" #include "components/sync/model/mutable_data_batch.h" @@ -337,7 +338,14 @@ Optional<syncer::ModelError> AutocompleteSyncBridge::MergeSyncData( RETURN_IF_ERROR(tracker.FlushToLocal(web_data_backend_)); RETURN_IF_ERROR(tracker.FlushToSync(true, std::move(metadata_change_list), change_processor())); - web_data_backend_->RemoveExpiredFormElements(); + + // TODO(crbug.com/920214) Deprecated, clean-up as part of the + // Autocomplete Retention Policy flag cleanup. + if (!base::FeatureList::IsEnabled( + autofill::features::kAutocompleteRetentionPolicyEnabled)) { + web_data_backend_->RemoveExpiredFormElements(); + } + web_data_backend_->NotifyThatSyncHasStarted(syncer::AUTOFILL); return {}; } @@ -361,7 +369,13 @@ Optional<ModelError> AutocompleteSyncBridge::ApplySyncChanges( RETURN_IF_ERROR(tracker.FlushToLocal(web_data_backend_)); RETURN_IF_ERROR(tracker.FlushToSync(false, std::move(metadata_change_list), change_processor())); - web_data_backend_->RemoveExpiredFormElements(); + + // TODO(crbug.com/920214) Deprecated, clean-up as part of the + // Autocomplete Retention Policy flag cleanup. + if (!base::FeatureList::IsEnabled( + autofill::features::kAutocompleteRetentionPolicyEnabled)) { + web_data_backend_->RemoveExpiredFormElements(); + } return {}; } @@ -438,6 +452,21 @@ void AutocompleteSyncBridge::ActOnLocalChanges( change_processor()->Delete(storage_key, metadata_change_list.get()); break; } + case AutofillChange::EXPIRE: { + // For expired entries, unlink and delete the sync metadata. + // That way we are not sending tombstone updates to the sync servers. + bool success = GetAutofillTable()->ClearSyncMetadata(syncer::AUTOFILL, + storage_key); + if (!success) { + change_processor()->ReportError( + {FROM_HERE, + "Failed to clear sync metadata for an expired autofill entry " + "from WebDatabase."}); + return; + } + + change_processor()->UntrackEntityForStorageKey(storage_key); + } } } diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc index d5a0700e746..d7dfa2eff27 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc @@ -17,12 +17,14 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" +#include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/sync/base/hash_util.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/data_type_activation_request.h" @@ -445,6 +447,34 @@ TEST_F(AutocompleteSyncBridgeTest, ApplySyncChangesSimple) { VerifyAllData({specifics2}); } +// Tests that the function RemoveExpiredFormElements is called when the +// Autocomplete Retention Policy feature flag is disabled. +TEST_F(AutocompleteSyncBridgeTest, + ApplySyncChangesSimple_FlagOff_Calls_RemoveExpiredFormElements) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndDisableFeature( + features::kAutocompleteRetentionPolicyEnabled); + + EXPECT_CALL(*backend(), RemoveExpiredFormElements); + + AutofillSpecifics specifics1 = CreateSpecifics(1); + ApplyAdds({specifics1}); +} + +// Tests that the function RemoveExpiredFormElements is not called when the +// Autocomplete Retention Policy feature flag is enabled. +TEST_F(AutocompleteSyncBridgeTest, + ApplySyncChangesSimple_FlagOn_Not_Calls_RemoveExpiredFormElements) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + + EXPECT_CALL(*backend(), RemoveExpiredFormElements).Times(0); + + AutofillSpecifics specifics1 = CreateSpecifics(1); + ApplyAdds({specifics1}); +} + // Should be resilient to deleting and updating non-existent things, and adding // existing ones. TEST_F(AutocompleteSyncBridgeTest, ApplySyncChangesWrongChangeType) { @@ -592,6 +622,33 @@ TEST_F(AutocompleteSyncBridgeTest, LocalEntryDeleted) { {AutofillChange(AutofillChange::REMOVE, deleted_entry.key())}); } +// Tests that AutofillEntry marked with AutofillChange::EXPIRE are unlinked from +// sync, and their sync metadata is deleted in this client. +TEST_F(AutocompleteSyncBridgeTest, LocalEntryExpired) { + StartSyncing(); + const AutofillSpecifics expired_specifics = CreateSpecifics(1, {2, 3}); + const AutofillEntry expired_entry = CreateAutofillEntry(expired_specifics); + const std::string storage_key = GetStorageKey(expired_specifics); + + // Let's add the sync metadata + ASSERT_TRUE(table()->UpdateSyncMetadata(syncer::AUTOFILL, storage_key, + EntityMetadata())); + + // Validate that it was added. + syncer::MetadataBatch batch; + ASSERT_TRUE(table()->GetAllSyncMetadata(syncer::AUTOFILL, &batch)); + ASSERT_EQ(1U, batch.TakeAllMetadata().size()); + + EXPECT_CALL(mock_processor(), UntrackEntityForStorageKey(storage_key)); + + bridge()->AutofillEntriesChanged( + {AutofillChange(AutofillChange::EXPIRE, expired_entry.key())}); + + // Expect metadata to have been cleaned up. + EXPECT_TRUE(table()->GetAllSyncMetadata(syncer::AUTOFILL, &batch)); + EXPECT_EQ(0U, batch.TakeAllMetadata().size()); +} + TEST_F(AutocompleteSyncBridgeTest, LoadMetadataCalled) { ModelTypeState model_type_state; model_type_state.set_initial_sync_done(true); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_change.h b/chromium/components/autofill/core/browser/webdata/autofill_change.h index 6212c6079c5..16c6290fa60 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_change.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_change.h @@ -9,11 +9,11 @@ #include <vector> #include "base/logging.h" +#include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" namespace autofill { -class AutofillProfile; class CreditCard; // For classic Autofill form fields, the KeyType is AutofillKey. @@ -21,11 +21,7 @@ class CreditCard; template <typename KeyType> class GenericAutofillChange { public: - enum Type { - ADD, - UPDATE, - REMOVE - }; + enum Type { ADD, UPDATE, REMOVE, EXPIRE }; virtual ~GenericAutofillChange() {} @@ -56,8 +52,9 @@ typedef std::vector<AutofillChange> AutofillChangeList; template <typename DataType> class AutofillDataModelChange : public GenericAutofillChange<std::string> { public: - // The |type| input specifies the change type. The |key| input is the key, - // which is expected to be the GUID identifying the |data_model|. + // The |type| input specifies the change type. The |key| input is the key + // that identifies the |data_model|; it is the GUID of the entry for local + // data and server_id of the entry for server data from GPay. // When |type| == ADD, |data_model| should be non-NULL. // When |type| == UPDATE, |data_model| should be non-NULL. // When |type| == REMOVE, |data_model| should be NULL. @@ -66,7 +63,8 @@ class AutofillDataModelChange : public GenericAutofillChange<std::string> { const DataType* data_model) : GenericAutofillChange<std::string>(type, key), data_model_(data_model) { DCHECK(type == REMOVE ? !data_model - : data_model && data_model->guid() == key); + : data_model && (data_model->guid() == key || + data_model->server_id() == key)); } ~AutofillDataModelChange() override {} @@ -86,6 +84,25 @@ class AutofillDataModelChange : public GenericAutofillChange<std::string> { typedef AutofillDataModelChange<AutofillProfile> AutofillProfileChange; typedef AutofillDataModelChange<CreditCard> CreditCardChange; +class AutofillProfileDeepChange : public AutofillProfileChange { + public: + AutofillProfileDeepChange(Type type, const AutofillProfile& profile) + : AutofillProfileChange(type, profile.guid(), &profile), + profile_(profile) {} + + AutofillProfileDeepChange(Type type, const std::string& guid) + : AutofillProfileChange(type, guid, nullptr), profile_(guid, "") { + DCHECK(type == GenericAutofillChange::REMOVE); + } + + ~AutofillProfileDeepChange() override {} + + AutofillProfile profile() const { return profile_; } + + private: + AutofillProfile profile_; +}; + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc index 080e6be3b32..f05cd1227fd 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc @@ -25,18 +25,19 @@ namespace browser_sync { AutofillProfileDataTypeController::AutofillProfileDataTypeController( scoped_refptr<base::SingleThreadTaskRunner> db_thread, const base::Closure& dump_stack, + syncer::SyncService* sync_service, syncer::SyncClient* sync_client, const scoped_refptr<autofill::AutofillWebDataService>& web_data_service) : AsyncDirectoryTypeController(syncer::AUTOFILL_PROFILE, dump_stack, + sync_service, sync_client, syncer::GROUP_DB, std::move(db_thread)), - sync_client_(sync_client), web_data_service_(web_data_service), callback_registered_(false), currently_enabled_(IsEnabled()) { - pref_registrar_.Init(sync_client_->GetPrefService()); + pref_registrar_.Init(sync_client->GetPrefService()); pref_registrar_.Add( autofill::prefs::kAutofillProfileEnabled, base::Bind(&AutofillProfileDataTypeController::OnUserPrefChanged, @@ -52,7 +53,7 @@ void AutofillProfileDataTypeController::OnPersonalDataChanged() { DCHECK(CalledOnValidThread()); DCHECK_EQ(state(), MODEL_STARTING); - sync_client_->GetPersonalDataManager()->RemoveObserver(this); + sync_client()->GetPersonalDataManager()->RemoveObserver(this); if (!web_data_service_) return; @@ -78,7 +79,7 @@ bool AutofillProfileDataTypeController::StartModels() { return false; } autofill::PersonalDataManager* personal_data = - sync_client_->GetPersonalDataManager(); + sync_client()->GetPersonalDataManager(); // Make sure PDM has the sync service. This is needed because in the account // wallet data mode, PDM uses the service to determine whether to use the @@ -88,7 +89,7 @@ bool AutofillProfileDataTypeController::StartModels() { // one single call in a more general place. if (base::FeatureList::IsEnabled( autofill::features::kAutofillEnableAccountWalletStorage)) { - personal_data->OnSyncServiceInitialized(sync_client_->GetSyncService()); + personal_data->OnSyncServiceInitialized(sync_service()); } // Waiting for the personal data is subtle: we do this as the PDM resets @@ -117,7 +118,7 @@ bool AutofillProfileDataTypeController::StartModels() { void AutofillProfileDataTypeController::StopModels() { DCHECK(CalledOnValidThread()); - sync_client_->GetPersonalDataManager()->RemoveObserver(this); + sync_client()->GetPersonalDataManager()->RemoveObserver(this); } bool AutofillProfileDataTypeController::ReadyForStart() const { @@ -136,8 +137,7 @@ void AutofillProfileDataTypeController::OnUserPrefChanged() { if (currently_enabled_) { // The preference was just enabled. Trigger a reconfiguration. This will do // nothing if the type isn't preferred. - syncer::SyncService* sync_service = sync_client_->GetSyncService(); - sync_service->ReenableDatatype(type()); + sync_service()->ReenableDatatype(type()); } else { DisableForPolicy(); } @@ -148,7 +148,7 @@ bool AutofillProfileDataTypeController::IsEnabled() { // Require the user-visible pref to be enabled to sync Autofill Profile data. return autofill::prefs::IsProfileAutofillEnabled( - sync_client_->GetPrefService()); + sync_client()->GetPrefService()); } void AutofillProfileDataTypeController::DisableForPolicy() { diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h index d981239acbd..b2886eea632 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h @@ -18,6 +18,11 @@ namespace autofill { class AutofillWebDataService; } // namespace autofill +namespace syncer { +class SyncClient; +class SyncService; +} // namespace syncer + namespace browser_sync { // Controls syncing of the AUTOFILL_PROFILE data type. @@ -29,6 +34,7 @@ class AutofillProfileDataTypeController AutofillProfileDataTypeController( scoped_refptr<base::SingleThreadTaskRunner> db_thread, const base::Closure& dump_stack, + syncer::SyncService* sync_service, syncer::SyncClient* sync_client, const scoped_refptr<autofill::AutofillWebDataService>& web_data_service); ~AutofillProfileDataTypeController() override; @@ -55,9 +61,6 @@ class AutofillProfileDataTypeController // Report an error (which will stop the datatype asynchronously). void DisableForPolicy(); - // A pointer to the sync client. - syncer::SyncClient* const sync_client_; - // A reference to the AutofillWebDataService for this controller. scoped_refptr<autofill::AutofillWebDataService> web_data_service_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc index db2726ee0bf..8385d72a5fb 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc @@ -9,19 +9,20 @@ #include "base/bind.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" -#include "components/sync/driver/sync_client.h" #include "components/sync/driver/sync_service.h" namespace browser_sync { AutofillProfileModelTypeController::AutofillProfileModelTypeController( std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, - syncer::SyncClient* sync_client) + PrefService* pref_service, + syncer::SyncService* sync_service) : ModelTypeController(syncer::AUTOFILL_PROFILE, std::move(delegate_on_disk)), - sync_client_(sync_client), + pref_service_(pref_service), + sync_service_(sync_service), currently_enabled_(IsEnabled()) { - pref_registrar_.Init(sync_client_->GetPrefService()); + pref_registrar_.Init(pref_service_); pref_registrar_.Add( autofill::prefs::kAutofillProfileEnabled, base::BindRepeating( @@ -45,15 +46,14 @@ void AutofillProfileModelTypeController::OnUserPrefChanged() { return; currently_enabled_ = new_enabled; - sync_client_->GetSyncService()->ReadyForStartChanged(type()); + sync_service_->ReadyForStartChanged(type()); } bool AutofillProfileModelTypeController::IsEnabled() { DCHECK(CalledOnValidThread()); // Require the user-visible pref to be enabled to sync Autofill Profile data. - return autofill::prefs::IsProfileAutofillEnabled( - sync_client_->GetPrefService()); + return autofill::prefs::IsProfileAutofillEnabled(pref_service_); } } // namespace browser_sync diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h index 2a6a4095acd..38aafd7d8d2 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h @@ -11,9 +11,11 @@ #include "components/prefs/pref_change_registrar.h" #include "components/sync/driver/model_type_controller.h" +class PrefService; + namespace syncer { class ModelTypeControllerDelegate; -class SyncClient; +class SyncService; } // namespace syncer namespace browser_sync { @@ -23,7 +25,8 @@ class AutofillProfileModelTypeController : public syncer::ModelTypeController { public: AutofillProfileModelTypeController( std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, - syncer::SyncClient* sync_client); + PrefService* pref_service, + syncer::SyncService* sync_service); ~AutofillProfileModelTypeController() override; // DataTypeController overrides. @@ -36,7 +39,8 @@ class AutofillProfileModelTypeController : public syncer::ModelTypeController { // Returns true if the pref is set such that autofill sync should be enabled. bool IsEnabled(); - syncer::SyncClient* const sync_client_; + PrefService* const pref_service_; + syncer::SyncService* const sync_service_; // Registrar for listening to prefs::kAutofillProfileEnabled. PrefChangeRegistrar pref_registrar_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc index d5bc7624172..4ee20ea6814 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc @@ -232,6 +232,10 @@ void AutofillProfileSyncBridge::ActOnLocalChange( // here. change_processor()->Delete(change.key(), metadata_change_list.get()); break; + case AutofillProfileChange::EXPIRE: + // EXPIRE changes are not being issued for profiles. + NOTREACHED(); + break; } if (Optional<ModelError> error = metadata_change_list->TakeError()) { diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc index ca84bff0f37..552c2dabef6 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc @@ -15,7 +15,7 @@ #include "base/guid.h" #include "base/location.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc index cd6d49216a8..51d3cb7ee83 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc @@ -76,8 +76,8 @@ void AutofillProfileSyncableService::CreateForWebDataServiceAndBackend( const std::string& app_locale) { web_data_service->GetDBUserData()->SetUserData( AutofillProfileSyncableServiceUserDataKey(), - base::WrapUnique( - new AutofillProfileSyncableService(webdata_backend, app_locale))); + std::make_unique<AutofillProfileSyncableService>(webdata_backend, + app_locale)); } // static diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h index ce6efa43404..079ff91ee41 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h @@ -50,6 +50,9 @@ class AutofillProfileSyncableService public syncer::SyncableService, public AutofillWebDataServiceObserverOnDBSequence { public: + AutofillProfileSyncableService(AutofillWebDataBackend* webdata_backend, + const std::string& app_locale); + ~AutofillProfileSyncableService() override; // Creates a new AutofillProfileSyncableService and hangs it off of @@ -87,9 +90,6 @@ class AutofillProfileSyncableService const syncer::SyncableService::StartSyncFlare& flare); protected: - AutofillProfileSyncableService(AutofillWebDataBackend* webdata_backend, - const std::string& app_locale); - // A convenience wrapper of a bunch of state we pass around while // associating models, and send to the WebDatabase for persistence. // We do this so we hold the write lock for only a small period. diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc index 199e53f7c24..b4dc3f5db51 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc @@ -11,8 +11,8 @@ #include "base/location.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/webdata/autofill_change.h" @@ -262,7 +262,7 @@ class AutofillProfileSyncableServiceTest : public testing::Test { } protected: - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; MockAutofillProfileSyncableService autofill_syncable_service_; std::unique_ptr<MockSyncChangeProcessor> sync_processor_; }; @@ -1502,7 +1502,7 @@ class SyncUpdatesUsageStatsTest } protected: - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; MockAutofillProfileSyncableService autofill_syncable_service_; std::unique_ptr<MockSyncChangeProcessor> sync_processor_; }; @@ -1604,7 +1604,7 @@ TEST_F(AutofillProfileSyncableServiceTest, ClientOverwritesUsageStats) { .WillOnce(Return(true)); autofill_syncable_service_.MergeDataAndStartSyncing( syncer::AUTOFILL_PROFILE, data_list, - base::WrapUnique(sync_change_processor), + std::unique_ptr<TestSyncChangeProcessor>(sync_change_processor), std::unique_ptr<syncer::SyncErrorFactory>( new syncer::SyncErrorFactoryMock())); @@ -1640,7 +1640,7 @@ TEST_F(AutofillProfileSyncableServiceTest, IgnoreServerProfileUpdate) { .WillOnce(Return(true)); autofill_syncable_service_.MergeDataAndStartSyncing( syncer::AUTOFILL_PROFILE, syncer::SyncDataList(), - base::WrapUnique(new TestSyncChangeProcessor), + std::make_unique<TestSyncChangeProcessor>(), std::unique_ptr<syncer::SyncErrorFactory>( new syncer::SyncErrorFactoryMock())); AutofillProfile server_profile(AutofillProfile::SERVER_PROFILE, "server-id"); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc index dfbede05b0c..d0647c4bf0e 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc @@ -5,6 +5,7 @@ #include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" #include "base/base64.h" +#include "base/pickle.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_data_util.h" @@ -113,67 +114,107 @@ CreditCard::CardType CardTypeFromWalletCardClass( } } -} // namespace +// Creates an AutofillProfile from the specified |address| specifics. +AutofillProfile ProfileFromSpecifics( + const sync_pb::WalletPostalAddress& address) { + AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); -std::string GetBase64EncodedServerId(const std::string& server_id) { - std::string encoded_id; - base::Base64Encode(server_id, &encoded_id); - return encoded_id; -} + // AutofillProfile stores multi-line addresses with newline separators. + std::vector<base::StringPiece> street_address( + address.street_address().begin(), address.street_address().end()); + profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, + base::UTF8ToUTF16(base::JoinString(street_address, "\n"))); + + profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name())); + profile.SetRawInfo(ADDRESS_HOME_STATE, + base::UTF8ToUTF16(address.address_1())); + profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2())); + profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + base::UTF8ToUTF16(address.address_3())); + // AutofillProfile doesn't support address_4 ("sub dependent locality"). + profile.SetRawInfo(ADDRESS_HOME_ZIP, + base::UTF8ToUTF16(address.postal_code())); + profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, + base::UTF8ToUTF16(address.sorting_code())); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, + base::UTF8ToUTF16(address.country_code())); + profile.set_language_code(address.language_code()); + + // SetInfo instead of SetRawInfo so the constituent pieces will be parsed + // for these data types. + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()), + profile.language_code()); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16(address.phone_number()), + profile.language_code()); + + profile.GenerateServerProfileIdentifier(); -std::string GetSpecificsIdForEntryServerId(const std::string& server_id) { - // TODO(jkrcal): This specifics id for wallet_data probably should not be - // base64 encoded - this function is only used in printing debug data; should - // the storage key for wallet_data below be encoded? (probably yes, as this is - // already launched). - return GetBase64EncodedServerId(server_id); + return profile; } -std::string GetSpecificsIdForMetadataId(const std::string& metadata_id) { - return GetBase64EncodedServerId(metadata_id); +// Creates an AutofillProfile from the specified |card| specifics. +CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { + CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id()); + result.SetNumber(base::UTF8ToUTF16(card.last_four())); + result.SetServerStatus(ServerToLocalStatus(card.status())); + result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type())); + result.set_card_type(CardTypeFromWalletCardClass(card.card_class())); + result.SetRawInfo(CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16(card.name_on_card())); + result.SetExpirationMonth(card.exp_month()); + result.SetExpirationYear(card.exp_year()); + result.set_billing_address_id(card.billing_address_id()); + result.set_bank_name(card.bank_name()); + return result; } -std::string GetStorageKeyForSpecificsId(const std::string& specifics_id) { - // We use the base64 encoded |specifics_id| directly as the storage key, this - // function only hides this definition from all its call sites. - return specifics_id; +// Creates a PaymentCustomerData object corresponding to the sync datatype +// |customer_data|. +PaymentsCustomerData CustomerDataFromSpecifics( + const sync_pb::PaymentsCustomerData& customer_data) { + return PaymentsCustomerData{/*customer_id=*/customer_data.id()}; } -std::string GetStorageKeyForEntryServerId(const std::string& server_id) { - // TODO(jkrcal): This probably needs to stay base64 encoded while specifics id - // should not. Fix. - return GetStorageKeyForSpecificsId(GetSpecificsIdForEntryServerId(server_id)); +} // namespace + +std::string GetBase64EncodedId(const std::string& id) { + std::string encoded_id; + base::Base64Encode(id, &encoded_id); + return encoded_id; } -std::string GetStorageKeyForMetadataId(const std::string& metadata_id) { - return GetStorageKeyForSpecificsId(GetSpecificsIdForMetadataId(metadata_id)); +std::string GetBase64DecodedId(const std::string& id) { + std::string decoded_id; + base::Base64Decode(id, &decoded_id); + return decoded_id; } -std::string GetClientTagForSpecificsId( - AutofillWalletSpecifics::WalletInfoType type, - const std::string& wallet_data_specifics_id) { - switch (type) { - case AutofillWalletSpecifics::POSTAL_ADDRESS: - return "address-" + wallet_data_specifics_id; - case AutofillWalletSpecifics::MASKED_CREDIT_CARD: - return "card-" + wallet_data_specifics_id; - case sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA: - return "customer-" + wallet_data_specifics_id; - case AutofillWalletSpecifics::UNKNOWN: - NOTREACHED(); - return ""; - } +std::string GetStorageKeyForWalletMetadataTypeAndSpecificsId( + sync_pb::WalletMetadataSpecifics::Type type, + const std::string& specifics_id) { + base::Pickle pickle; + pickle.WriteInt(static_cast<int>(type)); + // We use the (base64-encoded) |specifics_id| here. + pickle.WriteString(specifics_id); + return std::string(static_cast<const char*>(pickle.data()), pickle.size()); } void SetAutofillWalletSpecificsFromServerProfile( const AutofillProfile& address, - AutofillWalletSpecifics* wallet_specifics) { + AutofillWalletSpecifics* wallet_specifics, + bool enforce_utf8) { wallet_specifics->set_type(AutofillWalletSpecifics::POSTAL_ADDRESS); sync_pb::WalletPostalAddress* wallet_address = wallet_specifics->mutable_address(); - wallet_address->set_id(address.server_id()); + if (enforce_utf8) { + wallet_address->set_id(GetBase64EncodedId(address.server_id())); + } else { + wallet_address->set_id(address.server_id()); + } + wallet_address->set_language_code(TruncateUTF8(address.language_code())); if (address.HasRawInfo(NAME_FULL)) { @@ -218,69 +259,30 @@ void SetAutofillWalletSpecificsFromServerProfile( } } -std::unique_ptr<EntityData> CreateEntityDataFromAutofillServerProfile( - const AutofillProfile& address) { - auto entity_data = std::make_unique<EntityData>(); - - std::string specifics_id = - GetSpecificsIdForEntryServerId(address.server_id()); - entity_data->non_unique_name = GetClientTagForSpecificsId( - AutofillWalletSpecifics::POSTAL_ADDRESS, specifics_id); - - AutofillWalletSpecifics* wallet_specifics = - entity_data->specifics.mutable_autofill_wallet(); - - SetAutofillWalletSpecificsFromServerProfile(address, wallet_specifics); - - return entity_data; -} - -AutofillProfile ProfileFromSpecifics( - const sync_pb::WalletPostalAddress& address) { - AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); - - // AutofillProfile stores multi-line addresses with newline separators. - std::vector<base::StringPiece> street_address( - address.street_address().begin(), address.street_address().end()); - profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, - base::UTF8ToUTF16(base::JoinString(street_address, "\n"))); - - profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name())); - profile.SetRawInfo(ADDRESS_HOME_STATE, - base::UTF8ToUTF16(address.address_1())); - profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2())); - profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, - base::UTF8ToUTF16(address.address_3())); - // AutofillProfile doesn't support address_4 ("sub dependent locality"). - profile.SetRawInfo(ADDRESS_HOME_ZIP, - base::UTF8ToUTF16(address.postal_code())); - profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, - base::UTF8ToUTF16(address.sorting_code())); - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, - base::UTF8ToUTF16(address.country_code())); - profile.set_language_code(address.language_code()); - - // SetInfo instead of SetRawInfo so the constituent pieces will be parsed - // for these data types. - profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()), - profile.language_code()); - profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, - base::UTF8ToUTF16(address.phone_number()), - profile.language_code()); - - profile.GenerateServerProfileIdentifier(); - - return profile; -} - void SetAutofillWalletSpecificsFromServerCard( const CreditCard& card, - AutofillWalletSpecifics* wallet_specifics) { + AutofillWalletSpecifics* wallet_specifics, + bool enforce_utf8) { wallet_specifics->set_type(AutofillWalletSpecifics::MASKED_CREDIT_CARD); sync_pb::WalletMaskedCreditCard* wallet_card = wallet_specifics->mutable_masked_card(); - wallet_card->set_id(card.server_id()); + + if (enforce_utf8) { + wallet_card->set_id(GetBase64EncodedId(card.server_id())); + // The billing address id might refer to a local profile guid which doesn't + // need to be encoded. + if (base::IsStringUTF8(card.billing_address_id())) { + wallet_card->set_billing_address_id(card.billing_address_id()); + } else { + wallet_card->set_billing_address_id( + GetBase64EncodedId(card.billing_address_id())); + } + } else { + wallet_card->set_id(card.server_id()); + wallet_card->set_billing_address_id(card.billing_address_id()); + } + wallet_card->set_status(LocalToServerStatus(card)); if (card.HasRawInfo(CREDIT_CARD_NAME_FULL)) { wallet_card->set_name_on_card(TruncateUTF8( @@ -290,57 +292,10 @@ void SetAutofillWalletSpecificsFromServerCard( wallet_card->set_last_four(base::UTF16ToUTF8(card.LastFourDigits())); wallet_card->set_exp_month(card.expiration_month()); wallet_card->set_exp_year(card.expiration_year()); - wallet_card->set_billing_address_id(card.billing_address_id()); wallet_card->set_card_class(WalletCardClassFromCardType(card.card_type())); wallet_card->set_bank_name(card.bank_name()); } -std::unique_ptr<EntityData> CreateEntityDataFromCard(const CreditCard& card) { - std::string specifics_id = GetSpecificsIdForEntryServerId(card.server_id()); - - auto entity_data = std::make_unique<EntityData>(); - entity_data->non_unique_name = GetClientTagForSpecificsId( - AutofillWalletSpecifics::MASKED_CREDIT_CARD, specifics_id); - - AutofillWalletSpecifics* wallet_specifics = - entity_data->specifics.mutable_autofill_wallet(); - - SetAutofillWalletSpecificsFromServerCard(card, wallet_specifics); - - return entity_data; -} - -CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { - CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id()); - result.SetNumber(base::UTF8ToUTF16(card.last_four())); - result.SetServerStatus(ServerToLocalStatus(card.status())); - result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type())); - result.set_card_type(CardTypeFromWalletCardClass(card.card_class())); - result.SetRawInfo(CREDIT_CARD_NAME_FULL, - base::UTF8ToUTF16(card.name_on_card())); - result.SetExpirationMonth(card.exp_month()); - result.SetExpirationYear(card.exp_year()); - result.set_billing_address_id(card.billing_address_id()); - result.set_bank_name(card.bank_name()); - return result; -} - -std::unique_ptr<EntityData> CreateEntityDataFromPaymentsCustomerData( - const PaymentsCustomerData& customer_data) { - // We use customer_id as a storage key here. - auto entity_data = std::make_unique<EntityData>(); - entity_data->non_unique_name = GetClientTagForSpecificsId( - AutofillWalletSpecifics::CUSTOMER_DATA, customer_data.customer_id); - - AutofillWalletSpecifics* wallet_specifics = - entity_data->specifics.mutable_autofill_wallet(); - - SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, - wallet_specifics); - - return entity_data; -} - void SetAutofillWalletSpecificsFromPaymentsCustomerData( const PaymentsCustomerData& customer_data, AutofillWalletSpecifics* wallet_specifics) { @@ -351,11 +306,6 @@ void SetAutofillWalletSpecificsFromPaymentsCustomerData( mutable_customer_data->set_id(customer_data.customer_id); } -PaymentsCustomerData CustomerDataFromSpecifics( - const sync_pb::PaymentsCustomerData& customer_data) { - return PaymentsCustomerData{/*customer_id=*/customer_data.id()}; -} - void CopyRelevantWalletMetadataFromDisk( const AutofillTable& table, std::vector<CreditCard>* cards_from_server) { diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h index 07861d45969..fc6812fc600 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h @@ -18,61 +18,29 @@ class AutofillTable; class CreditCard; struct PaymentsCustomerData; -// Returns the specified |server_id| encoded in base 64. -std::string GetBase64EncodedServerId(const std::string& server_id); +// Returns the specified |id| encoded in / decoded from base 64. +std::string GetBase64EncodedId(const std::string& id); +std::string GetBase64DecodedId(const std::string& id); -// Returns the wallet data specifics id for the specified |server_id|. -std::string GetSpecificsIdForEntryServerId(const std::string& server_id); - -// Returns the wallet metadata specifics id for the specified |metadata_id|. -std::string GetSpecificsIdForMetadataId(const std::string& metadata_id); - -// Returns the storage key for the specified |specifics_id|. -std::string GetStorageKeyForSpecificsId(const std::string& specifics_id); - -// Returns the wallet data specifics storage key for the specified -// |server_id|. -std::string GetStorageKeyForEntryServerId(const std::string& server_id); - -// Returns the wallet metadata specifics storage key for the specified -// |metadata_id|. -std::string GetStorageKeyForMetadataId(const std::string& metadata_id); - -// Returns the client tag for the specified wallet |type| and -// |wallet_data_specifics_id|. -std::string GetClientTagForSpecificsId( - sync_pb::AutofillWalletSpecifics::WalletInfoType type, - const std::string& wallet_data_specifics_id); +// Returns the storage key to be used for wallet metadata for the specified +// wallet metadata |type| and |specifics_id|. +std::string GetStorageKeyForWalletMetadataTypeAndSpecificsId( + sync_pb::WalletMetadataSpecifics::Type type, + const std::string& specifics_id); // Sets the fields of the |wallet_specifics| based on the the specified -// |address|. +// |address|. If |enforce_utf8|, ids are encoded into UTF-8. void SetAutofillWalletSpecificsFromServerProfile( const AutofillProfile& address, - sync_pb::AutofillWalletSpecifics* wallet_specifics); - -// Creates a EntityData object corresponding to the specified |address|. -std::unique_ptr<syncer::EntityData> CreateEntityDataFromAutofillServerProfile( - const AutofillProfile& address); - -// Creates an AutofillProfile from the specified |address| specifics. -AutofillProfile ProfileFromSpecifics( - const sync_pb::WalletPostalAddress& address); + sync_pb::AutofillWalletSpecifics* wallet_specifics, + bool enforce_utf8 = false); // Sets the fields of the |wallet_specifics| based on the the specified |card|. +// If |enforce_utf8|, ids are encoded into UTF-8. void SetAutofillWalletSpecificsFromServerCard( const CreditCard& card, - sync_pb::AutofillWalletSpecifics* wallet_specifics); - -// Creates a EntityData object corresponding to the specified |card|. -std::unique_ptr<syncer::EntityData> CreateEntityDataFromCard( - const CreditCard& card); - -// Creates an AutofillProfile from the specified |card| specifics. -CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card); - -// Creates a EntityData object corresponding to the specified |customer_data|. -std::unique_ptr<syncer::EntityData> CreateEntityDataFromPaymentsCustomerData( - const PaymentsCustomerData& customer_data); + sync_pb::AutofillWalletSpecifics* wallet_specifics, + bool enforce_utf8 = false); // Sets the fields of the |wallet_specifics| based on the specified // |customer_data|. @@ -80,11 +48,6 @@ void SetAutofillWalletSpecificsFromPaymentsCustomerData( const PaymentsCustomerData& customer_data, sync_pb::AutofillWalletSpecifics* wallet_specifics); -// Creates a PaymentCustomerData object corresponding to the sync datatype -// |customer_data|. -PaymentsCustomerData CustomerDataFromSpecifics( - const sync_pb::PaymentsCustomerData& customer_data); - // TODO(sebsg): This should probably copy the converted state for the address // too. // Copies the metadata from the local cards (if present) to the corresponding diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc index a13ca78d12f..44741c86d84 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc @@ -34,6 +34,8 @@ #include "components/autofill/core/browser/webdata/autofill_table_encryptor.h" #include "components/autofill/core/browser/webdata/autofill_table_encryptor_factory.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_field_data.h" @@ -503,22 +505,28 @@ bool AutofillTable::AddFormFieldValue(const FormFieldData& element, bool AutofillTable::GetFormValuesForElementName( const base::string16& name, const base::string16& prefix, - std::vector<base::string16>* values, + std::vector<AutofillEntry>* entries, int limit) { - DCHECK(values); + DCHECK(entries); bool succeeded = false; if (prefix.empty()) { sql::Statement s; - s.Assign( - db_->GetUniqueStatement("SELECT value FROM autofill WHERE name = ? " - "ORDER BY count DESC LIMIT ?")); + s.Assign(db_->GetUniqueStatement( + "SELECT name, value, date_created, date_last_used FROM autofill " + "WHERE name = ? " + "ORDER BY count DESC LIMIT ?")); s.BindString16(0, name); s.BindInt(1, limit); - values->clear(); - while (s.Step()) - values->push_back(s.ColumnString16(0)); + entries->clear(); + while (s.Step()) { + entries->push_back(AutofillEntry( + AutofillKey(/*name=*/s.ColumnString16(0), + /*value=*/s.ColumnString16(1)), + /*date_created=*/base::Time::FromTimeT(s.ColumnInt64(2)), + /*date_last_used=*/base::Time::FromTimeT(s.ColumnInt64(3)))); + } succeeded = s.Succeeded(); } else { @@ -527,28 +535,33 @@ bool AutofillTable::GetFormValuesForElementName( next_prefix.back()++; sql::Statement s1; - s1.Assign( - db_->GetUniqueStatement("SELECT value FROM autofill " - "WHERE name = ? AND " - "value_lower >= ? AND " - "value_lower < ? " - "ORDER BY count DESC " - "LIMIT ?")); + s1.Assign(db_->GetUniqueStatement( + "SELECT name, value, date_created, date_last_used FROM autofill " + "WHERE name = ? AND " + "value_lower >= ? AND " + "value_lower < ? " + "ORDER BY count DESC " + "LIMIT ?")); s1.BindString16(0, name); s1.BindString16(1, prefix_lower); s1.BindString16(2, next_prefix); s1.BindInt(3, limit); - values->clear(); - while (s1.Step()) - values->push_back(s1.ColumnString16(0)); + entries->clear(); + while (s1.Step()) { + entries->push_back(AutofillEntry( + AutofillKey(/*name=*/s1.ColumnString16(0), + /*value=*/s1.ColumnString16(1)), + /*date_created=*/base::Time::FromTimeT(s1.ColumnInt64(2)), + /*date_last_used=*/base::Time::FromTimeT(s1.ColumnInt64(3)))); + } succeeded = s1.Succeeded(); if (IsFeatureSubstringMatchEnabled()) { sql::Statement s2; s2.Assign(db_->GetUniqueStatement( - "SELECT value FROM autofill " + "SELECT name, value, date_created, date_last_used FROM autofill " "WHERE name = ? AND (" " value LIKE '% ' || :prefix || '%' ESCAPE '!' OR " " value LIKE '%.' || :prefix || '%' ESCAPE '!' OR " @@ -564,8 +577,13 @@ bool AutofillTable::GetFormValuesForElementName( s2.BindString16(1, Substitute(prefix_lower, base::ASCIIToUTF16("_%"), 0x21)); s2.BindInt(2, limit); - while (s2.Step()) - values->push_back(s2.ColumnString16(0)); + while (s2.Step()) { + entries->push_back(AutofillEntry( + AutofillKey(/*name=*/s2.ColumnString16(0), + /*value=*/s2.ColumnString16(1)), + /*date_created=*/base::Time::FromTimeT(s2.ColumnInt64(2)), + /*date_last_used=*/base::Time::FromTimeT(s2.ColumnInt64(3)))); + } succeeded &= s2.Succeeded(); } @@ -681,8 +699,17 @@ bool AutofillTable::RemoveFormElementsAddedBetween( bool AutofillTable::RemoveExpiredFormElements( std::vector<AutofillChange>* changes) { + int64_t period = kExpirationPeriodInDays; + auto change_type = AutofillChange::REMOVE; + + if (base::FeatureList::IsEnabled( + autofill::features::kAutocompleteRetentionPolicyEnabled)) { + period = kAutocompleteRetentionPolicyPeriodInDays; + change_type = AutofillChange::EXPIRE; + } + base::Time expiration_time = - AutofillClock::Now() - base::TimeDelta::FromDays(kExpirationPeriodInDays); + AutofillClock::Now() - base::TimeDelta::FromDays(period); // Query for the name and value of all form elements that were last used // before the |expiration_time|. @@ -694,7 +721,7 @@ bool AutofillTable::RemoveExpiredFormElements( base::string16 name = select_for_delete.ColumnString16(0); base::string16 value = select_for_delete.ColumnString16(1); tentative_changes.push_back( - AutofillChange(AutofillChange::REMOVE, AutofillKey(name, value))); + AutofillChange(change_type, AutofillKey(name, value))); } if (!select_for_delete.Succeeded()) @@ -1342,6 +1369,24 @@ bool AutofillTable::UpdateServerCardMetadata(const CreditCard& credit_card) { return db_->GetLastChangeCount() > 0; } +bool AutofillTable::UpdateServerCardMetadata( + const AutofillMetadata& card_metadata) { + // Do not check if there was a record that got deleted. Inserting a new one is + // also fine. + RemoveServerCardMetadata(card_metadata.id); + sql::Statement s( + db_->GetUniqueStatement("INSERT INTO server_card_metadata(use_count, " + "use_date, billing_address_id, id)" + "VALUES (?,?,?,?)")); + s.BindInt64(0, card_metadata.use_count); + s.BindInt64(1, card_metadata.use_date.ToInternalValue()); + s.BindString(2, card_metadata.billing_address_id); + s.BindString(3, card_metadata.id); + s.Run(); + + return db_->GetLastChangeCount() > 0; +} + bool AutofillTable::RemoveServerCardMetadata(const std::string& id) { sql::Statement remove( db_->GetUniqueStatement("DELETE FROM server_card_metadata WHERE id = ?")); @@ -1418,6 +1463,24 @@ bool AutofillTable::UpdateServerAddressMetadata( return db_->GetLastChangeCount() > 0; } +bool AutofillTable::UpdateServerAddressMetadata( + const AutofillMetadata& address_metadata) { + // Do not check if there was a record that got deleted. Inserting a new one is + // also fine. + RemoveServerAddressMetadata(address_metadata.id); + sql::Statement s( + db_->GetUniqueStatement("INSERT INTO server_address_metadata(use_count, " + "use_date, has_converted, id)" + "VALUES (?,?,?,?)")); + s.BindInt64(0, address_metadata.use_count); + s.BindInt64(1, address_metadata.use_date.ToInternalValue()); + s.BindBool(2, address_metadata.has_converted); + s.BindString(3, address_metadata.id); + s.Run(); + + return db_->GetLastChangeCount() > 0; +} + bool AutofillTable::RemoveServerAddressMetadata(const std::string& id) { sql::Statement remove(db_->GetUniqueStatement( "DELETE FROM server_address_metadata WHERE id = ?")); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h index 4c47232d7c5..ae7114f18b4 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h @@ -306,7 +306,7 @@ class AutofillTable : public WebDatabaseTable, // |prefix|. The comparison of the prefix is case insensitive. bool GetFormValuesForElementName(const base::string16& name, const base::string16& prefix, - std::vector<base::string16>* values, + std::vector<AutofillEntry>* entries, int limit); // Removes rows from the autofill table if they were created on or after @@ -409,11 +409,13 @@ class AutofillTable : public WebDatabaseTable, // addresses. bool AddServerCardMetadata(const AutofillMetadata& card_metadata); bool UpdateServerCardMetadata(const CreditCard& credit_card); + bool UpdateServerCardMetadata(const AutofillMetadata& card_metadata); bool RemoveServerCardMetadata(const std::string& id); bool GetServerCardsMetadata( std::map<std::string, AutofillMetadata>* cards_metadata) const; bool AddServerAddressMetadata(const AutofillMetadata& address_metadata); bool UpdateServerAddressMetadata(const AutofillProfile& profile); + bool UpdateServerAddressMetadata(const AutofillMetadata& address_metadata); bool RemoveServerAddressMetadata(const std::string& id); bool GetServerAddressesMetadata( std::map<std::string, AutofillMetadata>* addresses_metadata) const; @@ -558,6 +560,12 @@ class AutofillTable : public WebDatabaseTable, FRIEND_TEST_ALL_PREFIXES( AutofillTableTest, Autofill_RemoveFormElementsAddedBetween_OlderThan30Days); + FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, + RemoveExpiredFormElements_FlagOff_Removes); + FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, + RemoveExpiredFormElements_FlagOn_Expires); + FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, + RemoveExpiredFormElements_FlagOn_NotOldEnough); FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_AddFormFieldValues); FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfile); FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateAutofillProfile); @@ -573,6 +581,7 @@ class AutofillTable : public WebDatabaseTable, Autofill_GetAllAutofillEntries_TwoDistinct); FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame); + FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_GetEntry_Populated); // Methods for adding autofill entries at a specified time. For // testing only. diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc index 6b20deb05ee..14d9f4ec53d 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc @@ -13,11 +13,11 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/guid.h" -#include "base/macros.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_metadata.h" @@ -28,7 +28,9 @@ #include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_field_data.h" @@ -37,6 +39,7 @@ #include "components/sync/protocol/model_type_state.pb.h" #include "components/webdata/common/web_database.h" #include "sql/statement.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using base::ASCIIToUTF16; @@ -46,6 +49,7 @@ using sync_pb::EntityMetadata; using sync_pb::ModelTypeState; using syncer::EntityMetadataMap; using syncer::MetadataBatch; +using testing::ElementsAre; namespace autofill { @@ -70,6 +74,10 @@ std::ostream& operator<<(std::ostream& os, const AutofillChange& change) { os << "REMOVE"; break; } + case AutofillChange::EXPIRE: { + os << "EXPIRED"; + break; + } } return os << " " << change.key(); } @@ -145,6 +153,7 @@ class AutofillTableTest : public testing::Test { base::ScopedTempDir temp_dir_; std::unique_ptr<AutofillTable> table_; std::unique_ptr<WebDatabase> db_; + base::test::ScopedFeatureList scoped_feature_list_; private: DISALLOW_COPY_AND_ASSIGN(AutofillTableTest); @@ -162,7 +171,7 @@ TEST_F(AutofillTableTest, Autofill) { base::Time now = base::Time::Now(); base::TimeDelta two_seconds = base::TimeDelta::FromSeconds(2); EXPECT_TRUE(table_->AddFormFieldValue(field, &changes)); - std::vector<base::string16> v; + std::vector<AutofillEntry> v; for (int i = 0; i < 5; ++i) { field.value = ASCIIToUTF16("Clark Kent"); EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, @@ -200,9 +209,9 @@ TEST_F(AutofillTableTest, Autofill) { ASCIIToUTF16("Name"), base::string16(), &v, 6)); EXPECT_EQ(3U, v.size()); if (v.size() == 3) { - EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]); - EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]); - EXPECT_EQ(ASCIIToUTF16("Superman"), v[2]); + EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0].key().value()); + EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1].key().value()); + EXPECT_EQ(ASCIIToUTF16("Superman"), v[2].key().value()); } // If we query again limiting the list size to 1, we should only get the most @@ -211,7 +220,7 @@ TEST_F(AutofillTableTest, Autofill) { ASCIIToUTF16("Name"), base::string16(), &v, 1)); EXPECT_EQ(1U, v.size()); if (v.size() == 1) { - EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]); + EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0].key().value()); } // Querying for suggestions given a prefix is case-insensitive, so the prefix @@ -220,8 +229,8 @@ TEST_F(AutofillTableTest, Autofill) { ASCIIToUTF16("Name"), ASCIIToUTF16("cLa"), &v, 6)); EXPECT_EQ(2U, v.size()); if (v.size() == 2) { - EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]); - EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]); + EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0].key().value()); + EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1].key().value()); } // Removing all elements since the beginning of this function should remove @@ -243,8 +252,8 @@ TEST_F(AutofillTableTest, Autofill) { AutofillKey(ASCIIToUTF16("Favorite Color"), ASCIIToUTF16("Green"))), }; - EXPECT_EQ(arraysize(kExpectedChanges), changes.size()); - for (size_t i = 0; i < arraysize(kExpectedChanges); ++i) { + EXPECT_EQ(base::size(kExpectedChanges), changes.size()); + for (size_t i = 0; i < base::size(kExpectedChanges); ++i) { EXPECT_EQ(kExpectedChanges[i], changes[i]); } @@ -278,6 +287,43 @@ TEST_F(AutofillTableTest, Autofill) { EXPECT_EQ(4U, v.size()); } +TEST_F(AutofillTableTest, Autofill_GetEntry_Populated) { + AutofillChangeList changes; + FormFieldData field; + field.name = ASCIIToUTF16("Name"); + field.value = ASCIIToUTF16("Superman"); + base::Time now = base::Time::FromDoubleT(1546889367); + + EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, now)); + + std::vector<AutofillEntry> prefix_v; + EXPECT_TRUE(table_->GetFormValuesForElementName( + field.name, ASCIIToUTF16("Super"), &prefix_v, 10)); + + std::vector<AutofillEntry> no_prefix_v; + EXPECT_TRUE(table_->GetFormValuesForElementName(field.name, ASCIIToUTF16(""), + &no_prefix_v, 10)); + + AutofillEntry expected_entry(AutofillKey(field.name, field.value), now, now); + + EXPECT_THAT(prefix_v, ElementsAre(expected_entry)); + EXPECT_THAT(no_prefix_v, ElementsAre(expected_entry)); + + // Update date_last_used. + base::Time new_time = now + base::TimeDelta::FromSeconds(1000); + EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, new_time)); + EXPECT_TRUE(table_->GetFormValuesForElementName( + field.name, ASCIIToUTF16("Super"), &prefix_v, 10)); + EXPECT_TRUE(table_->GetFormValuesForElementName(field.name, ASCIIToUTF16(""), + &no_prefix_v, 10)); + + expected_entry = + AutofillEntry(AutofillKey(field.name, field.value), now, new_time); + + EXPECT_THAT(prefix_v, ElementsAre(expected_entry)); + EXPECT_THAT(no_prefix_v, ElementsAre(expected_entry)); +} + TEST_F(AutofillTableTest, Autofill_GetCountOfValuesContainedBetween) { AutofillChangeList changes; // This test makes time comparisons that are precise to a microsecond, but the @@ -468,7 +514,7 @@ TEST_F(AutofillTableTest, Autofill_UpdateNullTerminated) { const char kName[] = "foo"; const char kValue[] = "bar"; // A value which contains terminating character. - std::string value(kValue, arraysize(kValue)); + std::string value(kValue, base::size(kValue)); AutofillEntry entry0(MakeAutofillEntry(kName, kValue, 1, -1)); AutofillEntry entry1(MakeAutofillEntry(kName, value, 2, 3)); @@ -772,6 +818,70 @@ TEST_F(AutofillTableTest, changes.clear(); } +// Tests that we set the change type to REMOVE for expired elements when the +// Autocomplete Retention Policy feature flag is off. +TEST_F(AutofillTableTest, RemoveExpiredFormElements_FlagOff_Removes) { + scoped_feature_list_.InitAndDisableFeature( + features::kAutocompleteRetentionPolicyEnabled); + auto kNow = AutofillClock::Now(); + auto k4MonthsOld = kNow - base::TimeDelta::FromDays(4 * 30); + + AutofillChangeList changes; + FormFieldData field; + field.name = ASCIIToUTF16("Name"); + field.value = ASCIIToUTF16("Superman"); + EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, k4MonthsOld)); + changes.clear(); + + EXPECT_TRUE(table_->RemoveExpiredFormElements(&changes)); + + EXPECT_EQ(AutofillChange(AutofillChange::REMOVE, + AutofillKey(field.name, field.value)), + changes[0]); +} + +// Tests that we set the change type to EXPIRE for expired elements when the +// Autocomplete Retention Policy feature flag is on. +TEST_F(AutofillTableTest, RemoveExpiredFormElements_FlagOn_Expires) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + auto kNow = AutofillClock::Now(); + auto k2YearsOld = kNow - base::TimeDelta::FromDays( + 2 * kAutocompleteRetentionPolicyPeriodInDays); + + AutofillChangeList changes; + FormFieldData field; + field.name = ASCIIToUTF16("Name"); + field.value = ASCIIToUTF16("Superman"); + EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, k2YearsOld)); + changes.clear(); + + EXPECT_TRUE(table_->RemoveExpiredFormElements(&changes)); + + EXPECT_EQ(AutofillChange(AutofillChange::EXPIRE, + AutofillKey(field.name, field.value)), + changes[0]); +} + +// Tests that, with the Autocomplete Retention Policy feature flag on, we don't +// delete non-expired entries' data from the SQLite table. +TEST_F(AutofillTableTest, RemoveExpiredFormElements_FlagOn_NotOldEnough) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + auto kNow = AutofillClock::Now(); + auto k2DaysOld = kNow - base::TimeDelta::FromDays(2); + + AutofillChangeList changes; + FormFieldData field; + field.name = ASCIIToUTF16("Name"); + field.value = ASCIIToUTF16("Superman"); + EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, k2DaysOld)); + changes.clear(); + + EXPECT_TRUE(table_->RemoveExpiredFormElements(&changes)); + EXPECT_TRUE(changes.empty()); +} + TEST_F(AutofillTableTest, AutofillProfile) { // Add a 'Home' profile with non-default data. The specific values are not // important. @@ -1979,6 +2089,133 @@ TEST_F(AutofillTableTest, SetGetRemoveServerAddressMetadata) { EXPECT_EQ(0U, outputs.size()); } +TEST_F(AutofillTableTest, AddUpdateServerAddressMetadata) { + // Create and set the metadata. + AutofillMetadata input; + input.id = "server id"; + input.use_count = 50; + input.use_date = Time::Now(); + input.has_converted = true; + ASSERT_TRUE(table_->AddServerAddressMetadata(input)); + + // Make sure it was added correctly. + std::map<std::string, AutofillMetadata> outputs; + ASSERT_TRUE(table_->GetServerAddressesMetadata(&outputs)); + ASSERT_EQ(1U, outputs.size()); + ASSERT_EQ(input, outputs[input.id]); + + // Update the metadata in the table. + input.use_count = 51; + EXPECT_TRUE(table_->UpdateServerAddressMetadata(input)); + + // Make sure it was updated correctly. + ASSERT_TRUE(table_->GetServerAddressesMetadata(&outputs)); + ASSERT_EQ(1U, outputs.size()); + EXPECT_EQ(input, outputs[input.id]); + + // Insert a new entry using update - that should also be legal. + input.id = "another server id"; + EXPECT_TRUE(table_->UpdateServerAddressMetadata(input)); + ASSERT_TRUE(table_->GetServerAddressesMetadata(&outputs)); + ASSERT_EQ(2U, outputs.size()); +} + +TEST_F(AutofillTableTest, AddUpdateServerCardMetadata) { + // Create and set the metadata. + AutofillMetadata input; + input.id = "server id"; + input.use_count = 50; + input.use_date = Time::Now(); + input.billing_address_id = "billing id"; + ASSERT_TRUE(table_->AddServerCardMetadata(input)); + + // Make sure it was added correctly. + std::map<std::string, AutofillMetadata> outputs; + ASSERT_TRUE(table_->GetServerCardsMetadata(&outputs)); + ASSERT_EQ(1U, outputs.size()); + ASSERT_EQ(input, outputs[input.id]); + + // Update the metadata in the table. + input.use_count = 51; + EXPECT_TRUE(table_->UpdateServerCardMetadata(input)); + + // Make sure it was updated correctly. + ASSERT_TRUE(table_->GetServerCardsMetadata(&outputs)); + ASSERT_EQ(1U, outputs.size()); + EXPECT_EQ(input, outputs[input.id]); + + // Insert a new entry using update - that should also be legal. + input.id = "another server id"; + EXPECT_TRUE(table_->UpdateServerCardMetadata(input)); + ASSERT_TRUE(table_->GetServerCardsMetadata(&outputs)); + ASSERT_EQ(2U, outputs.size()); +} + +TEST_F(AutofillTableTest, UpdateServerAddressMetadataDoesNotChangeData) { + AutofillProfile one(AutofillProfile::SERVER_PROFILE, "a123"); + std::vector<AutofillProfile> inputs; + inputs.push_back(one); + table_->SetServerProfiles(inputs); + + std::vector<std::unique_ptr<AutofillProfile>> outputs; + table_->GetServerProfiles(&outputs); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(one.server_id(), outputs[0]->server_id()); + + // Update metadata in the profile. + ASSERT_NE(outputs[0]->use_count(), 51u); + outputs[0]->set_use_count(51); + + AutofillMetadata input_metadata = outputs[0]->GetMetadata(); + EXPECT_TRUE(table_->UpdateServerAddressMetadata(input_metadata)); + + // Make sure it was updated correctly. + std::map<std::string, AutofillMetadata> output_metadata; + ASSERT_TRUE(table_->GetServerAddressesMetadata(&output_metadata)); + ASSERT_EQ(1U, output_metadata.size()); + EXPECT_EQ(input_metadata, output_metadata[input_metadata.id]); + + // Make sure nothing else got updated. + std::vector<std::unique_ptr<AutofillProfile>> outputs2; + table_->GetServerProfiles(&outputs2); + ASSERT_EQ(1u, outputs2.size()); + EXPECT_TRUE(outputs[0]->EqualsForSyncPurposes(*outputs2[0])); +} + +TEST_F(AutofillTableTest, UpdateServerCardMetadataDoesNotChangeData) { + std::vector<CreditCard> inputs; + inputs.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "a123")); + inputs[0].SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Paul F. Tompkins")); + inputs[0].SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("1")); + inputs[0].SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2020")); + inputs[0].SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("4111111111111111")); + test::SetServerCreditCards(table_.get(), inputs); + + std::vector<std::unique_ptr<CreditCard>> outputs; + ASSERT_TRUE(table_->GetServerCreditCards(&outputs)); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(inputs[0].server_id(), outputs[0]->server_id()); + + // Update metadata in the profile. + ASSERT_NE(outputs[0]->use_count(), 51u); + outputs[0]->set_use_count(51); + + AutofillMetadata input_metadata = outputs[0]->GetMetadata(); + EXPECT_TRUE(table_->UpdateServerCardMetadata(input_metadata)); + + // Make sure it was updated correctly. + std::map<std::string, AutofillMetadata> output_metadata; + ASSERT_TRUE(table_->GetServerCardsMetadata(&output_metadata)); + ASSERT_EQ(1U, output_metadata.size()); + EXPECT_EQ(input_metadata, output_metadata[input_metadata.id]); + + // Make sure nothing else got updated. + std::vector<std::unique_ptr<CreditCard>> outputs2; + table_->GetServerCreditCards(&outputs2); + ASSERT_EQ(1u, outputs2.size()); + EXPECT_EQ(0, outputs[0]->Compare(*outputs2[0])); +} + TEST_F(AutofillTableTest, RemoveWrongServerCardMetadata) { // Crete and set some metadata. AutofillMetadata input; @@ -2580,13 +2817,14 @@ TEST_P(GetFormValuesTest, GetFormValuesForElementName_SubstringMatchEnabled) { table_->AddFormFieldValue(field, &changes); } - std::vector<base::string16> v; + std::vector<AutofillEntry> v; table_->GetFormValuesForElementName( ASCIIToUTF16("Name"), ASCIIToUTF16(test_case.field_contents), &v, 6); EXPECT_EQ(test_case.expected_suggestion_count, v.size()); for (size_t j = 0; j < test_case.expected_suggestion_count; ++j) { - EXPECT_EQ(ASCIIToUTF16(test_case.expected_suggestion[j]), v[j]); + EXPECT_EQ(ASCIIToUTF16(test_case.expected_suggestion[j]), + v[j].key().value()); } changes.clear(); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc index c04756fd18c..98721d9d598 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc @@ -10,6 +10,7 @@ #include "base/base64.h" #include "base/logging.h" #include "base/optional.h" +#include "base/pickle.h" #include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" @@ -17,6 +18,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_util.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/mutable_data_batch.h" #include "components/sync/model_impl/client_tag_based_model_type_processor.h" @@ -27,6 +29,8 @@ namespace autofill { namespace { using sync_pb::WalletMetadataSpecifics; +using syncer::EntityChange; +using syncer::EntityChangeList; using syncer::EntityData; using syncer::MetadataChangeList; @@ -46,10 +50,53 @@ std::string GetClientTagForSpecificsId(WalletMetadataSpecifics::Type type, } } +// Returns the wallet metadata specifics id for the specified |metadata_id|. +std::string GetSpecificsIdForMetadataId(const std::string& metadata_id) { + // Metadata id is in the raw format (like profiles/cards from WalletData) + // whereas the specifics id is base64-encoded. + return GetBase64EncodedId(metadata_id); +} + +// Returns the wallet metadata id for the specified |specifics_id|. +std::string GetMetadataIdForSpecificsId(const std::string& specifics_id) { + // The specifics id is base64-encoded whereas the metadata id is in the raw + // format (like profiles/cards from WalletData). + return GetBase64DecodedId(specifics_id); +} + +// Returns the wallet metadata specifics storage key for the specified |type| +// and |metadata_id|. +std::string GetStorageKeyForWalletMetadataTypeAndId( + WalletMetadataSpecifics::Type type, + const std::string& metadata_id) { + return GetStorageKeyForWalletMetadataTypeAndSpecificsId( + type, GetSpecificsIdForMetadataId(metadata_id)); +} + +struct TypeAndMetadataId { + WalletMetadataSpecifics::Type type; + std::string metadata_id; +}; + +TypeAndMetadataId ParseWalletMetadataStorageKey( + const std::string& storage_key) { + TypeAndMetadataId parsed; + + base::Pickle pickle(storage_key.data(), storage_key.size()); + base::PickleIterator iterator(pickle); + int type_int; + if (!iterator.ReadInt(&type_int) || + !iterator.ReadString(&parsed.metadata_id)) { + NOTREACHED() << "Unsupported storage_key provided " << storage_key; + } + parsed.type = static_cast<WalletMetadataSpecifics::Type>(type_int); + return parsed; +} + // Returns EntityData for wallet_metadata for |local_metadata| and |type|. std::unique_ptr<EntityData> CreateEntityDataFromAutofillMetadata( - const AutofillMetadata& local_metadata, - WalletMetadataSpecifics::Type type) { + WalletMetadataSpecifics::Type type, + const AutofillMetadata& local_metadata) { auto entity_data = std::make_unique<EntityData>(); std::string specifics_id = GetSpecificsIdForMetadataId(local_metadata.id); entity_data->non_unique_name = GetClientTagForSpecificsId(type, specifics_id); @@ -69,10 +116,8 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillMetadata( } case WalletMetadataSpecifics::CARD: { // The strings must be in valid UTF-8 to sync. - std::string billing_address_id; - base::Base64Encode(local_metadata.billing_address_id, - &billing_address_id); - remote_metadata->set_card_billing_address_id(billing_address_id); + remote_metadata->set_card_billing_address_id( + GetBase64EncodedId(local_metadata.billing_address_id)); break; } case WalletMetadataSpecifics::UNKNOWN: { @@ -84,18 +129,156 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillMetadata( return entity_data; } -// Returns EntityData for wallet_metadata for |local_profile|. -std::unique_ptr<EntityData> CreateMetadataEntityDataFromAutofillServerProfile( - const AutofillProfile& local_profile) { - return CreateEntityDataFromAutofillMetadata(local_profile.GetMetadata(), - WalletMetadataSpecifics::ADDRESS); +// Returns AutofillMetadata for |specifics|. +AutofillMetadata CreateAutofillMetadataFromWalletMetadataSpecifics( + const WalletMetadataSpecifics& specifics) { + AutofillMetadata metadata; + metadata.id = GetMetadataIdForSpecificsId(specifics.id()); + metadata.use_count = specifics.use_count(); + metadata.use_date = base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromMicroseconds(specifics.use_date())); + + switch (specifics.type()) { + case WalletMetadataSpecifics::ADDRESS: + metadata.has_converted = specifics.address_has_converted(); + break; + case WalletMetadataSpecifics::CARD: + metadata.billing_address_id = + GetBase64DecodedId(specifics.card_billing_address_id()); + break; + case WalletMetadataSpecifics::UNKNOWN: + break; + } + + return metadata; +} + +bool HasLocalBillingAddress(const AutofillMetadata& metadata) { + return metadata.billing_address_id.size() == kLocalGuidSize; +} + +bool IsRemoteBillingAddressEqualOrBetter(const AutofillMetadata& local, + const AutofillMetadata& remote) { + // If local is empty, remote is better (or equal). Otherwise, if remote is + // empty, local is better. + if (local.billing_address_id.empty()) { + return true; + } else if (remote.billing_address_id.empty()) { + return false; + } + // Now we need to decide between non-empty profiles. Prefer id's pointing to + // local profiles over ids of non-local profiles. + if (HasLocalBillingAddress(local) != HasLocalBillingAddress(remote)) { + return HasLocalBillingAddress(remote); + } + // For both local / both remote, we prefer the more recently used. + return remote.use_date >= local.use_date; +} + +AutofillMetadata MergeMetadata(WalletMetadataSpecifics::Type type, + const AutofillMetadata& local, + const AutofillMetadata& remote) { + AutofillMetadata merged; + DCHECK_EQ(local.id, remote.id); + merged.id = local.id; + + switch (type) { + case WalletMetadataSpecifics::ADDRESS: + merged.has_converted = local.has_converted || remote.has_converted; + break; + case WalletMetadataSpecifics::CARD: + if (IsRemoteBillingAddressEqualOrBetter(local, remote)) { + merged.billing_address_id = remote.billing_address_id; + } else { + merged.billing_address_id = local.billing_address_id; + } + break; + case WalletMetadataSpecifics::UNKNOWN: + NOTREACHED(); + break; + } + + // Special case for local models with a use_count of one. This means the local + // model was only created, never used. The remote model should always be + // preferred. + // This situation can happen for new Chromium instances where there is no data + // yet on disk, making the use_date artificially high. Once the metadata sync + // kicks in, we should use that value. + if (local.use_count == 1) { + merged.use_count = remote.use_count; + merged.use_date = remote.use_date; + } else { + merged.use_count = std::max(local.use_count, remote.use_count); + merged.use_date = std::max(local.use_date, remote.use_date); + } + return merged; +} + +// Metadata is worth updating if its value is "newer" then before; here "newer" +// is the ordering of legal state transitions that metadata can take that is +// defined below. +bool IsMetadataWorthUpdating(AutofillMetadata existing_entry, + AutofillMetadata new_entry) { + if (existing_entry.use_count < new_entry.use_count && + existing_entry.use_date < new_entry.use_date) { + return true; + } + // For the following type-specific fields, we don't have to distinguish the + // type of metadata as both entries must be of the same type and therefore + // irrelevant values are default, thus equal. + + // It is only legal to move from non-converted to converted. Do not accept + // the other transition. + if (!existing_entry.has_converted && new_entry.has_converted) { + return true; + } + if (existing_entry.billing_address_id != new_entry.billing_address_id) { + return true; + } + return false; +} + +bool AddServerMetadata(AutofillTable* table, + WalletMetadataSpecifics::Type type, + const AutofillMetadata& metadata) { + switch (type) { + case WalletMetadataSpecifics::ADDRESS: + return table->AddServerAddressMetadata(metadata); + case WalletMetadataSpecifics::CARD: + return table->AddServerCardMetadata(metadata); + case WalletMetadataSpecifics::UNKNOWN: + NOTREACHED(); + return false; + } +} + +bool RemoveServerMetadata(AutofillTable* table, + WalletMetadataSpecifics::Type type, + const std::string& id) { + switch (type) { + case WalletMetadataSpecifics::ADDRESS: + return table->RemoveServerAddressMetadata(id); + case WalletMetadataSpecifics::CARD: + return table->RemoveServerCardMetadata(id); + case WalletMetadataSpecifics::UNKNOWN: + NOTREACHED(); + return false; + } } -// Returns EntityData for wallet_metadata for |local_card|. -std::unique_ptr<EntityData> CreateMetadataEntityDataFromCard( - const CreditCard& local_card) { - return CreateEntityDataFromAutofillMetadata(local_card.GetMetadata(), - WalletMetadataSpecifics::CARD); +bool UpdateServerMetadata(AutofillTable* table, + WalletMetadataSpecifics::Type type, + const AutofillMetadata& metadata) { + // TODO: Create UpdateServerAddressMetadata() that takes metadata as arg. + switch (type) { + case WalletMetadataSpecifics::ADDRESS: + return table->UpdateServerAddressMetadata(metadata); + case WalletMetadataSpecifics::CARD: + return table->UpdateServerCardMetadata(metadata); + case WalletMetadataSpecifics::UNKNOWN: + NOTREACHED(); + return false; + } } } // namespace @@ -155,16 +338,19 @@ base::Optional<syncer::ModelError> AutofillWalletMetadataSyncBridge::MergeSyncData( std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, syncer::EntityChangeList entity_data) { - NOTIMPLEMENTED(); - return base::nullopt; + // First upload local entities that are not mentioned in |entity_data|. + UploadInitialLocalData(metadata_change_list.get(), entity_data); + + return MergeRemoteChanges(std::move(metadata_change_list), + std::move(entity_data)); } base::Optional<syncer::ModelError> AutofillWalletMetadataSyncBridge::ApplySyncChanges( std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, syncer::EntityChangeList entity_data) { - NOTIMPLEMENTED(); - return base::nullopt; + return MergeRemoteChanges(std::move(metadata_change_list), + std::move(entity_data)); } void AutofillWalletMetadataSyncBridge::GetData(StorageKeyList storage_keys, @@ -191,70 +377,25 @@ std::string AutofillWalletMetadataSyncBridge::GetClientTag( std::string AutofillWalletMetadataSyncBridge::GetStorageKey( const syncer::EntityData& entity_data) { - return GetStorageKeyForSpecificsId( + return GetStorageKeyForWalletMetadataTypeAndSpecificsId( + entity_data.specifics.wallet_metadata().type(), entity_data.specifics.wallet_metadata().id()); } void AutofillWalletMetadataSyncBridge::AutofillProfileChanged( const AutofillProfileChange& change) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - const AutofillProfile* changed = change.data_model(); - if (!changed || changed->record_type() != AutofillProfile::SERVER_PROFILE) { + // Skip local profiles (if possible, i.e. if it is not a deletion where + // data_model() is not set). + if (change.data_model() && + change.data_model()->record_type() != AutofillProfile::SERVER_PROFILE) { return; } - - // The only legal change on a server profile is that its use count or use date - // or has-converted status gets updated. Other changes (adding, deleting) are - // only done by the AutofillWalletSyncBridge and result only in the - // AutofillMultipleChanged() notification. - DCHECK(change.type() == AutofillProfileChange::UPDATE); - SyncUpUpdatedEntity( - CreateMetadataEntityDataFromAutofillServerProfile(*changed)); + LocalMetadataChanged(WalletMetadataSpecifics::ADDRESS, change); } void AutofillWalletMetadataSyncBridge::CreditCardChanged( const CreditCardChange& change) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - const CreditCard* changed = change.data_model(); - if (!changed || changed->record_type() == CreditCard::LOCAL_CARD) { - return; - } - - // The only legal change on a server card is that its use count or use date or - // billing address id gets updated. Other changes (adding, deleting) are only - // done by the AutofillWalletSyncBridge and result only in the - // AutofillMultipleChanged() notification. - DCHECK(change.type() == CreditCardChange::UPDATE); - SyncUpUpdatedEntity(CreateMetadataEntityDataFromCard(*changed)); -} - -void AutofillWalletMetadataSyncBridge::AutofillMultipleChanged() { - NOTIMPLEMENTED(); -} - -void AutofillWalletMetadataSyncBridge::SyncUpUpdatedEntity( - std::unique_ptr<EntityData> entity_after_change) { - std::string storage_key = GetStorageKey(*entity_after_change); - auto it = cache_.find(storage_key); - - // This *changed* entity should already be in the cache, ignore otherwise. - if (it == cache_.end()) - return; - - const WalletMetadataSpecifics& specifics_before = it->second; - const WalletMetadataSpecifics& specifics_after = - entity_after_change->specifics.wallet_metadata(); - - if (specifics_before.use_count() < specifics_after.use_count() && - specifics_before.use_date() < specifics_after.use_date()) { - std::unique_ptr<MetadataChangeList> metadata_change_list = - CreateMetadataChangeList(); - cache_[storage_key] = specifics_after; - change_processor()->Put(storage_key, std::move(entity_after_change), - metadata_change_list.get()); - } + LocalMetadataChanged(WalletMetadataSpecifics::CARD, change); } AutofillTable* AutofillWalletMetadataSyncBridge::GetAutofillTable() { @@ -269,23 +410,23 @@ void AutofillWalletMetadataSyncBridge::LoadDataCacheAndMetadata() { return; } - // Load the data cache. - std::vector<std::unique_ptr<AutofillProfile>> profiles; - std::vector<std::unique_ptr<CreditCard>> cards; - if (!GetAutofillTable()->GetServerProfiles(&profiles) || - !GetAutofillTable()->GetServerCreditCards(&cards)) { + // Load the data cache (both addresses and cards into the same cache, the keys + // in the cache never overlap). + std::map<std::string, AutofillMetadata> addresses_metadata; + std::map<std::string, AutofillMetadata> cards_metadata; + if (!GetAutofillTable()->GetServerAddressesMetadata(&addresses_metadata) || + !GetAutofillTable()->GetServerCardsMetadata(&cards_metadata)) { change_processor()->ReportError( {FROM_HERE, "Failed reading autofill data from WebDatabase."}); return; } - for (const std::unique_ptr<AutofillProfile>& entry : profiles) { - cache_[GetStorageKeyForMetadataId(entry->GetMetadata().id)] = - CreateMetadataEntityDataFromAutofillServerProfile(*entry) - ->specifics.wallet_metadata(); + for (const auto& it : addresses_metadata) { + cache_[GetStorageKeyForWalletMetadataTypeAndId( + WalletMetadataSpecifics::ADDRESS, it.first)] = it.second; } - for (const std::unique_ptr<CreditCard>& entry : cards) { - cache_[GetStorageKeyForMetadataId(entry->GetMetadata().id)] = - CreateMetadataEntityDataFromCard(*entry)->specifics.wallet_metadata(); + for (const auto& it : cards_metadata) { + cache_[GetStorageKeyForWalletMetadataTypeAndId( + WalletMetadataSpecifics::CARD, it.first)] = it.second; } // Load the metadata and send to the processor. @@ -305,32 +446,166 @@ void AutofillWalletMetadataSyncBridge::GetDataImpl( DataCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::vector<std::unique_ptr<AutofillProfile>> profiles; - std::vector<std::unique_ptr<CreditCard>> cards; - if (!GetAutofillTable()->GetServerProfiles(&profiles) || - !GetAutofillTable()->GetServerCreditCards(&cards)) { - change_processor()->ReportError( - {FROM_HERE, "Failed to load entries from table."}); - return; - } - auto batch = std::make_unique<syncer::MutableDataBatch>(); - for (const std::unique_ptr<AutofillProfile>& entry : profiles) { - std::string key = GetStorageKeyForMetadataId(entry->GetMetadata().id); - if (!storage_keys_set || base::ContainsKey(*storage_keys_set, key)) { - batch->Put(key, - CreateMetadataEntityDataFromAutofillServerProfile(*entry)); + for (const auto& pair : cache_) { + const std::string& storage_key = pair.first; + const AutofillMetadata& metadata = pair.second; + TypeAndMetadataId parsed_storage_key = + ParseWalletMetadataStorageKey(storage_key); + if (!storage_keys_set || + base::ContainsKey(*storage_keys_set, storage_key)) { + batch->Put(storage_key, CreateEntityDataFromAutofillMetadata( + parsed_storage_key.type, metadata)); } } - for (const std::unique_ptr<CreditCard>& entry : cards) { - std::string key = GetStorageKeyForMetadataId(entry->GetMetadata().id); - if (!storage_keys_set || base::ContainsKey(*storage_keys_set, key)) { - batch->Put(key, CreateMetadataEntityDataFromCard(*entry)); + + std::move(callback).Run(std::move(batch)); +} + +void AutofillWalletMetadataSyncBridge::UploadInitialLocalData( + syncer::MetadataChangeList* metadata_change_list, + const syncer::EntityChangeList& entity_data) { + // First, make a copy of all local storage keys. + std::set<std::string> local_keys_to_upload; + for (const auto& it : cache_) { + local_keys_to_upload.insert(it.first); + } + // Strip |local_keys_to_upload| of the keys of data provided by the server. + for (const EntityChange& change : entity_data) { + DCHECK_EQ(change.type(), EntityChange::ACTION_ADD) + << "Illegal change; can only be called during initial MergeSyncData()"; + local_keys_to_upload.erase(change.storage_key()); + } + // Upload the remaining storage keys + for (const std::string& storage_key : local_keys_to_upload) { + TypeAndMetadataId parsed_storage_key = + ParseWalletMetadataStorageKey(storage_key); + change_processor()->Put(storage_key, + CreateEntityDataFromAutofillMetadata( + parsed_storage_key.type, cache_[storage_key]), + metadata_change_list); + } +} + +base::Optional<syncer::ModelError> +AutofillWalletMetadataSyncBridge::MergeRemoteChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + bool is_any_local_modified = false; + + AutofillTable* table = GetAutofillTable(); + + for (const EntityChange& change : entity_data) { + TypeAndMetadataId parsed_storage_key = + ParseWalletMetadataStorageKey(change.storage_key()); + switch (change.type()) { + case EntityChange::ACTION_ADD: + case EntityChange::ACTION_UPDATE: { + const WalletMetadataSpecifics& specifics = + change.data().specifics.wallet_metadata(); + AutofillMetadata remote = + CreateAutofillMetadataFromWalletMetadataSpecifics(specifics); + auto it = cache_.find(change.storage_key()); + base::Optional<AutofillMetadata> local = base::nullopt; + if (it != cache_.end()) { + local = it->second; + } + + if (!local) { + cache_[change.storage_key()] = remote; + is_any_local_modified |= AddServerMetadata( + GetAutofillTable(), parsed_storage_key.type, remote); + continue; + } + + // Resolve the conflict between the local and the newly received remote. + AutofillMetadata merged = + MergeMetadata(parsed_storage_key.type, *local, remote); + if (merged != *local) { + cache_[change.storage_key()] = merged; + is_any_local_modified |= + UpdateServerMetadata(table, parsed_storage_key.type, merged); + } + if (merged != remote) { + change_processor()->Put(change.storage_key(), + CreateEntityDataFromAutofillMetadata( + parsed_storage_key.type, merged), + metadata_change_list.get()); + } + break; + } + case EntityChange::ACTION_DELETE: { + cache_.erase(change.storage_key()); + is_any_local_modified |= RemoveServerMetadata( + table, parsed_storage_key.type, parsed_storage_key.metadata_id); + break; + } } } - std::move(callback).Run(std::move(batch)); + if (is_any_local_modified) { + web_data_backend_->NotifyOfMultipleAutofillChanges(); + } + return base::nullopt; +} + +template <class DataType> +void AutofillWalletMetadataSyncBridge::LocalMetadataChanged( + WalletMetadataSpecifics::Type type, + AutofillDataModelChange<DataType> change) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const std::string& metadata_id = change.key(); + std::string storage_key = + GetStorageKeyForWalletMetadataTypeAndId(type, metadata_id); + std::unique_ptr<MetadataChangeList> metadata_change_list = + CreateMetadataChangeList(); + + switch (change.type()) { + case AutofillProfileChange::EXPIRE: + NOTREACHED() << "EXPIRE change is not allowed for wallet entities"; + return; + case AutofillProfileChange::REMOVE: + if (RemoveServerMetadata(GetAutofillTable(), type, metadata_id)) { + cache_.erase(storage_key); + // Send up deletion only if we had this entry in the DB. It is not there + // if (i) it was previously deleted by a remote deletion or (ii) this is + // notification for a LOCAL_PROFILE (which have non-overlapping + // storage_keys). + change_processor()->Delete(storage_key, metadata_change_list.get()); + } + return; + case AutofillProfileChange::ADD: + case AutofillProfileChange::UPDATE: + DCHECK(change.data_model()); + + AutofillMetadata new_entry = change.data_model()->GetMetadata(); + auto it = cache_.find(storage_key); + base::Optional<AutofillMetadata> existing_entry = base::nullopt; + if (it != cache_.end()) { + existing_entry = it->second; + } + + if (existing_entry && + !IsMetadataWorthUpdating(*existing_entry, new_entry)) { + // Skip changes that are outdated, etc. (changes that would result in + // inferior metadata compared to what we have now). + return; + } + + cache_[storage_key] = new_entry; + if (existing_entry) { + UpdateServerMetadata(GetAutofillTable(), type, new_entry); + } else { + AddServerMetadata(GetAutofillTable(), type, new_entry); + } + + change_processor()->Put( + storage_key, CreateEntityDataFromAutofillMetadata(type, new_entry), + metadata_change_list.get()); + return; + } } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h index 59241199da3..16feaf2dd78 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h @@ -78,18 +78,14 @@ class AutofillWalletMetadataSyncBridge // AutofillWebDataServiceObserverOnDBSequence implementation. void AutofillProfileChanged(const AutofillProfileChange& change) override; void CreditCardChanged(const CreditCardChange& change) override; - void AutofillMultipleChanged() override; private: - // Syncs up an updated entity |entity_after_change| (if needed). - void SyncUpUpdatedEntity( - std::unique_ptr<syncer::EntityData> entity_after_change); - // Returns the table associated with the |web_data_backend_|. AutofillTable* GetAutofillTable(); - // Synchronously load |cache_| and sync metadata from the autofill table - // and pass the latter to the processor so that it can start tracking changes. + // Synchronously load the sync data into |cache_| and sync metadata from the + // autofill table and pass the latter to the processor so that it can start + // tracking changes. void LoadDataCacheAndMetadata(); // Reads local wallet metadata from the database and passes them into @@ -99,6 +95,23 @@ class AutofillWalletMetadataSyncBridge base::Optional<std::unordered_set<std::string>> storage_keys_set, DataCallback callback); + // Uploads local data that is not part of |entity_data| sent from the server + // during initial MergeSyncData(). + void UploadInitialLocalData(syncer::MetadataChangeList* metadata_change_list, + const syncer::EntityChangeList& entity_data); + + // Merges remote changes, specified in |entity_data|, with the local DB and, + // potentially, writes changes to the local DB and/or commits updates of + // entities from |entity_data| up to sync. + base::Optional<syncer::ModelError> MergeRemoteChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data); + + // Reacts to a local |change| of an entry of type |type|. + template <class DataType> + void LocalMetadataChanged(sync_pb::WalletMetadataSpecifics::Type type, + AutofillDataModelChange<DataType> change); + // AutofillWalletMetadataSyncBridge is owned by |web_data_backend_| through // SupportsUserData, so it's guaranteed to outlive |this|. AutofillWebDataBackend* const web_data_backend_; @@ -106,10 +119,9 @@ class AutofillWalletMetadataSyncBridge ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncBridge> scoped_observer_; - // Cache of the data (local data + data that hasn't synced down yet); keyed by - // storage keys. Needed for figuring out what to sync up when larger changes - // happen in the local database. - std::unordered_map<std::string, sync_pb::WalletMetadataSpecifics> cache_; + // Cache of the local data that allows figuring out the diff for local + // changes; keyed by storage keys. + std::map<std::string, AutofillMetadata> cache_; // Indicates whether we should rely on wallet data being actively synced. If // true, the bridge will prune metadata entries without corresponding wallet diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc index 2b0de491dcb..4306ae52280 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc @@ -6,6 +6,7 @@ #include <stddef.h> +#include <algorithm> #include <memory> #include <sstream> #include <utility> @@ -14,7 +15,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/time/time.h" @@ -23,6 +24,7 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h" +#include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" #include "components/autofill/core/common/autofill_constants.h" @@ -48,6 +50,7 @@ using syncer::MockModelTypeChangeProcessor; using syncer::ModelType; using testing::_; using testing::ElementsAre; +using testing::ElementsAreArray; using testing::IsEmpty; using testing::Return; using testing::UnorderedElementsAre; @@ -65,6 +68,15 @@ const char kAddr2SpecificsId[] = "YWRkcjLvv74="; const char kCard1SpecificsId[] = "Y2FyZDHvv74="; const char kCard2SpecificsId[] = "Y2FyZDLvv74="; +const std::string kAddr1StorageKey = + GetStorageKeyForWalletMetadataTypeAndSpecificsId( + WalletMetadataSpecifics::ADDRESS, + kAddr1SpecificsId); +const std::string kCard1StorageKey = + GetStorageKeyForWalletMetadataTypeAndSpecificsId( + WalletMetadataSpecifics::CARD, + kCard1SpecificsId); + // Unique sync tags for the server IDs. const char kAddr1SyncTag[] = "address-YWRkcjHvv74="; const char kCard1SyncTag[] = "card-Y2FyZDHvv74="; @@ -81,6 +93,16 @@ int64_t UseDateToProtoValue(base::Time use_date) { return use_date.ToDeltaSinceWindowsEpoch().InMicroseconds(); } +std::string GetAddressStorageKey(const std::string& specifics_id) { + return GetStorageKeyForWalletMetadataTypeAndSpecificsId( + WalletMetadataSpecifics::ADDRESS, specifics_id); +} + +std::string GetCardStorageKey(const std::string& specifics_id) { + return GetStorageKeyForWalletMetadataTypeAndSpecificsId( + WalletMetadataSpecifics::CARD, specifics_id); +} + WalletMetadataSpecifics CreateWalletMetadataSpecificsForAddressWithUseStats( const std::string& specifics_id, size_t use_count, @@ -173,6 +195,16 @@ std::string WalletMetadataSpecificsAsDebugString( return output.str(); } +std::vector<std::string> GetSortedSerializedSpecifics( + const std::vector<WalletMetadataSpecifics>& specifics) { + std::vector<std::string> serialized; + for (const WalletMetadataSpecifics& entry : specifics) { + serialized.push_back(entry.SerializeAsString()); + } + std::sort(serialized.begin(), serialized.end()); + return serialized; +} + MATCHER_P(EqualsSpecifics, expected, "") { if (arg.SerializeAsString() != expected.SerializeAsString()) { *result_listener << "entry\n" @@ -250,6 +282,18 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { return data; } + // Like GetAllData() but it also checks that cache is consistent with the disk + // content. + std::vector<WalletMetadataSpecifics> GetAllLocalDataInclRestart() { + std::vector<WalletMetadataSpecifics> data_before = GetAllLocalData(); + ResetProcessor(); + ResetBridge(); + std::vector<WalletMetadataSpecifics> data_after = GetAllLocalData(); + EXPECT_THAT(GetSortedSerializedSpecifics(data_before), + ElementsAreArray(GetSortedSerializedSpecifics(data_after))); + return data_after; + } + std::vector<WalletMetadataSpecifics> GetLocalData( AutofillWalletMetadataSyncBridge::StorageKeyList storage_keys) { std::vector<WalletMetadataSpecifics> data; @@ -313,7 +357,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForAddress) { WalletMetadataSpecifics specifics = CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId); EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)), - kAddr1SpecificsId); + GetAddressStorageKey(kAddr1SpecificsId)); } TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForCard) { @@ -321,7 +365,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForCard) { WalletMetadataSpecifics specifics = CreateWalletMetadataSpecificsForCard(kCard1SpecificsId); EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)), - kCard1SpecificsId); + GetCardStorageKey(kCard1SpecificsId)); } TEST_F(AutofillWalletMetadataSyncBridgeTest, @@ -348,7 +392,8 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldNotReturnNonexistentData) { ResetBridge(); - EXPECT_THAT(GetLocalData({kAddr1SpecificsId}), IsEmpty()); + EXPECT_THAT(GetLocalData({GetAddressStorageKey(kAddr1SpecificsId)}), + IsEmpty()); } TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnSelectedData) { @@ -358,7 +403,8 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnSelectedData) { CreateServerCreditCard(kCard2ServerId)}); ResetBridge(); - EXPECT_THAT(GetLocalData({kAddr1SpecificsId, kCard1SpecificsId}), + EXPECT_THAT(GetLocalData({GetAddressStorageKey(kAddr1SpecificsId), + GetCardStorageKey(kCard1SpecificsId)}), UnorderedElementsAre( EqualsSpecifics(CreateWalletMetadataSpecificsForAddress( kAddr1SpecificsId)), @@ -393,7 +439,8 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnCompleteData) { card_specifics.set_use_date(3); card_specifics.set_card_billing_address_id(kAddr1SpecificsId); - EXPECT_THAT(GetLocalData({kAddr1SpecificsId, kCard1SpecificsId}), + EXPECT_THAT(GetLocalData({GetAddressStorageKey(kAddr1SpecificsId), + GetCardStorageKey(kCard1SpecificsId)}), UnorderedElementsAre(EqualsSpecifics(profile_specifics), EqualsSpecifics(card_specifics))); } @@ -401,7 +448,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnCompleteData) { // Verify that lower values of metadata are not sent to the sync server when // local metadata is updated. TEST_F(AutofillWalletMetadataSyncBridgeTest, - DontSendLowerValueToServerOnSingleChange) { + DontSendLowerValueToServerOnUpdate) { table()->SetServerProfiles({CreateServerProfileWithUseStats( kAddr1ServerId, /*use_count=*/2, /*use_date=*/5)}); table()->SetServerCreditCards({CreateServerCreditCardWithUseStats( @@ -415,48 +462,103 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); - bridge()->AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, updated_profile.guid(), &updated_profile)); + bridge()->AutofillProfileChanged( + AutofillProfileChange(AutofillProfileChange::UPDATE, + updated_profile.server_id(), &updated_profile)); bridge()->CreditCardChanged(CreditCardChange( - CreditCardChange::UPDATE, updated_card.guid(), &updated_card)); + CreditCardChange::UPDATE, updated_card.server_id(), &updated_card)); + + // Check that also the local metadata did not get updated. + EXPECT_THAT( + GetAllLocalDataInclRestart(), + UnorderedElementsAre( + EqualsSpecifics(CreateWalletMetadataSpecificsForAddressWithUseStats( + kAddr1SpecificsId, /*use_count=*/2, /*use_date=*/5)), + EqualsSpecifics(CreateWalletMetadataSpecificsForCardWithUseStats( + kCard1SpecificsId, /*use_count=*/3, /*use_date=*/6)))); } -// Verify that one-off addition of metadata is not sent to the sync -// server. Metadata add and delete trigger multiple changes notification -// instead. -TEST_F(AutofillWalletMetadataSyncBridgeTest, DontAddToServerOnSingleChange) { +// Verify that higher values of metadata are sent to the sync server when local +// metadata is updated. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + SendHigherValuesToServerOnLocalUpdate) { table()->SetServerProfiles({CreateServerProfileWithUseStats( kAddr1ServerId, /*use_count=*/1, /*use_date=*/2)}); table()->SetServerCreditCards({CreateServerCreditCardWithUseStats( kCard1ServerId, /*use_count=*/3, /*use_date=*/4)}); ResetBridge(); + AutofillProfile updated_profile = CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/10, /*use_date=*/20); + CreditCard updated_card = CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/30, /*use_date=*/40); + + WalletMetadataSpecifics expected_profile_specifics = + CreateWalletMetadataSpecificsForAddressWithUseStats( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics expected_card_specifics = + CreateWalletMetadataSpecificsForCardWithUseStats( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + EXPECT_CALL( + mock_processor(), + Put(kAddr1StorageKey, HasSpecifics(expected_profile_specifics), _)); + EXPECT_CALL(mock_processor(), + Put(kCard1StorageKey, HasSpecifics(expected_card_specifics), _)); + + bridge()->AutofillProfileChanged( + AutofillProfileChange(AutofillProfileChange::UPDATE, + updated_profile.server_id(), &updated_profile)); + bridge()->CreditCardChanged(CreditCardChange( + CreditCardChange::UPDATE, updated_card.server_id(), &updated_card)); + + // Check that the local metadata got update as well. + EXPECT_THAT(GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(expected_profile_specifics), + EqualsSpecifics(expected_card_specifics))); +} + +// Verify that one-off addition of metadata is sent to the sync server. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + SendNewDataToServerOnLocalAddition) { + ResetBridge(); AutofillProfile new_profile = CreateServerProfileWithUseStats( - kAddr2ServerId, /*use_count=*/10, /*use_date=*/20); + kAddr1ServerId, /*use_count=*/10, /*use_date=*/20); CreditCard new_card = CreateServerCreditCardWithUseStats( - kCard2ServerId, /*use_count=*/30, /*use_date=*/40); + kCard1ServerId, /*use_count=*/30, /*use_date=*/40); - EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + WalletMetadataSpecifics expected_profile_specifics = + CreateWalletMetadataSpecificsForAddressWithUseStats( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics expected_card_specifics = + CreateWalletMetadataSpecificsForCardWithUseStats( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + EXPECT_CALL( + mock_processor(), + Put(kAddr1StorageKey, HasSpecifics(expected_profile_specifics), _)); + EXPECT_CALL(mock_processor(), + Put(kCard1StorageKey, HasSpecifics(expected_card_specifics), _)); bridge()->AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, new_profile.guid(), &new_profile)); + AutofillProfileChange::ADD, new_profile.server_id(), &new_profile)); bridge()->CreditCardChanged( - CreditCardChange(CreditCardChange::UPDATE, new_card.guid(), &new_card)); + CreditCardChange(CreditCardChange::ADD, new_card.server_id(), &new_card)); + + // Check that the new metadata got created as well. + EXPECT_THAT(GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(expected_profile_specifics), + EqualsSpecifics(expected_card_specifics))); } -// Verify that higher values of metadata are sent to the sync server when local -// metadata is updated. -TEST_F(AutofillWalletMetadataSyncBridgeTest, - SendHigherValuesToServerOnLocalSingleChange) { - table()->SetServerProfiles({CreateServerProfileWithUseStats( - kAddr1ServerId, /*use_count=*/1, /*use_date=*/2)}); - table()->SetServerCreditCards({CreateServerCreditCardWithUseStats( - kCard1ServerId, /*use_count=*/3, /*use_date=*/4)}); +// Verify that one-off addition of metadata is sent to the sync server (even +// though it is notified as an update). This tests that the bridge is robust and +// recreates metadata that may get deleted in the mean-time). +TEST_F(AutofillWalletMetadataSyncBridgeTest, SendNewDataToServerOnLocalUpdate) { ResetBridge(); - - AutofillProfile updated_profile = CreateServerProfileWithUseStats( + AutofillProfile new_profile = CreateServerProfileWithUseStats( kAddr1ServerId, /*use_count=*/10, /*use_date=*/20); - CreditCard updated_card = CreateServerCreditCardWithUseStats( + CreditCard new_card = CreateServerCreditCardWithUseStats( kCard1ServerId, /*use_count=*/30, /*use_date=*/40); WalletMetadataSpecifics expected_profile_specifics = @@ -468,14 +570,69 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, EXPECT_CALL( mock_processor(), - Put(kAddr1SpecificsId, HasSpecifics(expected_profile_specifics), _)); + Put(kAddr1StorageKey, HasSpecifics(expected_profile_specifics), _)); EXPECT_CALL(mock_processor(), - Put(kCard1SpecificsId, HasSpecifics(expected_card_specifics), _)); + Put(kCard1StorageKey, HasSpecifics(expected_card_specifics), _)); bridge()->AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, updated_profile.guid(), &updated_profile)); + AutofillProfileChange::UPDATE, new_profile.server_id(), &new_profile)); bridge()->CreditCardChanged(CreditCardChange( - CreditCardChange::UPDATE, updated_card.guid(), &updated_card)); + CreditCardChange::UPDATE, new_card.server_id(), &new_card)); + + // Check that the new metadata got created as well. + EXPECT_THAT(GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(expected_profile_specifics), + EqualsSpecifics(expected_card_specifics))); +} + +// Verify that one-off deletion of existing metadata is sent to the sync server. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + DeleteExistingDataFromServerOnLocalDeletion) { + AutofillProfile existing_profile = CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/10, /*use_date=*/20); + CreditCard existing_card = CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/30, /*use_date=*/40); + table()->SetServerProfiles({existing_profile}); + table()->SetServerCreditCards({existing_card}); + ResetBridge(); + + EXPECT_CALL(mock_processor(), Delete(kAddr1StorageKey, _)); + EXPECT_CALL(mock_processor(), Delete(kCard1StorageKey, _)); + + bridge()->AutofillProfileChanged(AutofillProfileChange( + AutofillProfileChange::REMOVE, existing_profile.server_id(), nullptr)); + bridge()->CreditCardChanged(CreditCardChange( + CreditCardChange::REMOVE, existing_card.server_id(), nullptr)); + + // Check that there is no metadata anymore. + EXPECT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); +} + +// Verify that deletion of non-existing metadata is not sent to the sync server. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + DoNotDeleteNonExistingDataFromServerOnLocalDeletion) { + AutofillProfile existing_profile = CreateServerProfileWithUseStats( + kAddr1ServerId, /*use_count=*/10, /*use_date=*/20); + CreditCard existing_card = CreateServerCreditCardWithUseStats( + kCard1ServerId, /*use_count=*/30, /*use_date=*/40); + // Save only data and not metadata. + table()->SetServerAddressesData({existing_profile}); + table()->SetServerCardsData({existing_card}); + ResetBridge(); + + // Check that there is no metadata, from start on. + ASSERT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); + + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + + bridge()->AutofillProfileChanged(AutofillProfileChange( + AutofillProfileChange::REMOVE, existing_profile.server_id(), nullptr)); + bridge()->CreditCardChanged(CreditCardChange( + CreditCardChange::REMOVE, existing_card.server_id(), nullptr)); + + // Check that there is also no metadata at the end. + EXPECT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc index 40ef9b40ee7..86fd8a07dff 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc @@ -511,6 +511,8 @@ syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges( // get rid of this hack. DCHECK(!ignore_multiple_changed_notification_); ignore_multiple_changed_notification_ = true; + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " ProcessSyncChanges notify the PDM"; web_data_backend_->NotifyOfMultipleAutofillChanges(); ignore_multiple_changed_notification_ = false; } @@ -539,8 +541,13 @@ void AutofillWalletMetadataSyncableService::AutofillProfileChanged( it->GetSpecifics().wallet_metadata(); const AutofillProfile& local = *change.data_model(); + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " AutofillProfileChanged " << local; + if (!AreLocalUseStatsUpdated(remote, local) && !IsLocalHasConvertedStatusUpdated(remote, local)) { + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " Nothing has changed, not syncing up."; return; } @@ -604,8 +611,8 @@ void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend( const std::string& app_locale) { web_data_service->GetDBUserData()->SetUserData( AutofillWalletMetadataSyncableServiceUserDataKey(), - base::WrapUnique(new AutofillWalletMetadataSyncableService( - web_data_backend, app_locale))); + std::make_unique<AutofillWalletMetadataSyncableService>(web_data_backend, + app_locale)); } // static @@ -655,6 +662,8 @@ bool AutofillWalletMetadataSyncableService::GetLocalData( bool AutofillWalletMetadataSyncableService::UpdateAddressStats( const AutofillProfile& profile) { + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " Applying change from sync " << profile; return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()) ->UpdateServerAddressMetadata(profile); } @@ -754,6 +763,8 @@ syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeData( // get rid of this hack. DCHECK(!ignore_multiple_changed_notification_); ignore_multiple_changed_notification_ = true; + // TODO(crbug.com/915229): Remove once the investigation is over. + DLOG(WARNING) << this << " MergeData notify the PDM"; web_data_backend_->NotifyOfMultipleAutofillChanges(); ignore_multiple_changed_notification_ = false; } diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h index 4df82f02c7b..0169b0deb07 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h @@ -49,6 +49,10 @@ class AutofillWalletMetadataSyncableService public syncer::SyncableService, public AutofillWebDataServiceObserverOnDBSequence { public: + AutofillWalletMetadataSyncableService( + AutofillWebDataBackend* web_data_backend, + const std::string& app_locale); + ~AutofillWalletMetadataSyncableService() override; // Determines whether this bridge should be monitoring the Wallet data. This @@ -91,10 +95,6 @@ class AutofillWalletMetadataSyncableService AutofillWebDataService* web_data_service); protected: - AutofillWalletMetadataSyncableService( - AutofillWebDataBackend* web_data_backend, - const std::string& app_locale); - // Populates the provided |profiles| and |cards| with mappings from server ID // to server profiles and server cards read from disk. This data contains the // usage stats. Returns true on success. diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc index eb9f740f4f6..8631ea78944 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc @@ -7,6 +7,7 @@ #include <utility> #include "base/base64.h" +#include "base/feature_list.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" @@ -20,6 +21,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_util.h" +#include "components/sync/driver/sync_driver_switches.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/mutable_data_batch.h" #include "components/sync/model/sync_merge_result.h" @@ -51,6 +53,23 @@ std::string GetSpecificsIdFromAutofillWalletSpecifics( return std::string(); } +std::string GetSpecificsIdFromAutofillProfile(const AutofillProfile& profile) { + // Both server_id and specifics_id are _not_ base64 encoded. + return profile.server_id(); +} + +std::string GetSpecificsIdFromCreditCard(const CreditCard& card) { + // Both server_id and specifics_id are _not_ base64 encoded. + return card.server_id(); +} + +std::string GetSpecificsIdFromPaymentsCustomerData( + const PaymentsCustomerData& customer_data) { + // Both customer_id and specifics_id are _not_ base64 encoded. + return customer_data.customer_id; +} + +// Returns the client tag for wallet data specifics id. std::string GetClientTagForWalletDataSpecificsId( const std::string& specifics_id) { // Unlike for the wallet_metadata model type, the wallet_data expects @@ -58,6 +77,64 @@ std::string GetClientTagForWalletDataSpecificsId( return specifics_id; } +// Returns the storage key to be used for wallet data for the specified wallet +// data |specifics_id|. +std::string GetStorageKeyForWalletDataSpecificsId( + const std::string& specifics_id) { + // We use the (non-base64-encoded) |specifics_id| directly as the storage key, + // this function only hides this definition from all its call sites. + return specifics_id; +} + +// Creates a EntityData object corresponding to the specified |address|. +std::unique_ptr<EntityData> CreateEntityDataFromAutofillServerProfile( + const AutofillProfile& address, + bool enforce_utf8) { + auto entity_data = std::make_unique<EntityData>(); + entity_data->non_unique_name = + "Server profile " + + GetBase64EncodedId(GetSpecificsIdFromAutofillProfile(address)); + + AutofillWalletSpecifics* wallet_specifics = + entity_data->specifics.mutable_autofill_wallet(); + SetAutofillWalletSpecificsFromServerProfile(address, wallet_specifics, + enforce_utf8); + + return entity_data; +} + +// Creates a EntityData object corresponding to the specified |card|. +std::unique_ptr<EntityData> CreateEntityDataFromCard(const CreditCard& card, + bool enforce_utf8) { + auto entity_data = std::make_unique<EntityData>(); + entity_data->non_unique_name = + "Server card " + GetBase64EncodedId(GetSpecificsIdFromCreditCard(card)); + + AutofillWalletSpecifics* wallet_specifics = + entity_data->specifics.mutable_autofill_wallet(); + SetAutofillWalletSpecificsFromServerCard(card, wallet_specifics, + enforce_utf8); + + return entity_data; +} + +// Creates a EntityData object corresponding to the specified |customer_data|. +std::unique_ptr<EntityData> CreateEntityDataFromPaymentsCustomerData( + const PaymentsCustomerData& customer_data) { + auto entity_data = std::make_unique<EntityData>(); + entity_data->non_unique_name = + "Payments customer data " + + GetBase64EncodedId(GetSpecificsIdFromPaymentsCustomerData(customer_data)); + + AutofillWalletSpecifics* wallet_specifics = + entity_data->specifics.mutable_autofill_wallet(); + + SetAutofillWalletSpecificsFromPaymentsCustomerData(customer_data, + wallet_specifics); + + return entity_data; +} + } // namespace // static @@ -111,6 +188,15 @@ AutofillWalletSyncBridge::CreateMetadataChangeList() { base::Optional<syncer::ModelError> AutofillWalletSyncBridge::MergeSyncData( std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, syncer::EntityChangeList entity_data) { + // All metadata changes have been already written, return early for an error. + base::Optional<syncer::ModelError> error = + static_cast<syncer::SyncMetadataStoreChangeList*>( + metadata_change_list.get()) + ->TakeError(); + if (error) { + return error; + } + SetSyncData(entity_data); // After the first sync, we are sure that initial sync is done. @@ -118,6 +204,8 @@ base::Optional<syncer::ModelError> AutofillWalletSyncBridge::MergeSyncData( initial_sync_done_ = true; active_callback_.Run(true); } + // TODO(crbug.com/853688): Update the AutofillTable API to know about write + // errors and report them here. return base::nullopt; } @@ -137,54 +225,7 @@ void AutofillWalletSyncBridge::GetData(StorageKeyList storage_keys, } void AutofillWalletSyncBridge::GetAllDataForDebugging(DataCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<std::unique_ptr<AutofillProfile>> profiles; - std::vector<std::unique_ptr<CreditCard>> cards; - std::unique_ptr<PaymentsCustomerData> customer_data; - if (!GetAutofillTable()->GetServerProfiles(&profiles) || - !GetAutofillTable()->GetServerCreditCards(&cards) || - !GetAutofillTable()->GetPaymentsCustomerData(&customer_data)) { - change_processor()->ReportError( - {FROM_HERE, "Failed to load entries from table."}); - return; - } - - // Convert all non base 64 strings so that they can be displayed properly. - auto batch = std::make_unique<syncer::MutableDataBatch>(); - for (const std::unique_ptr<AutofillProfile>& entry : profiles) { - std::unique_ptr<EntityData> entity_data = - CreateEntityDataFromAutofillServerProfile(*entry); - sync_pb::WalletPostalAddress* wallet_address = - entity_data->specifics.mutable_autofill_wallet()->mutable_address(); - - wallet_address->set_id(GetBase64EncodedServerId(wallet_address->id())); - - batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), - std::move(entity_data)); - } - for (const std::unique_ptr<CreditCard>& entry : cards) { - std::unique_ptr<EntityData> entity_data = CreateEntityDataFromCard(*entry); - sync_pb::WalletMaskedCreditCard* wallet_card = - entity_data->specifics.mutable_autofill_wallet()->mutable_masked_card(); - - wallet_card->set_id(GetBase64EncodedServerId(wallet_card->id())); - // The billing address id might refer to a local profile guid which doesn't - // need to be encoded. - if (!base::IsStringUTF8(wallet_card->billing_address_id())) { - wallet_card->set_billing_address_id( - GetBase64EncodedServerId(wallet_card->billing_address_id())); - } - - batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), - std::move(entity_data)); - } - - if (customer_data) { - batch->Put(GetStorageKeyForEntryServerId(customer_data->customer_id), - CreateEntityDataFromPaymentsCustomerData(*customer_data)); - } - std::move(callback).Run(std::move(batch)); + GetAllDataImpl(std::move(callback), /*enforce_utf8=*/true); } std::string AutofillWalletSyncBridge::GetClientTag( @@ -199,8 +240,9 @@ std::string AutofillWalletSyncBridge::GetClientTag( std::string AutofillWalletSyncBridge::GetStorageKey( const syncer::EntityData& entity_data) { DCHECK(entity_data.specifics.has_autofill_wallet()); - return GetStorageKeyForSpecificsId(GetSpecificsIdFromAutofillWalletSpecifics( - entity_data.specifics.autofill_wallet())); + return GetStorageKeyForWalletDataSpecificsId( + GetSpecificsIdFromAutofillWalletSpecifics( + entity_data.specifics.autofill_wallet())); } bool AutofillWalletSyncBridge::SupportsIncrementalUpdates() const { @@ -228,6 +270,11 @@ AutofillWalletSyncBridge::ApplyStopSyncChanges( } void AutofillWalletSyncBridge::GetAllDataForTesting(DataCallback callback) { + GetAllDataImpl(std::move(callback), /*enforce_utf8=*/false); +} + +void AutofillWalletSyncBridge::GetAllDataImpl(DataCallback callback, + bool enforce_utf8) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::vector<std::unique_ptr<AutofillProfile>> profiles; @@ -243,16 +290,19 @@ void AutofillWalletSyncBridge::GetAllDataForTesting(DataCallback callback) { auto batch = std::make_unique<syncer::MutableDataBatch>(); for (const std::unique_ptr<AutofillProfile>& entry : profiles) { - batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), - CreateEntityDataFromAutofillServerProfile(*entry)); + batch->Put(GetStorageKeyForWalletDataSpecificsId( + GetSpecificsIdFromAutofillProfile(*entry)), + CreateEntityDataFromAutofillServerProfile(*entry, enforce_utf8)); } for (const std::unique_ptr<CreditCard>& entry : cards) { - batch->Put(GetStorageKeyForEntryServerId(entry->server_id()), - CreateEntityDataFromCard(*entry)); + batch->Put(GetStorageKeyForWalletDataSpecificsId( + GetSpecificsIdFromCreditCard(*entry)), + CreateEntityDataFromCard(*entry, enforce_utf8)); } if (customer_data) { - batch->Put(GetStorageKeyForEntryServerId(customer_data->customer_id), + batch->Put(GetStorageKeyForWalletDataSpecificsId( + GetSpecificsIdFromPaymentsCustomerData(*customer_data)), CreateEntityDataFromPaymentsCustomerData(*customer_data)); } std::move(callback).Run(std::move(batch)); @@ -301,15 +351,20 @@ bool AutofillWalletSyncBridge::SetWalletCards( ComputeAutofillWalletDiff(existing_cards, wallet_cards); if (log_diff) { - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards.Added", diff.items_added); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards.Removed", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards2.Added", diff.items_added); + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards2.Removed", diff.items_removed); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards.AddedOrRemoved", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards2.AddedOrRemoved", diff.items_added + diff.items_removed); } if (!diff.IsEmpty()) { - table->SetServerCreditCards(wallet_cards); + if (base::FeatureList::IsEnabled( + ::switches::kSyncUSSAutofillWalletMetadata)) { + table->SetServerCardsData(wallet_cards); + } else { + table->SetServerCreditCards(wallet_cards); + } for (const CreditCardChange& change : diff.changes) web_data_backend_->NotifyOfCreditCardChanged(change); return true; @@ -331,16 +386,21 @@ bool AutofillWalletSyncBridge::SetWalletAddresses( ComputeAutofillWalletDiff(existing_addresses, wallet_addresses); if (log_diff) { - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses.Added", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses2.Added", diff.items_added); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses.Removed", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses2.Removed", diff.items_removed); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses.AddedOrRemoved", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses2.AddedOrRemoved", diff.items_added + diff.items_removed); } if (!diff.IsEmpty()) { - table->SetServerProfiles(wallet_addresses); + if (base::FeatureList::IsEnabled( + ::switches::kSyncUSSAutofillWalletMetadata)) { + table->SetServerAddressesData(wallet_addresses); + } else { + table->SetServerProfiles(wallet_addresses); + } for (const AutofillProfileChange& change : diff.changes) web_data_backend_->NotifyOfAutofillProfileChanged(change); return true; @@ -427,7 +487,7 @@ AutofillWalletSyncBridge::ComputeAutofillWalletDiff( if (cmp < 0) { ++result.items_removed; result.changes.emplace_back(AutofillDataModelChange<Item>::REMOVE, - (*old_it)->guid(), nullptr); + (*old_it)->server_id(), nullptr); ++old_it; } else if (cmp == 0) { ++old_it; @@ -435,7 +495,7 @@ AutofillWalletSyncBridge::ComputeAutofillWalletDiff( } else { ++result.items_added; result.changes.emplace_back(AutofillDataModelChange<Item>::ADD, - (*new_it)->guid(), *new_it); + (*new_it)->server_id(), *new_it); ++new_it; } } diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h index 46d91c27fef..17ea21c91bb 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h @@ -71,7 +71,7 @@ class AutofillWalletSyncBridge : public base::SupportsUserData::Data, override; // Sends all Wallet Data to the |callback| and keeps all the strings in their - // original format. + // original format (whereas GetAllDataForDebugging() has to make them UTF-8). void GetAllDataForTesting(DataCallback callback); private: @@ -84,6 +84,10 @@ class AutofillWalletSyncBridge : public base::SupportsUserData::Data, bool IsEmpty() const { return items_added == 0 && items_removed == 0; } }; + // Sends all Wallet Data to the |callback|. If |enforce_utf8|, the string + // fields that are in non-UTF-8 get encoded so that they conform to UTF-8. + void GetAllDataImpl(DataCallback callback, bool enforce_utf8); + // Sets the wallet data from |entity_data| to this client and records metrics // about added/deleted data. void SetSyncData(const syncer::EntityChangeList& entity_data); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc index 84edb01afb9..97c9520760b 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc @@ -12,12 +12,14 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/test/bind_test_util.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/time/time.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/country_names.h" @@ -31,6 +33,7 @@ #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/sync/base/hash_util.h" +#include "components/sync/driver/sync_driver_switches.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/mock_model_type_change_processor.h" #include "components/sync/model/sync_data.h" @@ -187,9 +190,33 @@ MATCHER_P2(AddChange, key, data, "") { return true; } +// Class that enables or disables USS based on test parameter. Must be the first +// base class of the test fixture. +// TODO(jkrcal): When the new implementation fully launches, remove this class, +// convert all tests from *_P back to *_F and remove the instance at the end. +class UssSwitchToggler : public testing::WithParamInterface<bool> { + public: + UssSwitchToggler() { + if (IsWalletMetadataOnUSS()) { + override_features_.InitAndEnableFeature( + ::switches::kSyncUSSAutofillWalletMetadata); + } else { + override_features_.InitAndDisableFeature( + ::switches::kSyncUSSAutofillWalletMetadata); + } + } + + protected: + bool IsWalletMetadataOnUSS() { return GetParam(); } + + private: + base::test::ScopedFeatureList override_features_; +}; + } // namespace -class AutofillWalletSyncBridgeTest : public testing::Test { +class AutofillWalletSyncBridgeTest : public UssSwitchToggler, + public testing::Test { public: AutofillWalletSyncBridgeTest() {} ~AutofillWalletSyncBridgeTest() override {} @@ -253,44 +280,55 @@ class AutofillWalletSyncBridgeTest : public testing::Test { } void ExpectAddressesDiffInHistograms(int added, int removed) { - histogram_tester_.ExpectUniqueSample("Autofill.WalletAddresses.Added", + histogram_tester_.ExpectUniqueSample("Autofill.WalletAddresses2.Added", /*bucket=*/added, /*count=*/1); - histogram_tester_.ExpectUniqueSample("Autofill.WalletAddresses.Removed", + histogram_tester_.ExpectUniqueSample("Autofill.WalletAddresses2.Removed", /*bucket=*/removed, /*count=*/1); histogram_tester_.ExpectUniqueSample( - "Autofill.WalletAddresses.AddedOrRemoved", + "Autofill.WalletAddresses2.AddedOrRemoved", /*bucket=*/added + removed, /*count=*/1); } void ExpectNoHistogramsForAddressesDiff() { - histogram_tester_.ExpectTotalCount("Autofill.WalletAddresses.Added", 0); - histogram_tester_.ExpectTotalCount("Autofill.WalletAddresses.Removed", 0); + histogram_tester_.ExpectTotalCount("Autofill.WalletAddresses2.Added", 0); + histogram_tester_.ExpectTotalCount("Autofill.WalletAddresses2.Removed", 0); histogram_tester_.ExpectTotalCount( - "Autofill.WalletAddresses.AddedOrRemoved", 0); + "Autofill.WalletAddresses2.AddedOrRemoved", 0); } void ExpectCardsDiffInHistograms(int added, int removed) { - histogram_tester_.ExpectUniqueSample("Autofill.WalletCards.Added", + histogram_tester_.ExpectUniqueSample("Autofill.WalletCards2.Added", /*bucket=*/added, /*count=*/1); - histogram_tester_.ExpectUniqueSample("Autofill.WalletCards.Removed", + histogram_tester_.ExpectUniqueSample("Autofill.WalletCards2.Removed", /*bucket=*/removed, /*count=*/1); - histogram_tester_.ExpectUniqueSample("Autofill.WalletCards.AddedOrRemoved", + histogram_tester_.ExpectUniqueSample("Autofill.WalletCards2.AddedOrRemoved", /*bucket=*/added + removed, /*count=*/1); } void ExpectNoHistogramsForCardsDiff() { - histogram_tester_.ExpectTotalCount("Autofill.WalletCards.Added", 0); - histogram_tester_.ExpectTotalCount("Autofill.WalletCards.Removed", 0); - histogram_tester_.ExpectTotalCount("Autofill.WalletCards.AddedOrRemoved", + histogram_tester_.ExpectTotalCount("Autofill.WalletCards2.Added", 0); + histogram_tester_.ExpectTotalCount("Autofill.WalletCards2.Removed", 0); + histogram_tester_.ExpectTotalCount("Autofill.WalletCards2.AddedOrRemoved", 0); } + void ExpectCountsOfWalletMetadataInDB(unsigned int cards_count, + unsigned int addresses_count) { + std::map<std::string, AutofillMetadata> cards_metadata; + ASSERT_TRUE(table()->GetServerCardsMetadata(&cards_metadata)); + EXPECT_EQ(cards_count, cards_metadata.size()); + + std::map<std::string, AutofillMetadata> addresses_metadata; + ASSERT_TRUE(table()->GetServerAddressesMetadata(&addresses_metadata)); + EXPECT_EQ(addresses_count, addresses_metadata.size()); + } + EntityData SpecificsToEntity(const AutofillWalletSpecifics& specifics) { EntityData data; *data.specifics.mutable_autofill_wallet() = specifics; @@ -351,21 +389,21 @@ class AutofillWalletSyncBridgeTest : public testing::Test { }; // The following 3 tests make sure client tags stay stable. -TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForAddress) { +TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForAddress) { AutofillWalletSpecifics specifics = CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId); EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), kAddr1SyncTag); } -TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCard) { +TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCard) { AutofillWalletSpecifics specifics = CreateAutofillWalletSpecificsForCard(kCard1SpecificsId); EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), kCard1SyncTag); } -TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) { +TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) { AutofillWalletSpecifics specifics = CreateAutofillWalletSpecificsForPaymentsCustomerData( kCustomerDataSyncTag); @@ -374,28 +412,28 @@ TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) { } // The following 3 tests make sure storage keys stay stable. -TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) { +TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) { AutofillWalletSpecifics specifics1 = CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId); EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics1)), kAddr1SpecificsId); } -TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) { +TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) { AutofillWalletSpecifics specifics2 = CreateAutofillWalletSpecificsForCard(kCard1SpecificsId); EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics2)), kCard1SpecificsId); } -TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) { +TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) { AutofillWalletSpecifics specifics3 = CreateAutofillWalletSpecificsForPaymentsCustomerData(kCustomerDataId); EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics3)), kCustomerDataId); } -TEST_F(AutofillWalletSyncBridgeTest, +TEST_P(AutofillWalletSyncBridgeTest, GetAllDataForDebugging_ShouldReturnAllData) { AutofillProfile address1 = test::GetServerProfile(); AutofillProfile address2 = test::GetServerProfile2(); @@ -428,7 +466,7 @@ TEST_F(AutofillWalletSyncBridgeTest, // Tests that when a new wallet card and new wallet address are sent by the // server, the client only keeps the new data. -TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) { +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) { // Create one profile and one card on the client. AutofillProfile address1 = test::GetServerProfile(); table()->SetServerProfiles({address1}); @@ -450,15 +488,22 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) { EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged( - AddChange(address2.guid(), address2))); - EXPECT_CALL(*backend(), - NotifyOfAutofillProfileChanged(RemoveChange(address1.guid()))); + AddChange(address2.server_id(), address2))); + EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged( + RemoveChange(address1.server_id()))); EXPECT_CALL(*backend(), - NotifyOfCreditCardChanged(AddChange(card2.guid(), card2))); + NotifyOfCreditCardChanged(AddChange(card2.server_id(), card2))); EXPECT_CALL(*backend(), - NotifyOfCreditCardChanged(RemoveChange(card1.guid()))); + NotifyOfCreditCardChanged(RemoveChange(card1.server_id()))); StartSyncing({profile_specifics2, card_specifics2, customer_data_specifics}); + if (IsWalletMetadataOnUSS()) { + // This bridge does not store metadata, i.e. billing_address_id. Strip it + // off so that the expectations below pass. + card_specifics2.mutable_masked_card()->set_billing_address_id( + std::string()); + } + // Only the server card should be present on the client. EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(EqualsSpecifics(profile_specifics2), @@ -470,7 +515,7 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) { // Tests that in initial sync, no metrics are recorded for new addresses and // cards. -TEST_F(AutofillWalletSyncBridgeTest, +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCardNoMetricsInitialSync) { ResetProcessor(); ResetBridge(/*initial_sync_done=*/false); @@ -490,6 +535,14 @@ TEST_F(AutofillWalletSyncBridgeTest, EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); StartSyncing({profile_specifics, card_specifics, customer_data_specifics}); + if (IsWalletMetadataOnUSS()) { + ExpectCountsOfWalletMetadataInDB(/*cards_count=*/0u, /*address_count=*/0u); + + // This bridge does not store metadata, i.e. billing_address_id. Strip it + // off so that the expectations below pass. + card_specifics.mutable_masked_card()->set_billing_address_id(std::string()); + } + EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(EqualsSpecifics(profile_specifics), EqualsSpecifics(card_specifics), @@ -500,7 +553,7 @@ TEST_F(AutofillWalletSyncBridgeTest, // Tests that when a new payments customer data is sent by the server, the // client only keeps the new data. -TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewPaymentsCustomerData) { +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NewPaymentsCustomerData) { // Create one profile, one card and one customer data entry on the client. AutofillProfile address = test::GetServerProfile(); table()->SetServerProfiles({address}); @@ -535,7 +588,7 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewPaymentsCustomerData) { // Tests that when the server sends no cards or address, the client should // delete all it's existing data. -TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) { +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) { // Create one profile and one card on the client. AutofillProfile local_profile = test::GetServerProfile(); table()->SetServerProfiles({local_profile}); @@ -544,11 +597,17 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) { EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged( - RemoveChange(local_profile.guid()))); + RemoveChange(local_profile.server_id()))); EXPECT_CALL(*backend(), - NotifyOfCreditCardChanged(RemoveChange(local_card.guid()))); + NotifyOfCreditCardChanged(RemoveChange(local_card.server_id()))); StartSyncing({}); + if (IsWalletMetadataOnUSS()) { + // This bridge should not touch the metadata; should get deleted by the + // metadata bridge. + ExpectCountsOfWalletMetadataInDB(/*cards_count=*/1u, /*address_count=*/1u); + } + EXPECT_TRUE(GetAllLocalData().empty()); // No diff metrics reported when new data is empty. ExpectNoHistogramsForAddressesDiff(); @@ -557,7 +616,7 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) { // Test that when the server sends the same address and card as the client has, // nothing changes on the client. -TEST_F(AutofillWalletSyncBridgeTest, +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_SameWalletAddressAndCardAndCustomerData) { // Create one profile and one card on the client. AutofillProfile profile = test::GetServerProfile(); @@ -591,7 +650,7 @@ TEST_F(AutofillWalletSyncBridgeTest, // Tests that when there are multiple changes happening at the same time, the // data from the server is what the client ends up with. -TEST_F(AutofillWalletSyncBridgeTest, +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_AddRemoveAndPreserveWalletAddressAndCard) { // Create two profile and one card on the client. AutofillProfile profile = test::GetServerProfile(); @@ -614,13 +673,21 @@ TEST_F(AutofillWalletSyncBridgeTest, &customer_data_specifics); EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged( + RemoveChange(profile2.server_id()))); EXPECT_CALL(*backend(), - NotifyOfAutofillProfileChanged(RemoveChange(profile2.guid()))); - EXPECT_CALL(*backend(), NotifyOfCreditCardChanged(RemoveChange(card.guid()))); + NotifyOfCreditCardChanged(RemoveChange(card.server_id()))); EXPECT_CALL(*backend(), - NotifyOfCreditCardChanged(AddChange(card2.guid(), card2))); + NotifyOfCreditCardChanged(AddChange(card2.server_id(), card2))); StartSyncing({profile_specifics, card2_specifics, customer_data_specifics}); + if (IsWalletMetadataOnUSS()) { + // This bridge does not store metadata, i.e. billing_address_id. Strip it + // off so that the expectations below pass. + card2_specifics.mutable_masked_card()->set_billing_address_id( + std::string()); + } + // Make sure that the client only has the data from the server. EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(EqualsSpecifics(profile_specifics), @@ -632,7 +699,7 @@ TEST_F(AutofillWalletSyncBridgeTest, // Test that all field values for a address sent form the server are copied on // the address on the client. -TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) { +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) { // Create a profile to be synced from the server. AutofillProfile profile = test::GetServerProfile(); AutofillWalletSpecifics profile_specifics; @@ -686,7 +753,7 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) { // Test that all field values for a card sent form the server are copied on the // card on the client. -TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) { +TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) { // Create a card to be synced from the server. CreditCard card = test::GetMaskedServerCard(); // Add this value type as it is not added by default but should be synced. @@ -696,6 +763,13 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) { StartSyncing({card_specifics}); + if (IsWalletMetadataOnUSS()) { + // This bridge does not store metadata, i.e. billing_address_id. Strip it + // off so that the expectations below pass. + card.set_billing_address_id(std::string()); + card_specifics.mutable_masked_card()->set_billing_address_id(std::string()); + } + EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(EqualsSpecifics(card_specifics))); @@ -718,12 +792,14 @@ TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) { EXPECT_FALSE(card.LastFourDigits().empty()); EXPECT_NE(0, card.expiration_month()); EXPECT_NE(0, card.expiration_year()); - EXPECT_FALSE(card.billing_address_id().empty()); + if (!IsWalletMetadataOnUSS()) { + EXPECT_FALSE(card.billing_address_id().empty()); + } EXPECT_NE(CreditCard::CARD_TYPE_UNKNOWN, card.card_type()); EXPECT_FALSE(card.bank_name().empty()); } -TEST_F(AutofillWalletSyncBridgeTest, LoadMetadataCalled) { +TEST_P(AutofillWalletSyncBridgeTest, LoadMetadataCalled) { EXPECT_TRUE(table()->UpdateSyncMetadata(syncer::AUTOFILL_WALLET_DATA, "key", EntityMetadata())); @@ -734,7 +810,7 @@ TEST_F(AutofillWalletSyncBridgeTest, LoadMetadataCalled) { ResetBridge(/*initial_sync_done=*/true); } -TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) { +TEST_P(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) { // Create one profile and one card on the client. AutofillProfile local_profile = test::GetServerProfile(); table()->SetServerProfiles({local_profile}); @@ -743,21 +819,27 @@ TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) { EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged( - RemoveChange(local_profile.guid()))); + RemoveChange(local_profile.server_id()))); EXPECT_CALL(*backend(), - NotifyOfCreditCardChanged(RemoveChange(local_card.guid()))); + NotifyOfCreditCardChanged(RemoveChange(local_card.server_id()))); // Passing in a non-null metadata change list indicates to the bridge that // sync is stopping because it was disabled. bridge()->ApplyStopSyncChanges( std::make_unique<syncer::InMemoryMetadataChangeList>()); + if (IsWalletMetadataOnUSS()) { + // This bridge should not touch the metadata; should get deleted by the + // metadata bridge. + ExpectCountsOfWalletMetadataInDB(/*cards_count=*/1u, /*address_count=*/1u); + } + EXPECT_TRUE(GetAllLocalData().empty()); // No diff metrics reported when clearing data. ExpectNoHistogramsForAddressesDiff(); ExpectNoHistogramsForCardsDiff(); } -TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) { +TEST_P(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) { // Create one profile and one card on the client. AutofillProfile local_profile = test::GetServerProfile(); table()->SetServerProfiles({local_profile}); @@ -777,7 +859,7 @@ TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) { ExpectNoHistogramsForCardsDiff(); } -TEST_F(AutofillWalletSyncBridgeTest, NotifiesWhenActivelySyncing) { +TEST_P(AutofillWalletSyncBridgeTest, NotifiesWhenActivelySyncing) { testing::InSequence seq; ResetProcessor(); @@ -802,4 +884,8 @@ TEST_F(AutofillWalletSyncBridgeTest, NotifiesWhenActivelySyncing) { bridge()->ApplyStopSyncChanges(/*delete_metadata_change_list=*/nullptr); } +INSTANTIATE_TEST_CASE_P(USS, + AutofillWalletSyncBridgeTest, + ::testing::Values(false, true)); + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc index 211c6f1517b..3cc21a09948 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc @@ -213,7 +213,8 @@ syncer::SyncMergeResult AutofillWalletSyncableService::MergeDataAndStartSyncing( std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) { DCHECK(thread_checker_.CalledOnValidThread()); sync_processor_ = std::move(sync_processor); - syncer::SyncMergeResult result = SetSyncData(initial_sync_data); + syncer::SyncMergeResult result = + SetSyncData(initial_sync_data, /*is_initial_merge=*/true); if (webdata_backend_) webdata_backend_->NotifyThatSyncHasStarted(type); return result; @@ -239,7 +240,8 @@ syncer::SyncError AutofillWalletSyncableService::ProcessSyncChanges( DCHECK(thread_checker_.CalledOnValidThread()); // Don't bother handling incremental updates. Wallet data changes very rarely // and has few items. Instead, just get all the current data and save it. - SetSyncData(sync_processor_->GetAllSyncData(syncer::AUTOFILL_WALLET_DATA)); + SetSyncData(sync_processor_->GetAllSyncData(syncer::AUTOFILL_WALLET_DATA), + /*is_initial_merge=*/false); return syncer::SyncError(); } @@ -250,8 +252,8 @@ void AutofillWalletSyncableService::CreateForWebDataServiceAndBackend( const std::string& app_locale) { web_data_service->GetDBUserData()->SetUserData( AutofillWalletSyncableServiceUserDataKey(), - base::WrapUnique( - new AutofillWalletSyncableService(webdata_backend, app_locale))); + std::make_unique<AutofillWalletSyncableService>(webdata_backend, + app_locale)); } // static @@ -340,7 +342,8 @@ void AutofillWalletSyncableService::CopyRelevantMetadataFromDisk( } syncer::SyncMergeResult AutofillWalletSyncableService::SetSyncData( - const syncer::SyncDataList& data_list) { + const syncer::SyncDataList& data_list, + bool is_initial_merge) { std::vector<CreditCard> wallet_cards; std::vector<AutofillProfile> wallet_addresses; std::vector<PaymentsCustomerData> customer_data; @@ -402,20 +405,29 @@ syncer::SyncMergeResult AutofillWalletSyncableService::SetSyncData( table->SetPaymentsCustomerData(&customer_data.front()); } + if (is_initial_merge && cards_diff.IsEmpty() && addresses_diff.IsEmpty()) { + // Skip reporting the diff on startup if there is no change. It can happen + // that new updates come into the directory before + // MergeDataAndStartSyncing() gets called; such updates should get reported. + // We cannot distinguish them precisely so we at least report the non-empty + // diffs which _must_ be caused by an update from the server. + should_report_diff = false; + } + if (should_report_diff) { - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards.Added", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards2.Added", cards_diff.items_added); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards.Removed", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards2.Removed", cards_diff.items_removed); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards.AddedOrRemoved", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCards2.AddedOrRemoved", cards_diff.items_added + cards_diff.items_removed); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses.Added", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses2.Added", addresses_diff.items_added); - UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses.Removed", + UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddresses2.Removed", addresses_diff.items_removed); UMA_HISTOGRAM_COUNTS_100( - "Autofill.WalletAddresses.AddedOrRemoved", + "Autofill.WalletAddresses2.AddedOrRemoved", addresses_diff.items_added + addresses_diff.items_removed); } diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h index 256d1a51cd0..e8c130d73ca 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h @@ -29,6 +29,9 @@ class AutofillWalletSyncableService : public base::SupportsUserData::Data, public syncer::SyncableService { public: + AutofillWalletSyncableService(AutofillWebDataBackend* webdata_backend, + const std::string& app_locale); + ~AutofillWalletSyncableService() override; // syncer::SyncableService implementation. @@ -60,11 +63,6 @@ class AutofillWalletSyncableService void InjectStartSyncFlare( const syncer::SyncableService::StartSyncFlare& flare); - protected: - AutofillWalletSyncableService( - AutofillWebDataBackend* webdata_backend, - const std::string& app_locale); - private: FRIEND_TEST_ALL_PREFIXES(AutofillWalletSyncableServiceTest, CopyRelevantMetadataFromDisk_KeepLocalAddresses); @@ -102,7 +100,8 @@ class AutofillWalletSyncableService static Diff ComputeDiff(const std::vector<std::unique_ptr<Item>>& old_data, const std::vector<Item>& new_data); - syncer::SyncMergeResult SetSyncData(const syncer::SyncDataList& data_list); + syncer::SyncMergeResult SetSyncData(const syncer::SyncDataList& data_list, + bool is_initial_merge); // Populates the wallet datatypes from the sync data and uses the sync data to // link the card to its billing address. diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc index 796447f1a02..e69f6834bc4 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc @@ -15,6 +15,7 @@ #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" #include "components/autofill/core/common/form_field_data.h" #include "components/webdata/common/web_database_backend.h" @@ -53,6 +54,11 @@ AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() { DCHECK(!user_data_); // Forgot to call ResetUserData? } +void AutofillWebDataBackendImpl::SetAutofillProfileChangedCallback( + base::RepeatingCallback<void(const AutofillProfileDeepChange&)> change_cb) { + on_autofill_profile_changed_cb_ = std::move(change_cb); +} + WebDatabase* AutofillWebDataBackendImpl::GetDatabase() { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); return web_database_backend_->database(); @@ -60,8 +66,26 @@ WebDatabase* AutofillWebDataBackendImpl::GetDatabase() { void AutofillWebDataBackendImpl::RemoveExpiredFormElements() { web_database_backend_->ExecuteWriteTask( - Bind(&AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl, - this)); + Bind(&AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl, this)); +} + +std::unique_ptr<WDTypedResult> +AutofillWebDataBackendImpl::RemoveExpiredAutocompleteEntries(WebDatabase* db) { + DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + AutofillChangeList changes; + + if (AutofillTable::FromWebDatabase(db)->RemoveExpiredFormElements(&changes)) { + if (!changes.empty()) { + // Post the notifications including the list of affected keys. + // This is sent here so that work resulting from this notification + // will be done on the DB sequence, and not the UI sequence. + for (auto& db_observer : db_observer_list_) + db_observer.AutofillEntriesChanged(changes); + } + } + + return std::make_unique<WDResult<size_t>>(AUTOFILL_CLEANUP_RESULT, + changes.size()); } void AutofillWebDataBackendImpl::NotifyOfAutofillProfileChanged( @@ -142,11 +166,11 @@ AutofillWebDataBackendImpl::GetFormValuesForElementName( int limit, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); - std::vector<base::string16> values; + std::vector<AutofillEntry> entries; AutofillTable::FromWebDatabase(db)->GetFormValuesForElementName( - name, prefix, &values, limit); - return std::unique_ptr<WDTypedResult>( - new WDResult<std::vector<base::string16>>(AUTOFILL_VALUE_RESULT, values)); + name, prefix, &entries, limit); + return std::make_unique<WDResult<std::vector<AutofillEntry>>>( + AUTOFILL_VALUE_RESULT, entries); } WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween( @@ -202,6 +226,13 @@ WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile( for (auto& db_observer : db_observer_list_) db_observer.AutofillProfileChanged(change); + if (!on_autofill_profile_changed_cb_.is_null()) { + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_, + AutofillProfileDeepChange( + AutofillProfileChange::ADD, profile))); + } + return WebDatabase::COMMIT_NEEDED; } @@ -227,6 +258,13 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile( for (auto& db_observer : db_observer_list_) db_observer.AutofillProfileChanged(change); + if (!on_autofill_profile_changed_cb_.is_null()) { + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_, + AutofillProfileDeepChange( + AutofillProfileChange::UPDATE, profile))); + } + return WebDatabase::COMMIT_NEEDED; } @@ -250,6 +288,13 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile( for (auto& db_observer : db_observer_list_) db_observer.AutofillProfileChanged(change); + if (!on_autofill_profile_changed_cb_.is_null()) { + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_, + AutofillProfileDeepChange( + AutofillProfileChange::REMOVE, guid))); + } + return WebDatabase::COMMIT_NEEDED; } @@ -410,12 +455,13 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerCardMetadata( const CreditCard& card, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + DCHECK_NE(CreditCard::LOCAL_CARD, card.record_type()); if (!AutofillTable::FromWebDatabase(db)->UpdateServerCardMetadata(card)) return WebDatabase::COMMIT_NOT_NEEDED; for (auto& db_observer : db_observer_list_) { db_observer.CreditCardChanged( - CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); + CreditCardChange(CreditCardChange::UPDATE, card.server_id(), &card)); } return WebDatabase::COMMIT_NEEDED; @@ -425,6 +471,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata( const AutofillProfile& profile, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + DCHECK_EQ(AutofillProfile::SERVER_PROFILE, profile.record_type()); if (!AutofillTable::FromWebDatabase(db)->UpdateServerAddressMetadata( profile)) { return WebDatabase::COMMIT_NOT_NEEDED; @@ -432,7 +479,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata( for (auto& db_observer : db_observer_list_) { db_observer.AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, profile.guid(), &profile)); + AutofillProfileChange::UPDATE, profile.server_id(), &profile)); } return WebDatabase::COMMIT_NEEDED; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h index 064d7ec2006..9b4a5a2abb6 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h @@ -55,19 +55,27 @@ class AutofillWebDataBackendImpl const base::Closure& on_changed_callback, const base::Callback<void(syncer::ModelType)>& on_sync_started_callback); + void SetAutofillProfileChangedCallback( + base::RepeatingCallback<void(const AutofillProfileDeepChange&)> + change_cb); + // AutofillWebDataBackend implementation. void AddObserver( AutofillWebDataServiceObserverOnDBSequence* observer) override; void RemoveObserver( AutofillWebDataServiceObserverOnDBSequence* observer) override; WebDatabase* GetDatabase() override; - void RemoveExpiredFormElements() override; void NotifyOfAutofillProfileChanged( const AutofillProfileChange& change) override; void NotifyOfCreditCardChanged(const CreditCardChange& change) override; void NotifyOfMultipleAutofillChanges() override; void NotifyThatSyncHasStarted(syncer::ModelType model_type) override; + // TODO(crbug.com/920214): Deprecated, will be removed when + // autocomplete retention policy shipped. Replaced by + // RemoveExpiredAutocompleteEntries. + void RemoveExpiredFormElements() override; + // Returns a SupportsUserData object that may be used to store data accessible // from the DB sequence. Should be called only from the DB sequence, and will // be destroyed on the DB sequence soon after ShutdownOnUISequence() is @@ -88,6 +96,12 @@ class AutofillWebDataBackendImpl int limit, WebDatabase* db); + // Function to remove expired Autocomplete entries, which deletes them from + // the Sqlite table, unlinks them from Sync and cleans up the metadata. + // Returns the number of entries cleaned-up. + std::unique_ptr<WDTypedResult> RemoveExpiredAutocompleteEntries( + WebDatabase* db); + // Removes form elements recorded for Autocomplete from the database. WebDatabase::State RemoveFormElementsAddedBetween( const base::Time& delete_begin, @@ -218,6 +232,9 @@ class AutofillWebDataBackendImpl // by this object. Is created on first call to |GetDBUserData()|. std::unique_ptr<SupportsUserDataAggregatable> user_data_; + // TODO(crbug.com/920214): Deprecated, will be removed when + // autocomplete retention policy shipped. Replaced by + // RemoveExpiredAutocompleteEntries. WebDatabase::State RemoveExpiredFormElementsImpl(WebDatabase* db); base::ObserverList<AutofillWebDataServiceObserverOnDBSequence>::Unchecked @@ -230,6 +247,9 @@ class AutofillWebDataBackendImpl base::Closure on_changed_callback_; base::Callback<void(syncer::ModelType)> on_sync_started_callback_; + base::RepeatingCallback<void(const AutofillProfileDeepChange&)> + on_autofill_profile_changed_cb_; + DISALLOW_COPY_AND_ASSIGN(AutofillWebDataBackendImpl); }; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc index dd40364ed89..ebb033556c9 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc @@ -107,6 +107,11 @@ void AutofillWebDataService::AddAutofillProfile( autofill_backend_, profile)); } +void AutofillWebDataService::SetAutofillProfileChangedCallback( + base::RepeatingCallback<void(const AutofillProfileDeepChange&)> change_cb) { + autofill_backend_->SetAutofillProfileChangedCallback(std::move(change_cb)); +} + void AutofillWebDataService::UpdateAutofillProfile( const AutofillProfile& profile) { wdbs_->ScheduleDBTask(FROM_HERE, @@ -315,6 +320,16 @@ base::SingleThreadTaskRunner* AutofillWebDataService::GetDBTaskRunner() { return db_task_runner_.get(); } +WebDataServiceBase::Handle +AutofillWebDataService::RemoveExpiredAutocompleteEntries( + WebDataServiceConsumer* consumer) { + return wdbs_->ScheduleDBTaskWithResult( + FROM_HERE, + Bind(&AutofillWebDataBackendImpl::RemoveExpiredAutocompleteEntries, + autofill_backend_), + consumer); +} + AutofillWebDataService::~AutofillWebDataService() { } diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h index a1db37c055a..f25b3b0cf35 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h @@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/supports_user_data.h" +#include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_webdata.h" #include "components/autofill/core/common/form_field_data.h" #include "components/sync/base/model_type.h" @@ -83,6 +84,10 @@ class AutofillWebDataService : public AutofillWebData, void UpdateAutofillEntries( const std::vector<AutofillEntry>& autofill_entries) override; + void SetAutofillProfileChangedCallback( + base::RepeatingCallback<void(const AutofillProfileDeepChange&)> + change_cb); + // Credit cards. void AddCreditCard(const CreditCard& credit_card) override; void UpdateCreditCard(const CreditCard& credit_card) override; @@ -137,6 +142,11 @@ class AutofillWebDataService : public AutofillWebData, // sequence. base::SingleThreadTaskRunner* GetDBTaskRunner(); + // Triggers an Autocomplete retention policy run which will cleanup data that + // hasn't been used since over the retention threshold. + virtual WebDataServiceBase::Handle RemoveExpiredAutocompleteEntries( + WebDataServiceConsumer* consumer); + protected: ~AutofillWebDataService() override; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h index 94805a9a999..7477ce7781b 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h @@ -37,6 +37,8 @@ class AutofillWebDataServiceObserverOnUISequence { // Sync. virtual void AutofillMultipleChanged() {} + virtual void AutofillProfileChanged(const AutofillProfileChange& change) {} + // Called on UI sequence when sync has started for |model_type|. virtual void SyncStarted(syncer::ModelType /* model_type */) {} diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc index 97f8650618b..f1d6e76fcc9 100644 --- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc @@ -43,6 +43,7 @@ using base::TimeDelta; using base::WaitableEvent; using testing::_; using testing::DoDefault; +using testing::ElementsAre; using testing::ElementsAreArray; namespace { @@ -106,7 +107,7 @@ class WebDataServiceTest : public testing::Test { base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()}); wdbs_ = new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(), db_task_runner); - wdbs_->AddTable(base::WrapUnique(new AutofillTable)); + wdbs_->AddTable(std::make_unique<AutofillTable>()); wdbs_->LoadDatabase(); wds_ = new AutofillWebDataService( @@ -204,7 +205,7 @@ TEST_F(WebDataServiceAutofillTest, FormFillAdd) { // The event will be signaled when the mock observer is notified. done_event_.TimedWait(test_timeout_); - AutofillWebDataServiceConsumer<std::vector<base::string16>> consumer; + AutofillWebDataServiceConsumer<std::vector<AutofillEntry>> consumer; WebDataServiceBase::Handle handle; static const int limit = 10; handle = wds_->GetFormValuesForElementName( @@ -212,7 +213,7 @@ TEST_F(WebDataServiceAutofillTest, FormFillAdd) { scoped_task_environment_.RunUntilIdle(); EXPECT_EQ(handle, consumer.handle()); ASSERT_EQ(1U, consumer.result().size()); - EXPECT_EQ(value1_, consumer.result()[0]); + EXPECT_EQ(value1_, consumer.result()[0].key().value()); } TEST_F(WebDataServiceAutofillTest, FormFillRemoveOne) { diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn index 8c39eef21f5..0ff74d6c22e 100644 --- a/chromium/components/autofill/core/common/BUILD.gn +++ b/chromium/components/autofill/core/common/BUILD.gn @@ -25,6 +25,7 @@ jumbo_static_library("common") { "autofill_switches.h", "autofill_util.cc", "autofill_util.h", + "button_title_type.h", "filling_status.h", "form_data.cc", "form_data.h", diff --git a/chromium/components/autofill/core/common/OWNERS b/chromium/components/autofill/core/common/OWNERS index c5e2808f24c..1b519b8281f 100644 --- a/chromium/components/autofill/core/common/OWNERS +++ b/chromium/components/autofill/core/common/OWNERS @@ -1,4 +1,3 @@ per-file *password*=dvadym@chromium.org per-file *password*=kolos@chromium.org -per-file *password*=vabr@chromium.org per-file *password*=vasilii@chromium.org diff --git a/chromium/components/autofill/core/common/autofill_constants.cc b/chromium/components/autofill/core/common/autofill_constants.cc index 53a8b465f1b..e1ebeb1822d 100644 --- a/chromium/components/autofill/core/common/autofill_constants.cc +++ b/chromium/components/autofill/core/common/autofill_constants.cc @@ -9,13 +9,6 @@ namespace autofill { -const char kHelpURL[] = -#if defined(OS_CHROMEOS) - "https://support.google.com/chromebook/?p=settings_autofill"; -#else - "https://support.google.com/chrome/?p=settings_autofill"; -#endif - const char kSettingsOrigin[] = "Chrome settings"; size_t MinRequiredFieldsForHeuristics() { diff --git a/chromium/components/autofill/core/common/autofill_constants.h b/chromium/components/autofill/core/common/autofill_constants.h index 2ab64b61059..f5c341618aa 100644 --- a/chromium/components/autofill/core/common/autofill_constants.h +++ b/chromium/components/autofill/core/common/autofill_constants.h @@ -7,12 +7,11 @@ #ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_CONSTANTS_H_ #define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_CONSTANTS_H_ -#include <stddef.h> // For size_t +#include <stddef.h> // For size_t -namespace autofill { +#include "base/time/time.h" -// Help URL for the Autofill dialog. -extern const char kHelpURL[]; +namespace autofill { // The origin of an AutofillDataModel created or modified in the settings page. extern const char kSettingsOrigin[]; @@ -45,6 +44,16 @@ enum ShowPasswordSuggestionsOptions { // its own credit card save policy. const int kMaxStrikesToPreventPoppingUpOfferToSavePrompt = 3; +// Constants for the soft/hard deletion of Autofill data. +constexpr base::TimeDelta kDisusedDataModelTimeDelta = + base::TimeDelta::FromDays(180); +constexpr base::TimeDelta kDisusedDataModelDeletionTimeDelta = + base::TimeDelta::FromDays(395); + +// The period after which autocomplete entries should be cleaned-up in days. +// Equivalent to roughly 14 months. +const int64_t kAutocompleteRetentionPolicyPeriodInDays = 14 * 31; + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_CONSTANTS_H_ diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc index ac8f821927a..fbe039a1880 100644 --- a/chromium/components/autofill/core/common/autofill_features.cc +++ b/chromium/components/autofill/core/common/autofill_features.cc @@ -16,11 +16,14 @@ #include "components/autofill/core/common/autofill_switches.h" #include "components/prefs/pref_service.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/ui_base_features.h" namespace autofill { namespace features { +// Controls whether the Autocomplete Retention Policy is being enforced or not. +const base::Feature kAutocompleteRetentionPolicyEnabled{ + "AutocompleteRetentionPolicyEnabled", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether autofill activates on non-HTTP(S) pages. Useful for // automated with data URLS in cases where it's too difficult to use the // embedded test server. Generally avoid using. @@ -113,22 +116,25 @@ const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics{ // crowd-sourced field type predictions are queried for a form. const base::Feature kAutofillEnforceMinRequiredFieldsForQuery{ "AutofillEnforceMinRequiredFieldsForQuery", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Controls whether or not a minimum number of fields is required before // field type votes are uploaded to the crowd-sourcing server. const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{ "AutofillEnforceMinRequiredFieldsForUpload", - base::FEATURE_ENABLED_BY_DEFAULT}; - -const base::Feature kAutofillExpandedPopupViews{ - "AutofillExpandedPopupViews", base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // When enabled, gets payment identity from sync service instead of // identity manager. const base::Feature kAutofillGetPaymentsIdentityFromSync{ "AutofillGetPaymentsIdentityFromSync", base::FEATURE_DISABLED_BY_DEFAULT}; +// When enabled, a credit card form that is hidden after receiving input can +// import the card. +const base::Feature kAutofillImportNonFocusableCreditCardForms{ + "AutofillImportNonFocusableCreditCardForms", + base::FEATURE_DISABLED_BY_DEFAULT}; + // When enabled, autofill suggestions are displayed in the keyboard accessory // instead of the regular popup. const base::Feature kAutofillKeyboardAccessory{ @@ -160,16 +166,6 @@ const base::Feature kAutofillPreferServerNamePredictions{ const base::Feature kAutofillPrefilledFields{"AutofillPrefilledFields", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillRationalizeFieldTypePredictions{ - "AutofillRationalizeFieldTypePredictions", - base::FEATURE_ENABLED_BY_DEFAULT}; - -// Controls whether Autofill should rationalize repeated server type -// predictions. -const base::Feature kAutofillRationalizeRepeatedServerPredictions{ - "AutofillRationalizeRepeatedServerPredictions", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Controls whether or not a group of fields not enclosed in a form can be // considered a form. If this is enabled, unowned fields will only constitute // a form if there are signals to suggest that this might a checkout page. @@ -200,7 +196,7 @@ const base::Feature kAutofillSaveCardImprovedUserConsent{ // When enabled, a sign in promo will show up right after the user // saves a card locally. This also introduces a "Manage Cards" bubble. const base::Feature kAutofillSaveCardSignInAfterLocalSave{ - "AutofillSaveCardSignInAfterLocalSave", base::FEATURE_DISABLED_BY_DEFAULT}; + "AutofillSaveCardSignInAfterLocalSave", base::FEATURE_ENABLED_BY_DEFAULT}; // Controls whether offering to save cards will consider data from the Autofill // strike database. @@ -208,6 +204,12 @@ const base::Feature kAutofillSaveCreditCardUsesStrikeSystem{ "AutofillSaveCreditCardUsesStrikeSystem", base::FEATURE_DISABLED_BY_DEFAULT}; +// Controls whether offering to save cards will consider data from the Autofill +// strike database (new version). +const base::Feature kAutofillSaveCreditCardUsesStrikeSystemV2{ + "AutofillSaveCreditCardUsesStrikeSystemV2", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether experiment ids should be sent through // Google Payments RPCs or not. const base::Feature kAutofillSendExperimentIdsInPaymentsRPCs{ @@ -230,6 +232,11 @@ const base::Feature kAutofillSendOnlyCountryInGetUploadDetails{ const base::Feature kAutofillServerCommunication{ "AutofillServerCommunication", base::FEATURE_ENABLED_BY_DEFAULT}; +// Controls whether the payments settings page should list the credit cards +// split by type: Local of from Account. +const base::Feature kAutofillSettingsCardTypeSplit{ + "AutofillSettingsCardTypeSplit", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether autofill suggestions are filtered by field values previously // filled by website. const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms{ @@ -258,6 +265,9 @@ const base::Feature kAutofillSuggestInvalidProfileData{ const base::Feature kAutofillSuppressDisusedAddresses{ "AutofillSuppressDisusedAddresses", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillProfileClientValidation{ + "AutofillProfileClientValidation", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kAutofillSuppressDisusedCreditCards{ "AutofillSuppressDisusedCreditCards", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -294,15 +304,9 @@ const base::Feature kAutofillUpstreamEditableExpirationDate{ "AutofillUpstreamEditableExpirationDate", base::FEATURE_DISABLED_BY_DEFAULT}; -// Controls whether the credit card upload bubble shows the Google Pay logo and -// a shorter "Save card?" header message on mobile. -const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile{ - "AutofillUpstreamUseGooglePayOnAndroidBranding", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Controls whether to use the API or use the legacy server. -extern const base::Feature kAutofillUseApi{"AutofillUseApi", - base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillUseApi{"AutofillUseApi", + base::FEATURE_DISABLED_BY_DEFAULT}; // Controls whether the PaymentsCustomerData is used to make requests to // Google Payments. @@ -319,10 +323,6 @@ const base::Feature kAutomaticPasswordGeneration = { "AutomaticPasswordGeneration", base::FEATURE_ENABLED_BY_DEFAULT}; #endif -// Controls whether or not the autofill UI triggers on a single click. -const base::Feature kSingleClickAutofill{"SingleClickAutofill", - base::FEATURE_ENABLED_BY_DEFAULT}; - const char kAutofillCreditCardLocalCardMigrationParameterName[] = "variant"; const char kAutofillCreditCardLocalCardMigrationParameterWithoutSettingsPage[] = @@ -386,15 +386,6 @@ bool IsAutofillManualFallbackEnabled() { return base::FeatureList::IsEnabled(kAutofillManualFallbackPhaseTwo); } -bool ShouldUseNativeViews() { -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) - return base::FeatureList::IsEnabled(kAutofillExpandedPopupViews) || - base::FeatureList::IsEnabled(::features::kExperimentalUi); -#else - return false; -#endif -} - bool IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled() { return base::FeatureList::IsEnabled( kAutofillSaveCardDialogUnlabeledExpirationDate); diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h index 4cf32f6c674..01e901d9043 100644 --- a/chromium/components/autofill/core/common/autofill_features.h +++ b/chromium/components/autofill/core/common/autofill_features.h @@ -21,6 +21,7 @@ namespace autofill { namespace features { // All features in alphabetical order. +extern const base::Feature kAutocompleteRetentionPolicyEnabled; extern const base::Feature kAutofillAllowNonHttpActivation; extern const base::Feature kAutofillAddressNormalizer; extern const base::Feature kAutofillAlwaysFillAddresses; @@ -41,8 +42,8 @@ extern const base::Feature kAutofillEnableIFrameSupportOniOS; extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics; extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery; extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload; -extern const base::Feature kAutofillExpandedPopupViews; extern const base::Feature kAutofillGetPaymentsIdentityFromSync; +extern const base::Feature kAutofillImportNonFocusableCreditCardForms; extern const base::Feature kAutofillKeyboardAccessory; extern const base::Feature kAutofillLocalCardMigrationShowFeedback; extern const base::Feature kAutofillManualFallback; @@ -52,18 +53,18 @@ extern const base::Feature kAutofillPreferServerNamePredictions; extern const base::Feature kAutofillNoLocalSaveOnUploadSuccess; extern const base::Feature kAutofillOverrideWithRaterConsensus; extern const base::Feature kAutofillPrefilledFields; -extern const base::Feature kAutofillRationalizeFieldTypePredictions; -extern const base::Feature kAutofillRationalizeRepeatedServerPredictions; extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout; extern const base::Feature kAutofillRichMetadataQueries; extern const base::Feature kAutofillSaveCardDialogUnlabeledExpirationDate; extern const base::Feature kAutofillSaveCardImprovedUserConsent; extern const base::Feature kAutofillSaveCardSignInAfterLocalSave; extern const base::Feature kAutofillSaveCreditCardUsesStrikeSystem; +extern const base::Feature kAutofillSaveCreditCardUsesStrikeSystemV2; extern const base::Feature kAutofillSaveOnProbablySubmitted; extern const base::Feature kAutofillSendExperimentIdsInPaymentsRPCs; extern const base::Feature kAutofillSendOnlyCountryInGetUploadDetails; extern const base::Feature kAutofillServerCommunication; +extern const base::Feature kAutofillSettingsCardTypeSplit; extern const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms; extern const base::Feature kAutofillShowAutocompleteConsoleWarnings; extern const base::Feature kAutofillShowTypePredictions; @@ -82,9 +83,9 @@ extern const base::Feature kAutofillUpstreamEditableCardholderName; extern const base::Feature kAutofillUpstreamEditableExpirationDate; extern const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile; extern const base::Feature kAutofillUseApi; +extern const base::Feature kAutofillProfileClientValidation; extern const base::Feature kAutofillUsePaymentsCustomerData; extern const base::Feature kAutomaticPasswordGeneration; -extern const base::Feature kSingleClickAutofill; extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[]; extern const char kAutofillLocalCardMigrationCloseButtonDelay[]; extern const char kAutofillCreditCardLocalCardMigrationParameterName[]; @@ -150,11 +151,6 @@ bool IsPasswordManualFallbackEnabled(); // enabled. bool IsAutofillManualFallbackEnabled(); -// Returns true if the native Views implementation of the Desktop dropdown -// should be used. This will also be true if the kExperimentalUi flag is true, -// which forces a bunch of forthcoming UI changes on. -bool ShouldUseNativeViews(); - // Returns true if expiration dates on the save card dialog should be // unlabeled, i.e. not preceded by "Exp." bool IsAutofillSaveCardDialogUnlabeledExpirationDateEnabled(); diff --git a/chromium/components/autofill/core/common/autofill_l10n_util.cc b/chromium/components/autofill/core/common/autofill_l10n_util.cc index 9ab031f12fb..f22057abae5 100644 --- a/chromium/components/autofill/core/common/autofill_l10n_util.cc +++ b/chromium/components/autofill/core/common/autofill_l10n_util.cc @@ -31,7 +31,7 @@ std::unique_ptr<icu::Collator> GetCollatorForLocale(const icu::Locale& locale) { << locale_name; // Attempt to load the English locale. - collator = base::WrapUnique( + collator.reset( icu::Collator::createInstance(icu::Locale::getEnglish(), ignored)); if (!collator) { LOG(ERROR) << "Failed to initialize the ICU Collator with the English " diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc index 86ea54e241b..6e37efe25dc 100644 --- a/chromium/components/autofill/core/common/autofill_prefs.cc +++ b/chromium/components/autofill/core/common/autofill_prefs.cc @@ -126,6 +126,11 @@ const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled"; const char kAutofillWalletImportStorageCheckboxState[] = "autofill.wallet_import_storage_checkbox_state"; +// Integer that is set to the last major version where the Autocomplete +// retention policy was run. +const char kAutocompleteLastVersionRetentionPolicy[] = + "autocomplete.retention_policy_last_version"; + void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { // Synced prefs. Used for cross-device choices, e.g., credit card Autofill. registry->RegisterDoublePref( @@ -166,6 +171,8 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); registry->RegisterIntegerPref( prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0); + registry->RegisterIntegerPref(prefs::kAutocompleteLastVersionRetentionPolicy, + 0); registry->RegisterBooleanPref( prefs::kAutofillMigrateLocalCardsCancelledPrompt, false); registry->RegisterBooleanPref(prefs::kAutofillOrphanRowsRemoved, false); diff --git a/chromium/components/autofill/core/common/autofill_prefs.h b/chromium/components/autofill/core/common/autofill_prefs.h index bc4ff4790fe..47bd73a7e0f 100644 --- a/chromium/components/autofill/core/common/autofill_prefs.h +++ b/chromium/components/autofill/core/common/autofill_prefs.h @@ -41,6 +41,7 @@ extern const char kAutofillUploadEvents[]; extern const char kAutofillUploadEventsLastResetTimestamp[]; extern const char kAutofillWalletImportEnabled[]; extern const char kAutofillWalletImportStorageCheckboxState[]; +extern const char kAutocompleteLastVersionRetentionPolicy[]; namespace sync_transport_opt_in { enum Flags { diff --git a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc index 09fd4d7ea05..1a9e4e0558e 100644 --- a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc +++ b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc @@ -6,6 +6,8 @@ #include <memory> +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "components/prefs/pref_service_factory.h" @@ -176,5 +178,25 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_Clear) { ->DictEmpty()); } +// Tests that the account id hash that we generate can be written and read from +// JSON properly. +TEST_F(AutofillPrefsTest, WalletSyncTransportPref_CanBeSetAndReadFromJSON) { + const std::string account1 = "account1"; + + // Set the opt-in for the first account. + SetUserOptedInWalletSyncTransport(pref_service(), account1, true); + EXPECT_FALSE(pref_service() + ->GetDictionary(prefs::kAutofillSyncTransportOptIn) + ->DictEmpty()); + + const base::DictionaryValue* dictionary = + pref_service()->GetDictionary(prefs::kAutofillSyncTransportOptIn); + + std::string output_js; + EXPECT_TRUE(base::JSONWriter::Write(*dictionary, &output_js)); + EXPECT_TRUE(dictionary->Equals( + base::DictionaryValue::From(base::JSONReader::Read(output_js)).get())); +} + } // namespace prefs -} // namespace autofill
\ No newline at end of file +} // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_switches.cc b/chromium/components/autofill/core/common/autofill_switches.cc index c753a2e3dfd..4bb9f632105 100644 --- a/chromium/components/autofill/core/common/autofill_switches.cc +++ b/chromium/components/autofill/core/common/autofill_switches.cc @@ -19,7 +19,7 @@ const char kAutofillServerURL[] = "autofill-server-url"; // The randomized encoding type to use when sending metadata uploads. The // value of the parameter must be one of the valid integer values of the // AutofillRandomizedValue_EncodingType enum. -extern const char kAutofillMetadataUploadEncoding[] = +const char kAutofillMetadataUploadEncoding[] = "autofill-metadata-upload-encoding"; // Force hiding the local save checkbox in the autofill dialog box for getting diff --git a/chromium/components/autofill/core/common/button_title_type.h b/chromium/components/autofill/core/common/button_title_type.h new file mode 100644 index 00000000000..bf3696d5807 --- /dev/null +++ b/chromium/components/autofill/core/common/button_title_type.h @@ -0,0 +1,26 @@ +// Copyright 2017 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_BUTTON_TITLE_TYPE_H_ +#define COMPONENTS_AUTOFILL_CORE_COMMON_BUTTON_TITLE_TYPE_H_ + +namespace autofill { + +// Describes how a form button is implemented in HTML source. Should be +// synced with |ButtonTitleType| in +// components/autofill/core/browser/proto/server.proto. +enum ButtonTitleType { + NONE = 0, + BUTTON_ELEMENT_SUBMIT_TYPE = 1, // <button type='submit'> + BUTTON_ELEMENT_BUTTON_TYPE = 2, // <button type='button'> + INPUT_ELEMENT_SUBMIT_TYPE = 3, // <input type='submit'> + INPUT_ELEMENT_BUTTON_TYPE = 4, // <input type='button'> + HYPERLINK = 5, // e.g. <a class='button'> + DIV = 6, // e.g. <div id='submit'> + SPAN = 7 // e.g. <span name='btn'> +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_COMMON_FORM_SUBMISSION_SOURCE_H_ diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc index f0f11cf33a5..06c2327da2c 100644 --- a/chromium/components/autofill/core/common/form_data.cc +++ b/chromium/components/autofill/core/common/form_data.cc @@ -72,7 +72,7 @@ FormData::FormData() : is_form_tag(true), is_formless_checkout(false) {} FormData::FormData(const FormData& data) : name(data.name), - button_title(data.button_title), + button_titles(data.button_titles), origin(data.origin), action(data.action), main_frame_origin(data.main_frame_origin), diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h index fc2afba536f..66aff9021fe 100644 --- a/chromium/components/autofill/core/common/form_data.h +++ b/chromium/components/autofill/core/common/form_data.h @@ -9,6 +9,7 @@ #include <vector> #include "base/strings/string16.h" +#include "components/autofill/core/common/button_title_type.h" #include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/submission_indicator_event.h" #include "url/gurl.h" @@ -16,6 +17,13 @@ namespace autofill { +// Pair of a button title (e.g. "Register") and its type (e.g. +// INPUT_ELEMENT_SUBMIT_TYPE). +using ButtonTitleInfo = std::pair<base::string16, ButtonTitleType>; + +// List of button titles of a given form. +using ButtonTitleList = std::vector<ButtonTitleInfo>; + // Holds information about a form to be filled and/or submitted. struct FormData { static constexpr uint32_t kNotSetFormRendererId = @@ -56,8 +64,8 @@ struct FormData { // form signatures. // TODO(crbug/896689): remove this and use attributes/unique_id instead. base::string16 name; - // The form submission button's title. - base::string16 button_title; + // Titles of form's buttons. + ButtonTitleList button_titles; // The URL (minus query parameters) containing the form. GURL origin; // The action target of the form. diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc index a720d677b3b..66eae10cc37 100644 --- a/chromium/components/autofill/core/common/password_form.cc +++ b/chromium/components/autofill/core/common/password_form.cc @@ -37,6 +37,8 @@ void PasswordFormToJSON(const PasswordForm& form, target->SetString("username_value", form.username_value); target->SetString("password_element", form.password_element); target->SetString("password_value", form.password_value); + target->SetInteger("password_element_renderer_id", + form.password_element_renderer_id); target->SetString("new_password_element", form.new_password_element); target->SetInteger("password_element_renderer_id", form.password_element_renderer_id); @@ -45,6 +47,8 @@ void PasswordFormToJSON(const PasswordForm& form, form.new_password_marked_by_site); target->SetString("confirmation_password_element", form.confirmation_password_element); + target->SetInteger("confirmation_password_element_renderer_id", + form.confirmation_password_element_renderer_id); target->SetString("other_possible_usernames", ValueElementVectorToString(form.other_possible_usernames)); target->SetString("all_possible_passwords", @@ -71,9 +75,10 @@ void PasswordFormToJSON(const PasswordForm& form, std::ostringstream submission_event_string_stream; submission_event_string_stream << form.submission_event; target->SetString("submission_event", submission_event_string_stream.str()); - target->SetBoolean("only_for_fallback_saving", form.only_for_fallback_saving); + target->SetBoolean("only_for_fallback", form.only_for_fallback); target->SetBoolean("is_gaia_with_skip_save_password_form", form.is_gaia_with_skip_save_password_form); + target->SetBoolean("is_new_password_reliable", form.is_new_password_reliable); } } // namespace @@ -93,7 +98,7 @@ PasswordForm::PasswordForm() is_public_suffix_match(false), is_affiliation_based_match(false), submission_event(SubmissionIndicatorEvent::NONE), - only_for_fallback_saving(false), + only_for_fallback(false), is_gaia_with_skip_save_password_form(false) {} PasswordForm::PasswordForm(const PasswordForm& other) = default; @@ -114,6 +119,12 @@ bool PasswordForm::IsPossibleChangePasswordFormWithoutUsername() const { return IsPossibleChangePasswordForm() && username_element.empty(); } +bool PasswordForm::HasPasswordElement() const { + return has_renderer_ids ? password_element_renderer_id != + FormFieldData::kNotSetFormControlRendererId + : !password_element.empty(); +} + bool PasswordForm::operator==(const PasswordForm& form) const { return scheme == form.scheme && signon_realm == form.signon_realm && origin == form.origin && action == form.action && @@ -130,7 +141,12 @@ bool PasswordForm::operator==(const PasswordForm& form) const { password_element_renderer_id == form.password_element_renderer_id && password_value == form.password_value && new_password_element == form.new_password_element && + confirmation_password_element_renderer_id == + form.confirmation_password_element_renderer_id && new_password_marked_by_site == form.new_password_marked_by_site && + confirmation_password_element == form.confirmation_password_element && + confirmation_password_element_renderer_id == + form.confirmation_password_element_renderer_id && new_password_value == form.new_password_value && preferred == form.preferred && date_created == form.date_created && date_synced == form.date_synced && @@ -151,9 +167,10 @@ bool PasswordForm::operator==(const PasswordForm& form) const { app_display_name == form.app_display_name && app_icon_url == form.app_icon_url && submission_event == form.submission_event && - only_for_fallback_saving == form.only_for_fallback_saving && + only_for_fallback == form.only_for_fallback && is_gaia_with_skip_save_password_form == - form.is_gaia_with_skip_save_password_form; + form.is_gaia_with_skip_save_password_form && + is_new_password_reliable == form.is_new_password_reliable; } bool PasswordForm::operator!=(const PasswordForm& form) const { diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h index f5d70421922..fc55fa533ce 100644 --- a/chromium/components/autofill/core/common/password_form.h +++ b/chromium/components/autofill/core/common/password_form.h @@ -200,10 +200,20 @@ struct PasswordForm { // element corresponding to the new password. Optional, and not persisted. base::string16 new_password_element; + // The renderer id of the new password input element. It is set during the new + // form parsing and not persisted. + uint32_t new_password_element_renderer_id = + FormFieldData::kNotSetFormControlRendererId; + // The confirmation password element. Optional, only set on form parsing, and // not persisted. base::string16 confirmation_password_element; + // The renderer id of the confirmation password input element. It is set + // during the new form parsing and not persisted. + uint32_t confirmation_password_element_renderer_id = + FormFieldData::kNotSetFormControlRendererId; + // The new password. Optional, and not persisted. base::string16 new_password_value; @@ -302,13 +312,19 @@ struct PasswordForm { // out only for submitted forms. SubmissionIndicatorEvent submission_event; - // True iff heuristics declined this form for saving (e.g. only credit card - // fields were found). But this form can be saved only with the fallback. - bool only_for_fallback_saving; + // True iff heuristics declined this form for normal saving or filling (e.g. + // only credit card fields were found). But this form can be saved or filled + // only with the fallback. + bool only_for_fallback; // True iff this is Gaia form which should be skipped on saving. bool is_gaia_with_skip_save_password_form; + // True iff the new password field was found with server hints or autocomplete + // attributes. Only set on form parsing for filling, and not persisted. Used + // as signal for password generation eligibility. + bool is_new_password_reliable = false; + // Return true if we consider this form to be a change password form. // We use only client heuristics, so it could include signup forms. bool IsPossibleChangePasswordForm() const; @@ -318,6 +334,9 @@ struct PasswordForm { // include signup forms. bool IsPossibleChangePasswordFormWithoutUsername() const; + // Returns true if current password element is set. + bool HasPasswordElement() const; + // Equality operators for testing. bool operator==(const PasswordForm& form) const; bool operator!=(const PasswordForm& form) const; diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc index ae72606e31e..42b65b4c889 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.cc +++ b/chromium/components/autofill/core/common/password_form_fill_data.cc @@ -29,22 +29,30 @@ void InitPasswordFormFillData( // |username_field| and |password_field| because they are currently not used // by the password autocomplete code. FormFieldData username_field; - username_field.name = form_on_page.username_element; username_field.value = preferred_match->username_value; - username_field.unique_renderer_id = form_on_page.username_element_renderer_id; - result->username_may_use_prefilled_placeholder = - form_on_page.username_may_use_prefilled_placeholder; FormFieldData password_field; - password_field.name = form_on_page.password_element; password_field.value = preferred_match->password_value; - password_field.unique_renderer_id = form_on_page.password_element_renderer_id; - password_field.form_control_type = "password"; + if (!form_on_page.only_for_fallback) { + // Fill fields identifying information only for non-fallback case. In + // fallback case, a fill popup is shown on clicking on each password + // field so no need in any field identifiers. + username_field.name = form_on_page.username_element; + username_field.unique_renderer_id = + form_on_page.username_element_renderer_id; + result->username_may_use_prefilled_placeholder = + form_on_page.username_may_use_prefilled_placeholder; -// On iOS, use the unique_id field to refer to elements. + password_field.name = form_on_page.password_element; + password_field.unique_renderer_id = + form_on_page.password_element_renderer_id; + password_field.form_control_type = "password"; + + // On iOS, use the unique_id field to refer to elements. #if defined(OS_IOS) - username_field.unique_id = form_on_page.username_element; - password_field.unique_id = form_on_page.password_element; + username_field.unique_id = form_on_page.username_element; + password_field.unique_id = form_on_page.password_element; #endif + } // Fill basic form data. result->form_renderer_id = form_on_page.form_data.unique_renderer_id; @@ -73,12 +81,16 @@ void InitPasswordFormFillData( } } -PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data) { +PasswordFormFillData MaybeClearPasswordValues( + const PasswordFormFillData& data) { // In case when there is a username on a page (for example in a hidden field), // credentials from |additional_logins| could be used for filling on load. So // in case of filling on load nor |password_field| nor |additional_logins| // can't be cleared - if (!data.wait_for_username) + bool is_fallback = + data.has_renderer_ids && data.password_field.unique_renderer_id == + FormFieldData::kNotSetFormControlRendererId; + if (!data.wait_for_username && !is_fallback) return data; PasswordFormFillData result(data); result.password_field.value.clear(); diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h index 5db0c17b244..cbb47f8971a 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.h +++ b/chromium/components/autofill/core/common/password_form_fill_data.h @@ -91,9 +91,9 @@ void InitPasswordFormFillData( bool wait_for_username_before_autofill, PasswordFormFillData* result); -// Renderer needs to have only a password that should be autofilled, all other -// passwords might be safety erased. -PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data); +// If |data.wait_for_username| is set, the renderer does not need to receive +// passwords, yet, and this function clears the password values from |data|. +PasswordFormFillData MaybeClearPasswordValues(const PasswordFormFillData& data); } // namespace autofill diff --git a/chromium/components/autofill/core/common/password_form_generation_data.h b/chromium/components/autofill/core/common/password_form_generation_data.h index f14d2953821..40fb1977be2 100644 --- a/chromium/components/autofill/core/common/password_form_generation_data.h +++ b/chromium/components/autofill/core/common/password_form_generation_data.h @@ -9,7 +9,9 @@ #include "base/optional.h" #include "base/strings/string16.h" +#include "build/build_config.h" #include "components/autofill/core/common/form_field_data.h" +#include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/signatures_util.h" #include "url/gurl.h" @@ -37,6 +39,23 @@ struct PasswordFormGenerationData { base::Optional<FieldSignature> confirmation_field_signature; }; +// Structure used for sending information from browser to renderer about on +// which fields password should be generated. +// TODO(https://crbug.com/866444): Remove old PasswordFormGenerationData and +// rename to PasswordFormGenerationData when the old parser is gone. +struct NewPasswordFormGenerationData { +#if defined(OS_IOS) + base::string16 form_name; + base::string16 new_password_element; + base::string16 confirmation_password_element; +#else + uint32_t new_password_renderer_id = + FormFieldData::kNotSetFormControlRendererId; + uint32_t confirmation_password_renderer_id = + FormFieldData::kNotSetFormControlRendererId; +#endif +}; + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_ diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc index 5c7cb4e96b1..de254813971 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.cc +++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc @@ -82,9 +82,18 @@ void SavePasswordProgressLogger::LogPasswordForm( } log.SetString(GetStringFromID(STRING_NEW_PASSWORD_ELEMENT), ScrubElementID(form.new_password_element)); + if (form.has_renderer_ids) { + log.SetString(GetStringFromID(STRING_NEW_PASSWORD_ELEMENT_RENDERER_ID), + UintToString(form.new_password_element_renderer_id)); + } if (!form.confirmation_password_element.empty()) { log.SetString(GetStringFromID(STRING_CONFIRMATION_PASSWORD_ELEMENT), ScrubElementID(form.confirmation_password_element)); + if (form.has_renderer_ids) { + log.SetString( + GetStringFromID(STRING_CONFIRMATION_PASSWORD_ELEMENT_RENDERER_ID), + UintToString(form.confirmation_password_element_renderer_id)); + } } log.SetBoolean(GetStringFromID(STRING_PASSWORD_GENERATED), form.type == PasswordForm::TYPE_GENERATED); @@ -208,8 +217,13 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Password element renderer id"; case SavePasswordProgressLogger::STRING_NEW_PASSWORD_ELEMENT: return "New password element"; + case SavePasswordProgressLogger::STRING_NEW_PASSWORD_ELEMENT_RENDERER_ID: + return "New password element renderer id"; case SavePasswordProgressLogger::STRING_CONFIRMATION_PASSWORD_ELEMENT: return "Confirmation password element"; + case SavePasswordProgressLogger:: + STRING_CONFIRMATION_PASSWORD_ELEMENT_RENDERER_ID: + return "Confirmation password element renderer id"; case SavePasswordProgressLogger::STRING_PASSWORD_GENERATED: return "Password generated"; case SavePasswordProgressLogger::STRING_TIMES_USED: @@ -291,7 +305,7 @@ std::string SavePasswordProgressLogger::GetStringFromID( case SavePasswordProgressLogger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD: return "PasswordManager::AskUserOrSavePassword"; case SavePasswordProgressLogger::STRING_CAN_PROVISIONAL_MANAGER_SAVE_METHOD: - return "PasswordManager::CanProvisionalManagerSave"; + return "PasswordManager::IsAutomaticSavePromptAvailable"; case SavePasswordProgressLogger::STRING_NO_PROVISIONAL_SAVE_MANAGER: return "No provisional save manager"; case SavePasswordProgressLogger::STRING_NUMBER_OF_VISIBLE_FORMS: @@ -446,6 +460,16 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Form parsing input"; case STRING_FORM_PARSING_OUTPUT: return "Form parsing output"; + case STRING_FAILED_TO_FILL_INTO_IFRAME: + return "Failed to fill: Form is in iframe on a non-PSL-matching security " + "origin"; + case STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT: + return "Failed to fill: No autocompleteable element found"; + case STRING_FAILED_TO_FILL_PREFILLED_USERNAME: + return "Failed to fill: Username field was prefilled, but no credential " + "exists whose username matches the prefilled value"; + case STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME: + return "Failed to fill: No credential matching found"; case SavePasswordProgressLogger::STRING_INVALID: return "INVALID"; // Intentionally no default: clause here -- all IDs need to get covered. diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h index 40775e06328..404e5c2473d 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.h +++ b/chromium/components/autofill/core/common/save_password_progress_logger.h @@ -50,7 +50,9 @@ class SavePasswordProgressLogger { STRING_PASSWORD_ELEMENT, STRING_PASSWORD_ELEMENT_RENDERER_ID, STRING_NEW_PASSWORD_ELEMENT, + STRING_NEW_PASSWORD_ELEMENT_RENDERER_ID, STRING_CONFIRMATION_PASSWORD_ELEMENT, + STRING_CONFIRMATION_PASSWORD_ELEMENT_RENDERER_ID, STRING_PASSWORD_GENERATED, STRING_TIMES_USED, STRING_PSL_MATCH, @@ -166,6 +168,10 @@ class SavePasswordProgressLogger { STRING_IS_FORM_TAG, STRING_FORM_PARSING_INPUT, STRING_FORM_PARSING_OUTPUT, + STRING_FAILED_TO_FILL_INTO_IFRAME, + STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT, + STRING_FAILED_TO_FILL_PREFILLED_USERNAME, + STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME, STRING_INVALID, // Represents a string returned in a case of an error. STRING_MAX = STRING_INVALID }; diff --git a/chromium/components/autofill/ios/browser/BUILD.gn b/chromium/components/autofill/ios/browser/BUILD.gn index c17fc305885..3a5e25be0d6 100644 --- a/chromium/components/autofill/ios/browser/BUILD.gn +++ b/chromium/components/autofill/ios/browser/BUILD.gn @@ -67,6 +67,7 @@ source_set("test_support") { "//base", "//base/test:test_support", "//components/autofill/core/browser", + "//components/leveldb_proto:leveldb_proto", "//ios/web/public", ] } diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm index 40a51344cdf..eb8bf0dd088 100644 --- a/chromium/components/autofill/ios/browser/autofill_agent.mm +++ b/chromium/components/autofill/ios/browser/autofill_agent.mm @@ -231,8 +231,7 @@ autofillManagerFromWebState:(web::WebState*)webState DCHECK_EQ(1U, forms.size()); autofill::FormData form = forms[0]; autofillManager->OnFormSubmitted(form, false, - autofill::SubmissionSource::FORM_SUBMISSION, - base::TimeTicks::Now()); + autofill::SubmissionSource::FORM_SUBMISSION); autofill::KeyboardAccessoryMetricsLogger::OnFormSubmitted(); } diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.h b/chromium/components/autofill/ios/browser/autofill_driver_ios.h index 75ec90b29c5..2624127f010 100644 --- a/chromium/components/autofill/ios/browser/autofill_driver_ios.h +++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.h @@ -54,7 +54,6 @@ class AutofillDriverIOS : public AutofillDriver { void RendererShouldClearPreviewedForm() override; void RendererShouldAcceptDataListSuggestion( const base::string16& value) override; - void DidInteractWithCreditCardForm() override; AutofillManager* autofill_manager() { return &autofill_manager_; } diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm index 94da426d9af..bba0e29ee9a 100644 --- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm +++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm @@ -116,12 +116,6 @@ void AutofillDriverIOS::RendererShouldAcceptDataListSuggestion( const base::string16& value) { } -void AutofillDriverIOS::DidInteractWithCreditCardForm() { - if (!web::IsOriginSecure(web_state_->GetLastCommittedURL())) { - autofill_manager_.client()->DidInteractWithNonsecureCreditCardInput(); - } -} - void AutofillDriverIOS::RendererShouldClearFilledSection() {} void AutofillDriverIOS::RendererShouldClearPreviewedForm() { diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.h b/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.h index 39903370245..56a6630190e 100644 --- a/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.h +++ b/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.h @@ -34,18 +34,19 @@ class AutofillDriverIOSWebFrameFactory AutofillManager::AutofillDownloadManagerState enable_download_manager); ~AutofillDriverIOSWebFrameFactory() override; - // Returns a AutofillDriverIOSFromWebFrame for |web_frame|, creating it if - // needed. - AutofillDriverIOSWebFrame* AutofillDriverIOSFromWebFrame( - web::WebFrame* web_frame); - - private: AutofillDriverIOSWebFrameFactory( web::WebState* web_state, AutofillClient* client, id<AutofillDriverIOSBridge> bridge, const std::string& app_locale, AutofillManager::AutofillDownloadManagerState enable_download_manager); + + // Returns a AutofillDriverIOSFromWebFrame for |web_frame|, creating it if + // needed. + AutofillDriverIOSWebFrame* AutofillDriverIOSFromWebFrame( + web::WebFrame* web_frame); + + private: web::WebState* web_state_ = nullptr; AutofillClient* client_ = nullptr; id<AutofillDriverIOSBridge> bridge_ = nil; @@ -96,7 +97,6 @@ class AutofillDriverIOSWebFrame AutofillDriverIOS* driver() { return driver_.get(); } scoped_refptr<AutofillDriverIOSRefCountable> GetRetainableDriver(); - private: AutofillDriverIOSWebFrame( web::WebState* web_state, web::WebFrame* web_frame, diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.mm index c924b11f8ce..2c4988db611 100644 --- a/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.mm +++ b/chromium/components/autofill/ios/browser/autofill_driver_ios_webframe.mm @@ -20,8 +20,8 @@ void AutofillDriverIOSWebFrameFactory::CreateForWebStateAndDelegate( web_state->SetUserData( UserDataKey(), - base::WrapUnique(new AutofillDriverIOSWebFrameFactory( - web_state, client, bridge, app_locale, enable_download_manager))); + std::make_unique<AutofillDriverIOSWebFrameFactory>( + web_state, client, bridge, app_locale, enable_download_manager)); } AutofillDriverIOSWebFrameFactory::AutofillDriverIOSWebFrameFactory( @@ -59,9 +59,9 @@ void AutofillDriverIOSWebFrame::CreateForWebFrameAndDelegate( return; web_frame->SetUserData(UserDataKey(), - base::WrapUnique(new AutofillDriverIOSWebFrame( + std::make_unique<AutofillDriverIOSWebFrame>( web_state, web_frame, client, bridge, app_locale, - enable_download_manager))); + enable_download_manager)); } AutofillDriverIOSRefCountable::AutofillDriverIOSRefCountable( diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.h b/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.h index d6fc06948b4..7e3dabd4c62 100644 --- a/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.h +++ b/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.h @@ -28,7 +28,6 @@ class AutofillDriverIOSWebState ~AutofillDriverIOSWebState() override; - protected: AutofillDriverIOSWebState( web::WebState* web_state, AutofillClient* client, diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.mm index d69d3b5fd14..0237ae17128 100644 --- a/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.mm +++ b/chromium/components/autofill/ios/browser/autofill_driver_ios_webstate.mm @@ -24,8 +24,8 @@ void AutofillDriverIOSWebState::CreateForWebStateAndDelegate( web_state->SetUserData( UserDataKey(), - base::WrapUnique(new AutofillDriverIOSWebState( - web_state, client, bridge, app_locale, enable_download_manager))); + std::make_unique<AutofillDriverIOSWebState>( + web_state, client, bridge, app_locale, enable_download_manager)); } AutofillDriverIOSWebState::AutofillDriverIOSWebState( diff --git a/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h index cb879636101..4089ada1978 100644 --- a/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h +++ b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.h @@ -24,7 +24,7 @@ - (void)receivedUploadCardResponse; -- (void)ccsmStrikeChangeComplete; +- (void)strikeChangeComplete; @end @@ -46,7 +46,7 @@ class CreditCardSaveManagerTestObserverBridge void OnReceivedGetUploadDetailsResponse() override; void OnSentUploadCardRequest() override; void OnReceivedUploadCardResponse() override; - void OnCCSMStrikeChangeComplete() override; + void OnStrikeChangeComplete() override; private: __weak id<CreditCardSaveManagerTestObserver> observer_ = nil; diff --git a/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm index f615e04ff27..bbb0c41f08c 100644 --- a/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm +++ b/chromium/components/autofill/ios/browser/credit_card_save_manager_test_observer_bridge.mm @@ -43,8 +43,8 @@ void CreditCardSaveManagerTestObserverBridge::OnReceivedUploadCardResponse() { [observer_ receivedUploadCardResponse]; } -void CreditCardSaveManagerTestObserverBridge::OnCCSMStrikeChangeComplete() { - [observer_ ccsmStrikeChangeComplete]; +void CreditCardSaveManagerTestObserverBridge::OnStrikeChangeComplete() { + [observer_ strikeChangeComplete]; } } // namespace autofill diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm index fd595e57bbe..ed04da751eb 100644 --- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm +++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm @@ -16,8 +16,6 @@ #error "This file requires ARC support." #endif -DEFINE_WEB_STATE_USER_DATA_KEY(autofill::FormActivityTabHelper); - namespace autofill { namespace { diff --git a/chromium/components/autofill/ios/form_util/resources/form_handlers.js b/chromium/components/autofill/ios/form_util/resources/form_handlers.js index 8963d6bf4fc..940b256a480 100644 --- a/chromium/components/autofill/ios/form_util/resources/form_handlers.js +++ b/chromium/components/autofill/ios/form_util/resources/form_handlers.js @@ -94,9 +94,13 @@ function getFullyQualifiedUrl_(originalURL) { */ function formActivity_(evt) { var target = evt.target; + if (!['FORM', 'INPUT', 'OPTION', 'SELECT', 'TEXTAREA'].includes( + target.tagName)) { + return; + } var value = target.value || ''; var fieldType = target.type || ''; - if (evt.type != 'blur') { + if (evt.type !== 'blur') { lastFocusedElement_ = document.activeElement; } if (['change', 'input'].includes(evt.type) && @@ -122,6 +126,10 @@ function formActivity_(evt) { */ function submitHandler_(evt) { if (evt['defaultPrevented']) return; + if (evt.target.tagName !== 'FORM') { + return; + } + formSubmitted_(evt.target); } @@ -225,7 +233,7 @@ __gCrWeb.formHandlers['trackFormMutations'] = function(delay) { addedElements, [].slice.call(node.getElementsByTagName('*'))); } var form_changed = addedElements.find(function(element) { - return element.tagName.match(/(FORM|INPUT|SELECT|OPTION)/); + return element.tagName.match(/(FORM|INPUT|SELECT|OPTION|TEXTAREA)/); }); if (form_changed) { var msg = { |