diff options
author | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-01 20:36:00 +0000 |
---|---|---|
committer | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-01 20:36:00 +0000 |
commit | 005c1a4a321ab4d54209adf19460e26a5135726c (patch) | |
tree | 0f816c802f555234c798cc89b5b567eef6d44acf | |
parent | 4c655ea69daf9ff9395afc51e65020474491e48d (diff) | |
download | chromium_src-005c1a4a321ab4d54209adf19460e26a5135726c.zip chromium_src-005c1a4a321ab4d54209adf19460e26a5135726c.tar.gz chromium_src-005c1a4a321ab4d54209adf19460e26a5135726c.tar.bz2 |
Move some Autofill processing logic on form submit to a background thread.
BUG=76992
TEST=Autofill continues to upload form data to the crowdsourcing server
Review URL: http://codereview.chromium.org/8387016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108162 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/autofill/autofill_manager.cc | 159 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.h | 27 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager_unittest.cc | 161 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_metrics_unittest.cc | 115 | ||||
-rw-r--r-- | chrome/browser/ui/tab_contents/tab_contents_wrapper.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/tab_contents/tab_contents_wrapper.h | 3 |
6 files changed, 297 insertions, 170 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc index 9b8ec0b..e5754a7 100644 --- a/chrome/browser/autofill/autofill_manager.cc +++ b/chrome/browser/autofill/autofill_manager.cc @@ -11,6 +11,7 @@ #include <set> #include <utility> +#include "base/bind.h" #include "base/command_line.h" #include "base/logging.h" #include "base/string16.h" @@ -44,6 +45,7 @@ #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/browser/renderer_host/render_view_host.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "googleurl/src/gurl.h" @@ -127,6 +129,40 @@ bool FormIsHTTPS(const FormStructure& form) { return form.source_url().SchemeIs(chrome::kHttpsScheme); } +// Uses the existing personal data in |profiles| and |credit_cards| to determine +// possible field types for the |submitted_form|. This is potentially +// expensive -- on the order of 50ms even for a small set of |stored_data|. +// Hence, it should not run on the UI thread -- to avoid locking up the UI -- +// nor on the IO thread -- to avoid blocking IPC calls. +void DeterminePossibleFieldTypesForUpload( + const std::vector<AutofillProfile>& profiles, + const std::vector<CreditCard>& credit_cards, + FormStructure* submitted_form) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + // For each field in the |submitted_form|, extract the value. Then for each + // profile or credit card, identify any stored types that match the value. + for (size_t i = 0; i < submitted_form->field_count(); ++i) { + AutofillField* field = submitted_form->field(i); + string16 value = CollapseWhitespace(field->value, false); + + FieldTypeSet matching_types; + for (std::vector<AutofillProfile>::const_iterator it = profiles.begin(); + it != profiles.end(); ++it) { + it->GetMatchingTypes(value, &matching_types); + } + for (std::vector<CreditCard>::const_iterator it = credit_cards.begin(); + it != credit_cards.end(); ++it) { + it->GetMatchingTypes(value, &matching_types); + } + + if (matching_types.empty()) + matching_types.insert(UNKNOWN_TYPE); + + field->set_possible_types(matching_types); + } +} + // Check for unidentified forms among those with the most query or upload // requests. If found, present an infobar prompting the user to send Google // Feedback identifying these forms. Only executes if the appropriate flag is @@ -219,8 +255,6 @@ AutofillManager::AutofillManager(TabContentsWrapper* tab_contents) user_did_autofill_(false), user_did_edit_autofilled_field_(false), external_delegate_(NULL) { - DCHECK(tab_contents); - // |personal_data_| is NULL when using TestTabContents. personal_data_ = PersonalDataManagerFactory::GetForProfile( tab_contents->profile()->GetOriginalProfile()); @@ -282,53 +316,81 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) { return handled; } -void AutofillManager::OnFormSubmitted(const FormData& form, +bool AutofillManager::OnFormSubmitted(const FormData& form, const TimeTicks& timestamp) { // Let AutoComplete know as well. tab_contents_wrapper_->autocomplete_history_manager()->OnFormSubmitted(form); if (!IsAutofillEnabled()) - return; + return false; if (tab_contents()->browser_context()->IsOffTheRecord()) - return; + return false; // Don't save data that was submitted through JavaScript. if (!form.user_submitted) - return; + return false; // Grab a copy of the form data. - FormStructure submitted_form(form); + scoped_ptr<FormStructure> submitted_form(new FormStructure(form)); // Disregard forms that we wouldn't ever autofill in the first place. - if (!submitted_form.ShouldBeParsed(true)) - return; + if (!submitted_form->ShouldBeParsed(true)) + return false; // Ignore forms not present in our cache. These are typically forms with // wonky JavaScript that also makes them not auto-fillable. FormStructure* cached_submitted_form; if (!FindCachedForm(form, &cached_submitted_form)) - return; - submitted_form.UpdateFromCache(*cached_submitted_form); + return false; + + submitted_form->UpdateFromCache(*cached_submitted_form); + if (submitted_form->IsAutofillable(true)) + ImportFormData(*submitted_form); // Only upload server statistics and UMA metrics if at least some local data // is available to use as a baseline. - if (!personal_data_->profiles().empty() || - !personal_data_->credit_cards().empty()) { - DeterminePossibleFieldTypesForUpload(&submitted_form); - submitted_form.LogQualityMetrics(*metric_logger_, - forms_loaded_timestamp_, - initial_interaction_timestamp_, - timestamp); - - if (submitted_form.ShouldBeCrowdsourced()) - UploadFormData(submitted_form); - } + const std::vector<AutofillProfile*>& profiles = personal_data_->profiles(); + const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards(); + if (!profiles.empty() || !credit_cards.empty()) { + // Copy the profile and credit card data, so that it can be accessed on a + // separate thread. + std::vector<AutofillProfile> copied_profiles; + copied_profiles.reserve(profiles.size()); + for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin(); + it != profiles.end(); ++it) { + copied_profiles.push_back(**it); + } - if (!submitted_form.IsAutofillable(true)) - return; + std::vector<CreditCard> copied_credit_cards; + copied_credit_cards.reserve(credit_cards.size()); + for (std::vector<CreditCard*>::const_iterator it = credit_cards.begin(); + it != credit_cards.end(); ++it) { + copied_credit_cards.push_back(**it); + } - ImportFormData(submitted_form); + // TODO(isherman): Ideally, we should not be using the FILE thread here. + // Per jar@, this is a good compromise for now, as we don't currently have a + // broad consensus on how to support such one-off background tasks. + + // Note that ownership of |submitted_form| is passed to the second task, + // using |base::Owned|. + FormStructure* raw_submitted_form = submitted_form.get(); + BrowserThread::PostTaskAndReply( + BrowserThread::FILE, FROM_HERE, + base::Bind(&DeterminePossibleFieldTypesForUpload, + copied_profiles, + copied_credit_cards, + raw_submitted_form), + base::Bind(&AutofillManager::UploadFormDataAsyncCallback, + this, + base::Owned(submitted_form.release()), + forms_loaded_timestamp_, + initial_interaction_timestamp_, + timestamp)); + } + + return true; } void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms, @@ -627,35 +689,6 @@ bool AutofillManager::IsAutofillEnabled() const { return profile->GetPrefs()->GetBoolean(prefs::kAutofillEnabled); } -void AutofillManager::DeterminePossibleFieldTypesForUpload( - FormStructure* submitted_form) { - // Combine all the profiles and credit cards stored in |personal_data_| into - // one vector for ease of iteration. - const std::vector<AutofillProfile*>& profiles = personal_data_->profiles(); - const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards(); - std::vector<FormGroup*> stored_data; - stored_data.insert(stored_data.end(), profiles.begin(), profiles.end()); - stored_data.insert(stored_data.end(), credit_cards.begin(), - credit_cards.end()); - - // For each field in the |submitted_form|, extract the value. Then for each - // profile or credit card, identify any stored types that match the value. - for (size_t i = 0; i < submitted_form->field_count(); i++) { - AutofillField* field = submitted_form->field(i); - string16 value = CollapseWhitespace(field->value, false); - FieldTypeSet matching_types; - for (std::vector<FormGroup*>::const_iterator it = stored_data.begin(); - it != stored_data.end(); ++it) { - (*it)->GetMatchingTypes(value, &matching_types); - } - - if (matching_types.empty()) - matching_types.insert(UNKNOWN_TYPE); - - field->set_possible_types(matching_types); - } -} - void AutofillManager::SendAutofillTypePredictions( const std::vector<FormStructure*>& forms) const { if (!CommandLine::ForCurrentProcess()->HasSwitch( @@ -691,6 +724,24 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) { } } +// 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 +// get reset before this method executes. +void AutofillManager::UploadFormDataAsyncCallback( + const FormStructure* submitted_form, + const TimeTicks& load_time, + const TimeTicks& interaction_time, + const TimeTicks& submission_time) { + submitted_form->LogQualityMetrics(*metric_logger_, + load_time, + interaction_time, + submission_time); + + if (submitted_form->ShouldBeCrowdsourced()) + UploadFormData(*submitted_form); +} + void AutofillManager::UploadFormData(const FormStructure& submitted_form) { if (disable_download_manager_requests_) return; diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h index f81e964..4115187 100644 --- a/chrome/browser/autofill/autofill_manager.h +++ b/chrome/browser/autofill/autofill_manager.h @@ -14,6 +14,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "base/string16.h" @@ -47,10 +48,10 @@ struct FormField; // Manages saving and restoring the user's personal information entered into web // forms. class AutofillManager : public TabContentsObserver, - public AutofillDownloadManager::Observer { + public AutofillDownloadManager::Observer, + public base::RefCounted<AutofillManager> { public: explicit AutofillManager(TabContentsWrapper* tab_contents); - virtual ~AutofillManager(); // Registers our Enable/Disable Autofill pref. static void RegisterUserPrefs(PrefService* prefs); @@ -65,6 +66,8 @@ class AutofillManager : public TabContentsObserver, protected: // Only test code should subclass AutofillManager. + friend class base::RefCounted<AutofillManager>; + virtual ~AutofillManager(); // The string/int pair is composed of the guid string and variant index // respectively. The variant index is an index into the multi-valued item @@ -84,6 +87,14 @@ class AutofillManager : public TabContentsObserver, // Reset cache. void Reset(); + // Logs quality metrics for the |submitted_form| and uploads the form data + // to the crowdsourcing server, if appropriate. + virtual void UploadFormDataAsyncCallback( + const FormStructure* submitted_form, + const base::TimeTicks& load_time, + const base::TimeTicks& interaction_time, + const base::TimeTicks& submission_time); + // Maps GUIDs to and from IDs that are used to identify profiles and credit // cards sent to and from the renderer process. virtual int GUIDToID(const GUIDPair& guid) const; @@ -110,6 +121,12 @@ class AutofillManager : public TabContentsObserver, return external_delegate_; } + // Processes the submitted |form|, saving any new Autofill data and uploading + // the possible field types for the submitted fields to the crowdsouring + // server. Returns false if this form is not relevant for Autofill. + bool OnFormSubmitted(const webkit_glue::FormData& form, + const base::TimeTicks& timestamp); + private: // TabContentsObserver: virtual void DidNavigateMainFramePostCommit( @@ -121,8 +138,6 @@ class AutofillManager : public TabContentsObserver, virtual void OnLoadedServerPredictions( const std::string& response_xml) OVERRIDE; - void OnFormSubmitted(const webkit_glue::FormData& form, - const base::TimeTicks& timestamp); void OnFormsSeen(const std::vector<webkit_glue::FormData>& forms, const base::TimeTicks& timestamp); void OnTextFieldDidChange(const webkit_glue::FormData& form, @@ -223,10 +238,6 @@ class AutofillManager : public TabContentsObserver, // Parses the forms using heuristic matching and querying the Autofill server. void ParseForms(const std::vector<webkit_glue::FormData>& forms); - // Uses existing personal data to determine possible field types for the - // |submitted_form|. - void DeterminePossibleFieldTypesForUpload(FormStructure* submitted_form); - // Imports the form data, submitted by the user, into |personal_data_|. void ImportFormData(const FormStructure& submitted_form); diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc index 7c777b5..af71687 100644 --- a/chrome/browser/autofill/autofill_manager_unittest.cc +++ b/chrome/browser/autofill/autofill_manager_unittest.cc @@ -411,7 +411,9 @@ class TestAutofillManager : public AutofillManager { TestPersonalDataManager* personal_data) : AutofillManager(tab_contents, personal_data), personal_data_(personal_data), - autofill_enabled_(true) { + autofill_enabled_(true), + did_finish_async_form_submit_(false), + message_loop_is_running_(false) { } virtual bool IsAutofillEnabled() const OVERRIDE { return autofill_enabled_; } @@ -420,6 +422,62 @@ class TestAutofillManager : public AutofillManager { autofill_enabled_ = autofill_enabled; } + void set_expected_submitted_field_types( + const std::vector<FieldTypeSet>& expected_types) { + expected_submitted_field_types_ = expected_types; + } + + virtual void UploadFormDataAsyncCallback( + const FormStructure* submitted_form, + const base::TimeTicks& load_time, + const base::TimeTicks& interaction_time, + const base::TimeTicks& submission_time) OVERRIDE { + if (message_loop_is_running_) { + MessageLoop::current()->Quit(); + message_loop_is_running_ = false; + } else { + did_finish_async_form_submit_ = true; + } + + // If we have expected field types set, make sure they match. + if (!expected_submitted_field_types_.empty()) { + ASSERT_EQ(expected_submitted_field_types_.size(), + submitted_form->field_count()); + for (size_t i = 0; i < expected_submitted_field_types_.size(); ++i) { + SCOPED_TRACE( + StringPrintf("Field %d with value %s", static_cast<int>(i), + UTF16ToUTF8(submitted_form->field(i)->value).c_str())); + const FieldTypeSet& possible_types = + submitted_form->field(i)->possible_types(); + EXPECT_EQ(expected_submitted_field_types_[i].size(), + possible_types.size()); + for (FieldTypeSet::const_iterator it = + expected_submitted_field_types_[i].begin(); + it != expected_submitted_field_types_[i].end(); ++it) { + EXPECT_TRUE(possible_types.count(*it)) + << "Expected type: " << AutofillType::FieldTypeToString(*it); + } + } + } + + AutofillManager::UploadFormDataAsyncCallback(submitted_form, + load_time, + interaction_time, + submission_time); + } + + // Wait for the asynchronous OnFormSubmitted() call to complete. + void WaitForAsyncFormSubmit() { + if (!did_finish_async_form_submit_) { + // TODO(isherman): It seems silly to need this variable. Is there some + // way I can just query the message loop's state? + message_loop_is_running_ = true; + MessageLoop::current()->Run(); + } else { + did_finish_async_form_submit_ = false; + } + } + virtual void UploadFormData(const FormStructure& submitted_form) OVERRIDE { submitted_form_signature_ = submitted_form.FormSignature(); } @@ -452,10 +510,19 @@ class TestAutofillManager : public AutofillManager { } private: + // AutofillManager is ref counted. + virtual ~TestAutofillManager() {} + // Weak reference. TestPersonalDataManager* personal_data_; + bool autofill_enabled_; + + bool did_finish_async_form_submit_; + bool message_loop_is_running_; + std::string submitted_form_signature_; + std::vector<FieldTypeSet> expected_submitted_field_types_; DISALLOW_COPY_AND_ASSIGN(TestAutofillManager); }; @@ -468,24 +535,32 @@ class AutofillManagerTest : public TabContentsWrapperTestHarness { AutofillManagerTest() : TabContentsWrapperTestHarness(), - browser_thread_(BrowserThread::UI, &message_loop_) { + ui_thread_(BrowserThread::UI, &message_loop_), + file_thread_(BrowserThread::FILE) { } virtual ~AutofillManagerTest() { // Order of destruction is important as AutofillManager relies on // PersonalDataManager to be around when it gets destroyed. - autofill_manager_.reset(NULL); + autofill_manager_ = NULL; } - virtual void SetUp() { + virtual void SetUp() OVERRIDE { Profile* profile = new TestingProfile(); browser_context_.reset(profile); PersonalDataManagerFactory::GetInstance()->SetTestingFactory( profile, TestPersonalDataManager::Build); TabContentsWrapperTestHarness::SetUp(); - autofill_manager_.reset(new TestAutofillManager(contents_wrapper(), - &personal_data_)); + autofill_manager_ = new TestAutofillManager(contents_wrapper(), + &personal_data_); + + file_thread_.Start(); + } + + virtual void TearDown() OVERRIDE { + file_thread_.Stop(); + TabContentsWrapperTestHarness::TearDown(); } void GetAutofillSuggestions(int query_id, @@ -509,7 +584,8 @@ class AutofillManagerTest : public TabContentsWrapperTestHarness { } void FormSubmitted(const FormData& form) { - autofill_manager_->OnFormSubmitted(form, base::TimeTicks::Now()); + if (autofill_manager_->OnFormSubmitted(form, base::TimeTicks::Now())) + autofill_manager_->WaitForAsyncFormSubmit(); } void FillAutofillFormData(int query_id, @@ -570,9 +646,10 @@ class AutofillManagerTest : public TabContentsWrapperTestHarness { } protected: - content::TestBrowserThread browser_thread_; + content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_thread_; - scoped_ptr<TestAutofillManager> autofill_manager_; + scoped_refptr<TestAutofillManager> autofill_manager_; TestPersonalDataManager personal_data_; private: @@ -2773,70 +2850,8 @@ TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload) { form.fields.push_back(field); expected_types.push_back(types); - FormStructure form_structure(form); - autofill_manager_->DeterminePossibleFieldTypesForUpload(&form_structure); - - ASSERT_EQ(expected_types.size(), form_structure.field_count()); - for (size_t i = 0; i < expected_types.size(); ++i) { - SCOPED_TRACE( - StringPrintf("Field %d with value %s", static_cast<int>(i), - UTF16ToUTF8(form_structure.field(i)->value).c_str())); - const FieldTypeSet& possible_types = - form_structure.field(i)->possible_types(); - EXPECT_EQ(expected_types[i].size(), possible_types.size()); - for (FieldTypeSet::const_iterator it = expected_types[i].begin(); - it != expected_types[i].end(); ++it) { - EXPECT_TRUE(possible_types.count(*it)) - << "Expected type: " << AutofillType::FieldTypeToString(*it); - } - } -} - -TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUploadStressTest) { - personal_data_.ClearAutofillProfiles(); - const int kNumProfiles = 5; - for (int i = 0; i < kNumProfiles; ++i) { - AutofillProfile* profile = new AutofillProfile; - autofill_test::SetProfileInfo(profile, - StringPrintf("John%d", i).c_str(), - "", - StringPrintf("Doe%d", i).c_str(), - StringPrintf("JohnDoe%d@somesite.com", - i).c_str(), - "", - StringPrintf("%d 1st st.", i).c_str(), - "", - "Memphis", "Tennessee", "38116", "USA", - StringPrintf("650234%04d", i).c_str()); - profile->set_guid( - StringPrintf("00000000-0000-0000-0001-00000000%04d", i).c_str()); - personal_data_.AddProfile(profile); - } - FormData form; - CreateTestAddressFormData(&form); - ASSERT_LT(3U, form.fields.size()); - form.fields[0].value = ASCIIToUTF16("6502340001"); - form.fields[1].value = ASCIIToUTF16("John1"); - form.fields[2].value = ASCIIToUTF16("12345"); - FormStructure form_structure(form); - autofill_manager_->DeterminePossibleFieldTypesForUpload(&form_structure); - ASSERT_LT(3U, form_structure.field_count()); - const FieldTypeSet& possible_types0 = - form_structure.field(0)->possible_types(); - EXPECT_EQ(2U, possible_types0.size()); - EXPECT_TRUE(possible_types0.find(PHONE_HOME_WHOLE_NUMBER) != - possible_types0.end()); - EXPECT_TRUE(possible_types0.find(PHONE_HOME_CITY_AND_NUMBER) != - possible_types0.end()); - const FieldTypeSet& possible_types1 = - form_structure.field(1)->possible_types(); - EXPECT_EQ(1U, possible_types1.size()); - EXPECT_TRUE(possible_types1.find(NAME_FIRST) != possible_types1.end()); - const FieldTypeSet& possible_types2 = - form_structure.field(2)->possible_types(); - EXPECT_EQ(1U, possible_types2.size()); - EXPECT_TRUE(possible_types2.find(UNKNOWN_TYPE) != - possible_types2.end()); + autofill_manager_->set_expected_submitted_field_types(expected_types); + FormSubmitted(form); } namespace { diff --git a/chrome/browser/autofill/autofill_metrics_unittest.cc b/chrome/browser/autofill/autofill_metrics_unittest.cc index 26b7af0..fc86dc7 100644 --- a/chrome/browser/autofill/autofill_metrics_unittest.cc +++ b/chrome/browser/autofill/autofill_metrics_unittest.cc @@ -178,10 +178,11 @@ class TestAutofillManager : public AutofillManager { TestAutofillManager(TabContentsWrapper* tab_contents, TestPersonalDataManager* personal_manager) : AutofillManager(tab_contents, personal_manager), - autofill_enabled_(true) { + autofill_enabled_(true), + did_finish_async_form_submit_(false), + message_loop_is_running_(false) { set_metric_logger(new MockAutofillMetrics); } - virtual ~TestAutofillManager() {} virtual bool IsAutofillEnabled() const { return autofill_enabled_; } @@ -210,8 +211,46 @@ class TestAutofillManager : public AutofillManager { form_structures()->push_back(form_structure); } + void FormSubmitted(const FormData& form, const TimeTicks& timestamp) { + if (!OnFormSubmitted(form, timestamp)) + return; + + // Wait for the asynchronous FormSubmitted() call to complete. + if (!did_finish_async_form_submit_) { + // TODO(isherman): It seems silly to need this variable. Is there some + // way I can just query the message loop's state? + message_loop_is_running_ = true; + MessageLoop::current()->Run(); + } else { + did_finish_async_form_submit_ = false; + } + } + + virtual void UploadFormDataAsyncCallback( + const FormStructure* submitted_form, + const base::TimeTicks& load_time, + const base::TimeTicks& interaction_time, + const base::TimeTicks& submission_time) OVERRIDE { + if (message_loop_is_running_) { + MessageLoop::current()->Quit(); + message_loop_is_running_ = false; + } else { + did_finish_async_form_submit_ = true; + } + + AutofillManager::UploadFormDataAsyncCallback(submitted_form, + load_time, + interaction_time, + submission_time); + } + private: + // AutofillManager is ref counted. + virtual ~TestAutofillManager() {} + bool autofill_enabled_; + bool did_finish_async_form_submit_; + bool message_loop_is_running_; DISALLOW_COPY_AND_ASSIGN(TestAutofillManager); }; @@ -223,30 +262,33 @@ class AutofillMetricsTest : public TabContentsWrapperTestHarness { AutofillMetricsTest(); virtual ~AutofillMetricsTest(); - virtual void SetUp(); + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; protected: AutofillCCInfoBarDelegate* CreateDelegate(MockAutofillMetrics* metric_logger, CreditCard** created_card); - scoped_ptr<TestAutofillManager> autofill_manager_; + content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_thread_; + + scoped_refptr<TestAutofillManager> autofill_manager_; TestPersonalDataManager personal_data_; private: - content::TestBrowserThread browser_thread_; - DISALLOW_COPY_AND_ASSIGN(AutofillMetricsTest); }; AutofillMetricsTest::AutofillMetricsTest() : TabContentsWrapperTestHarness(), - browser_thread_(BrowserThread::UI, &message_loop_) { + ui_thread_(BrowserThread::UI, &message_loop_), + file_thread_(BrowserThread::FILE) { } AutofillMetricsTest::~AutofillMetricsTest() { // Order of destruction is important as AutofillManager relies on // PersonalDataManager to be around when it gets destroyed. - autofill_manager_.reset(NULL); + autofill_manager_ = NULL; } void AutofillMetricsTest::SetUp() { @@ -256,8 +298,15 @@ void AutofillMetricsTest::SetUp() { profile, TestPersonalDataManager::Build); TabContentsWrapperTestHarness::SetUp(); - autofill_manager_.reset(new TestAutofillManager(contents_wrapper(), - &personal_data_)); + autofill_manager_ = new TestAutofillManager(contents_wrapper(), + &personal_data_); + + file_thread_.Start(); +} + +void AutofillMetricsTest::TearDown() { + file_thread_.Stop(); + TabContentsWrapperTestHarness::TearDown(); } AutofillCCInfoBarDelegate* AutofillMetricsTest::CreateDelegate( @@ -420,8 +469,8 @@ TEST_F(AutofillMetricsTest, QualityMetrics) { AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME)); // Simulate form submission. - EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form, - TimeTicks::Now())); + EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, + TimeTicks::Now())); } // Test that we log the appropriate additional metrics when Autofill failed. @@ -538,8 +587,8 @@ TEST_F(AutofillMetricsTest, QualityMetricsForFailure) { } // Simulate form submission. - EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form, - TimeTicks::Now())); + EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, + TimeTicks::Now())); } // Test that we behave sanely when the cached form differs from the submitted @@ -696,8 +745,8 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) { std::string())); // Simulate form submission. - EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form, - TimeTicks::Now())); + EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, + TimeTicks::Now())); } // Test that we don't log quality metrics for non-autofillable forms. @@ -723,8 +772,8 @@ TEST_F(AutofillMetricsTest, NoQualityMetricsForNonAutofillableForms) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, std::string())).Times(0); - EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form, - TimeTicks::Now())); + EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, + TimeTicks::Now())); // Search forms are not auto-fillable. form.action = GURL("http://example.com/search?q=Elvis%20Presley"); @@ -736,8 +785,8 @@ TEST_F(AutofillMetricsTest, NoQualityMetricsForNonAutofillableForms) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, std::string())).Times(0); - EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form, - TimeTicks::Now())); + EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, + TimeTicks::Now())); } // Test that we recored the experiment id appropriately. @@ -862,8 +911,8 @@ TEST_F(AutofillMetricsTest, QualityMetricsWithExperimentId) { ADDRESS_HOME_COUNTRY, experiment_id)); // Simulate form submission. - EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form, - TimeTicks::Now())); + EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form, + TimeTicks::Now())); } // Test that the profile count is logged correctly. @@ -1106,7 +1155,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { *autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)).Times(0); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Add more fields to the form. @@ -1128,7 +1177,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Fill in two of the fields. @@ -1141,7 +1190,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Fill in the third field. @@ -1153,7 +1202,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_NONE)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } @@ -1166,7 +1215,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Mark all of the fillable fields as autofilled. @@ -1179,7 +1228,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_ALL)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } // Clear out the third field's value. @@ -1191,7 +1240,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogUserHappinessMetric( AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::Now()); + autofill_manager_->FormSubmitted(form, TimeTicks::Now()); } } @@ -1344,7 +1393,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { EXPECT_CALL(*autofill_manager_->metric_logger(), LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0); autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17)); + autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } @@ -1364,7 +1413,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks::FromInternalValue(3)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17)); + autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } @@ -1385,7 +1434,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1)); autofill_manager_->OnDidFillAutofillFormData( TimeTicks::FromInternalValue(5)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17)); + autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } @@ -1409,7 +1458,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { TimeTicks::FromInternalValue(5)); autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), TimeTicks::FromInternalValue(3)); - autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17)); + autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17)); autofill_manager_->Reset(); Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger()); } diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc index 78843dc..8d95117 100644 --- a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc +++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc @@ -247,7 +247,7 @@ TabContentsWrapper::TabContentsWrapper(TabContents* contents) // Create the tab helpers. autocomplete_history_manager_.reset(new AutocompleteHistoryManager(contents)); - autofill_manager_.reset(new AutofillManager(this)); + autofill_manager_ = new AutofillManager(this); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kExternalAutofillPopup)) { autofill_external_delegate_.reset( diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h index 09fe200..1592e6c 100644 --- a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h +++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper_synced_tab_delegate.h" @@ -274,7 +275,7 @@ class TabContentsWrapper : public TabContentsObserver, // "Tab Helpers" section in the member functions area, above.) scoped_ptr<AutocompleteHistoryManager> autocomplete_history_manager_; - scoped_ptr<AutofillManager> autofill_manager_; + scoped_refptr<AutofillManager> autofill_manager_; scoped_ptr<AutofillExternalDelegate> autofill_external_delegate_; scoped_ptr<AutomationTabHelper> automation_tab_helper_; scoped_ptr<BlockedContentTabHelper> blocked_content_tab_helper_; |