diff options
author | levin@chromium.org <levin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-17 04:10:08 +0000 |
---|---|---|
committer | levin@chromium.org <levin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-17 04:10:08 +0000 |
commit | 1c507659ce3d86b0c6705d07005da486574804c2 (patch) | |
tree | 20b7b44073f2addd3f2ece3f8fefc46f38276d62 | |
parent | 8f3b5f4371c32005c9bb3ef868e9ae6568c42943 (diff) | |
download | chromium_src-1c507659ce3d86b0c6705d07005da486574804c2.zip chromium_src-1c507659ce3d86b0c6705d07005da486574804c2.tar.gz chromium_src-1c507659ce3d86b0c6705d07005da486574804c2.tar.bz2 |
Implement SearchProviderInstallData.
Support for Google base URL will be in another patch.
BUG=38475
TEST=unit_tests --gtest_filter=SearchProviderInstallDataTest*
Review URL: http://codereview.chromium.org/3403008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59765 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/search_engines/search_provider_install_data.cc | 186 | ||||
-rw-r--r-- | chrome/browser/search_engines/search_provider_install_data.h | 79 | ||||
-rw-r--r-- | chrome/browser/search_engines/search_provider_install_data_unittest.cc | 201 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_prepopulate_data.cc | 3 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 1 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 |
6 files changed, 458 insertions, 13 deletions
diff --git a/chrome/browser/search_engines/search_provider_install_data.cc b/chrome/browser/search_engines/search_provider_install_data.cc new file mode 100644 index 0000000..b137ece --- /dev/null +++ b/chrome/browser/search_engines/search_provider_install_data.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/search_engines/search_provider_install_data.h" + +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/task.h" +#include "chrome/browser/search_engines/search_host_to_urls_map.h" +#include "chrome/browser/search_engines/search_terms_data.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/search_engines/util.h" +#include "chrome/browser/webdata/web_data_service.h" + +typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet; + +namespace { + +// Implementation of SearchTermsData that may be used on the I/O thread. +class IOThreadSearchTermsData : public SearchTermsData { + public: + IOThreadSearchTermsData() {} + + // Implementation of SearchTermsData. + virtual std::string GoogleBaseURLValue() const; + virtual std::string GetApplicationLocale() const; +#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) + virtual std::wstring GetRlzParameterValue() const { + // This value doesn't matter for our purposes. + return std::wstring(); + } +#endif + + private: + + DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData); +}; + +std::string IOThreadSearchTermsData::GoogleBaseURLValue() const { + // TODO(levin): fix this. + return "http://FIXME.FIXME/"; +} + +std::string IOThreadSearchTermsData::GetApplicationLocale() const { + // This value doesn't matter for our purposes. + return "yy"; +} + +// Indicates if the two inputs have the same security origin. +// |requested_origin| should only be a security origin (no path, etc.). +// It is ok if |template_url| is NULL. +static bool IsSameOrigin(const GURL& requested_origin, + const TemplateURL* template_url, + const SearchTermsData& search_terms_data) { + DCHECK(requested_origin == requested_origin.GetOrigin()); + return template_url && requested_origin == + TemplateURLModel::GenerateSearchURLUsingTermsData( + template_url, + search_terms_data).GetOrigin(); +} + +} // namespace + +SearchProviderInstallData::SearchProviderInstallData( + WebDataService* web_service) + : web_service_(web_service), + load_handle_(0) { +} + +SearchProviderInstallData::~SearchProviderInstallData() { + if (load_handle_) { + DCHECK(web_service_.get()); + web_service_->CancelRequest(load_handle_); + } +} + +void SearchProviderInstallData::CallWhenLoaded(Task* task) { + if (provider_map_.get()) { + task->Run(); + delete task; + return; + } + + task_queue_.Push(task); + if (load_handle_) + return; + + if (web_service_.get()) + load_handle_ = web_service_->GetKeywords(this); + else + OnLoadFailed(); +} + +SearchProviderInstallData::State SearchProviderInstallData::GetInstallState( + const GURL& requested_origin) { + DCHECK(provider_map_.get()); + + // First check to see if the origin is the default search provider. + if (requested_origin.spec() == default_search_origin_) + return INSTALLED_AS_DEFAULT; + + // Is the url any search provider? + const TemplateURLSet* urls = provider_map_->GetURLsForHost( + requested_origin.host()); + if (!urls) + return NOT_INSTALLED; + + IOThreadSearchTermsData search_terms_data; + for (TemplateURLSet::const_iterator i = urls->begin(); + i != urls->end(); ++i) { + const TemplateURL* template_url = *i; + if (IsSameOrigin(requested_origin, template_url, search_terms_data)) + return INSTALLED_BUT_NOT_DEFAULT; + } + return NOT_INSTALLED; +} + +void SearchProviderInstallData::OnWebDataServiceRequestDone( + WebDataService::Handle h, + const WDTypedResult* result) { + // Reset the load_handle so that we don't try and cancel the load in + // the destructor. + load_handle_ = 0; + + if (!result) { + // Results are null if the database went away or (most likely) wasn't + // loaded. + OnLoadFailed(); + return; + } + + const TemplateURL* default_search_provider = NULL; + int new_resource_keyword_version = 0; + std::vector<TemplateURL*> extracted_template_urls; + GetSearchProvidersUsingKeywordResult(*result, + NULL, + NULL, + &extracted_template_urls, + &default_search_provider, + &new_resource_keyword_version); + template_urls_.get().insert(template_urls_.get().begin(), + extracted_template_urls.begin(), + extracted_template_urls.end()); + IOThreadSearchTermsData search_terms_data; + provider_map_.reset(new SearchHostToURLsMap()); + provider_map_->Init(template_urls_.get(), search_terms_data); + SetDefault(default_search_provider); + NotifyLoaded(); +} + +void SearchProviderInstallData::SetDefault(const TemplateURL* template_url) { + if (!template_url) { + default_search_origin_.clear(); + return; + } + + IOThreadSearchTermsData search_terms_data; + const GURL url(TemplateURLModel::GenerateSearchURLUsingTermsData( + template_url, search_terms_data)); + if (!url.is_valid() || !url.has_host()) { + default_search_origin_.clear(); + return; + } + default_search_origin_ = url.GetOrigin().spec(); +} + +void SearchProviderInstallData::OnLoadFailed() { + provider_map_.reset(new SearchHostToURLsMap()); + IOThreadSearchTermsData search_terms_data; + provider_map_->Init(template_urls_.get(), search_terms_data); + SetDefault(NULL); + NotifyLoaded(); +} + +void SearchProviderInstallData::NotifyLoaded() { + task_queue_.Run(); + + // Since we expect this request to be rare, clear out the information. This + // also keeps the responses current as the search providers change. + provider_map_.reset(); + SetDefault(NULL); +} diff --git a/chrome/browser/search_engines/search_provider_install_data.h b/chrome/browser/search_engines/search_provider_install_data.h index 02595db..f6fbf3b 100644 --- a/chrome/browser/search_engines/search_provider_install_data.h +++ b/chrome/browser/search_engines/search_provider_install_data.h @@ -4,22 +4,29 @@ #ifndef CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_DATA_H_ #define CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_DATA_H_ +#pragma once +#include <string> + +#include "base/basictypes.h" #include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/scoped_vector.h" +#include "base/task_queue.h" +#include "chrome/browser/webdata/web_data_service.h" class GURL; +class SearchHostToURLsMap; +class Task; +class TemplateURL; -// Provides the search provider install state for the I/O thread. -class SearchProviderInstallData - : public base::RefCountedThreadSafe<SearchProviderInstallData> { +// Provides the search provider install state for the I/O thread. It works by +// loading the data on demand (when CallWhenLoaded is called) and then throwing +// away the results after the callbacks are done, so the results are always up +// to date with what is in the database. +class SearchProviderInstallData : public WebDataServiceConsumer { public: enum State { - // The install state cannot be determined at the moment. - NOT_READY = -2, - - // Equates to an access denied error. - DENIED = -1, - // The search provider is not installed. NOT_INSTALLED = 0, @@ -30,12 +37,58 @@ class SearchProviderInstallData INSTALLED_AS_DEFAULT = 2 }; + explicit SearchProviderInstallData(WebDataService* web_service); + ~SearchProviderInstallData(); + + // Use to determine when the search provider information is loaded. + // The callback may happen synchronously or asynchronously. This + // takes ownership of |task|. There is no need to do anything special + // to make it function (as it just relies on the normal I/O thread message + // loop). + void CallWhenLoaded(Task* task); + // Returns the search provider install state for the given origin. - virtual State GetInstallState(const GURL& requested_origin) = 0; + // This should only be called while a task is called back from CallWhenLoaded. + State GetInstallState(const GURL& requested_origin); + + private: + // WebDataServiceConsumer + // Notification that the keywords have been loaded. + // This is invoked from WebDataService, and should not be directly + // invoked. + virtual void OnWebDataServiceRequestDone(WebDataService::Handle h, + const WDTypedResult* result); + + // Stores information about the default search provider. + void SetDefault(const TemplateURL* template_url); + + // Sets up the loaded state and then lets clients know that the search + // provider install state has been loaded. + void OnLoadFailed(); + + // Does notifications to let clients know that the search provider + // install state has been loaded. + void NotifyLoaded(); + + // The list of tasks to call after the load has finished. + TaskQueue task_queue_; + + // Service used to store entries. + scoped_refptr<WebDataService> web_service_; + + // If non-zero, we're waiting on a load. + WebDataService::Handle load_handle_; + + // Holds results of a load that was done using this class. + scoped_ptr<SearchHostToURLsMap> provider_map_; + + // The list of template urls that are owned by the class. + ScopedVector<const TemplateURL> template_urls_; + + // The security origin for the default search provider. + std::string default_search_origin_; - protected: - friend class base::RefCountedThreadSafe<SearchProviderInstallData>; - virtual ~SearchProviderInstallData() {} + DISALLOW_COPY_AND_ASSIGN(SearchProviderInstallData); }; #endif // CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_DATA_H_ diff --git a/chrome/browser/search_engines/search_provider_install_data_unittest.cc b/chrome/browser/search_engines/search_provider_install_data_unittest.cc new file mode 100644 index 0000000..1989a4c --- /dev/null +++ b/chrome/browser/search_engines/search_provider_install_data_unittest.cc @@ -0,0 +1,201 @@ +// Copyright (c) 2010 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 <string> + +#include "base/basictypes.h" +#include "base/message_loop.h" +#include "base/ref_counted.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/search_engines/search_provider_install_data.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/search_engines/template_url_model_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Create a TemplateURL. The caller owns the returned TemplateURL*. +static TemplateURL* CreateTemplateURL(const std::string& url, + const std::wstring& keyword) { + TemplateURL* t_url = new TemplateURL(); + t_url->SetURL(url, 0, 0); + t_url->set_keyword(keyword); + t_url->set_short_name(keyword); + return t_url; +} + +// Test the SearchProviderInstallData::GetInstallState. +class TestGetInstallState : + public base::RefCountedThreadSafe<TestGetInstallState> { + public: + explicit TestGetInstallState(WebDataService* web_data_service) + : install_data_(web_data_service), + main_loop_(NULL), + passed_(false) { + } + + void set_search_provider_host( + const std::string& search_provider_host) { + search_provider_host_ = search_provider_host; + } + + void set_default_search_provider_host( + const std::string& default_search_provider_host) { + default_search_provider_host_ = default_search_provider_host; + } + + // Runs the test. Returns true if all passed. False if any failed. + bool RunTests(const ChromeThread& io_thread); + + private: + friend class base::RefCountedThreadSafe<TestGetInstallState>; + ~TestGetInstallState(); + + // Starts the test run on the IO thread. + void StartTestOnIOThread(); + + // Callback for when SearchProviderInstallData is ready to have + // GetInstallState called. Runs all of the test cases. + void DoInstallStateTests(); + + // Does a verification for one url and its expected state. + void VerifyInstallState(SearchProviderInstallData::State expected_state, + const std::string& url); + + SearchProviderInstallData install_data_; + MessageLoop* main_loop_; + + // A host which should be a search provider but not the default. + std::string search_provider_host_; + + // A host which should be a search provider but not the default. + std::string default_search_provider_host_; + + // Used to indicate if DoInstallStateTests passed all test. + bool passed_; + + DISALLOW_COPY_AND_ASSIGN(TestGetInstallState); +}; + +bool TestGetInstallState::RunTests(const ChromeThread& io_thread) { + passed_ = true; + + main_loop_ = MessageLoop::current(); + + io_thread.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &TestGetInstallState::StartTestOnIOThread)); + // Run the current message loop. When the test is finished on the I/O thread, + // it invokes Quit, which unblocks this. + MessageLoop::current()->Run(); + main_loop_ = NULL; + + // Let the testing code know what the result is. + return passed_; +} + +TestGetInstallState::~TestGetInstallState() { +} + +void TestGetInstallState::StartTestOnIOThread() { + install_data_.CallWhenLoaded( + NewRunnableMethod(this, + &TestGetInstallState::DoInstallStateTests)); +} + +void TestGetInstallState::DoInstallStateTests() { + // Installed but not default. + VerifyInstallState(SearchProviderInstallData::INSTALLED_BUT_NOT_DEFAULT, + "http://" + search_provider_host_ + "/"); + VerifyInstallState(SearchProviderInstallData::INSTALLED_BUT_NOT_DEFAULT, + "http://" + search_provider_host_ + ":80/"); + + // Not installed. + VerifyInstallState(SearchProviderInstallData::NOT_INSTALLED, + "http://" + search_provider_host_ + ":96/"); + + // Not installed due to different scheme. + VerifyInstallState(SearchProviderInstallData::NOT_INSTALLED, + "https://" + search_provider_host_ + "/"); + + // Not installed. + VerifyInstallState(SearchProviderInstallData::NOT_INSTALLED, + "http://a" + search_provider_host_ + "/"); + + // Installed as default. + if (!default_search_provider_host_.empty()) { + VerifyInstallState(SearchProviderInstallData::INSTALLED_AS_DEFAULT, + "http://" + default_search_provider_host_ + "/"); + } + + // All done. + main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +} + +void TestGetInstallState::VerifyInstallState( + SearchProviderInstallData::State expected_state, + const std::string& url) { + + SearchProviderInstallData::State actual_state = + install_data_.GetInstallState(GURL(url)); + if (expected_state == actual_state) + return; + + passed_ = false; + LOG(ERROR) << "GetInstallState for " << url << " failed. Expected " << + expected_state << ". Actual " << actual_state << "."; +} + +// Provides basic test set-up/tear-down functionality needed by all tests +// that use TemplateURLModelTestUtil. +class SearchProviderInstallDataTest : public testing::Test { + public: + SearchProviderInstallDataTest() {} + + virtual void SetUp() { + testing::Test::SetUp(); + util_.SetUp(); + io_thread_.reset(new ChromeThread(ChromeThread::IO)); + io_thread_->Start(); + } + + virtual void TearDown() { + io_thread_->Stop(); + io_thread_.reset(); + util_.TearDown(); + testing::Test::TearDown(); + } + + protected: + TemplateURLModelTestUtil util_; + scoped_ptr<ChromeThread> io_thread_; + + DISALLOW_COPY_AND_ASSIGN(SearchProviderInstallDataTest); +}; + +TEST_F(SearchProviderInstallDataTest, GetInstallState) { + // Set up the database. + util_.ChangeModelToLoadState(); + std::string host = "www.unittest.com"; + TemplateURL* t_url = CreateTemplateURL("http://" + host + "/path", + L"unittest"); + util_.model()->Add(t_url); + + // Wait for the changes to be saved. + util_.BlockTillServiceProcessesRequests(); + + // Verify the search providers install state (with no default set). + scoped_refptr<TestGetInstallState> test_get_install_state( + new TestGetInstallState(util_.GetWebDataService())); + test_get_install_state->set_search_provider_host(host); + EXPECT_TRUE(test_get_install_state->RunTests(*io_thread_.get())); + + // Set-up a default and try it all one more time. + std::string default_host = "www.mmm.com"; + TemplateURL* default_url = CreateTemplateURL("http://" + default_host + "/", + L"mmm"); + util_.model()->Add(default_url); + util_.model()->SetDefaultSearchProvider(default_url); + test_get_install_state->set_default_search_provider_host(default_host); + EXPECT_TRUE(test_get_install_state->RunTests(*io_thread_.get())); +} diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc index c542ddd..7b745bd 100644 --- a/chrome/browser/search_engines/template_url_prepopulate_data.cc +++ b/chrome/browser/search_engines/template_url_prepopulate_data.cc @@ -3185,6 +3185,9 @@ TemplateURL* MakePrepopulatedTemplateURL(const wchar_t* name, void GetPrepopulatedTemplateFromPrefs(PrefService* prefs, std::vector<TemplateURL*>* t_urls) { + if (!prefs) + return; + const ListValue* list = prefs->GetList(prefs::kSearchProviderOverrides); if (!list) diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 205b82c..ece83e9 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2465,6 +2465,7 @@ 'browser/search_engines/search_host_to_urls_map.h', 'browser/search_engines/search_host_to_urls_map.cc', 'browser/search_engines/search_provider_install_data.h', + 'browser/search_engines/search_provider_install_data.cc', 'browser/search_engines/search_provider_install_state_dispatcher_host.cc', 'browser/search_engines/search_provider_install_state_dispatcher_host.h', 'browser/search_engines/search_terms_data.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 9ce7667..d7f34dc 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1216,6 +1216,7 @@ 'browser/safe_browsing/safe_browsing_util_unittest.cc', 'browser/search_engines/keyword_editor_controller_unittest.cc', 'browser/search_engines/search_host_to_urls_map_unittest.cc', + 'browser/search_engines/search_provider_install_data_unittest.cc', 'browser/search_engines/template_url_model_test_util.cc', 'browser/search_engines/template_url_model_test_util.h', 'browser/search_engines/template_url_model_unittest.cc', |