Commit c64258bf authored by stevet@chromium.org's avatar stevet@chromium.org

Implement SyncableServices in TemplateURLService. Add related unittests.

TEST=Ensure all TemplateURLService related unit tests pass.
BUG=15548
Review URL: http://codereview.chromium.org/7566036

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96969 0039d316-1c4b-4281-b951-d872f2087c98
parent 20e01ed0
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "chrome/browser/search_engines/search_engine_type.h" #include "chrome/browser/search_engines/search_engine_type.h"
#include "chrome/browser/search_engines/search_terms_data.h" #include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url_service.h" #include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/common/guid.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h" #include "chrome/installer/util/google_update_settings.h"
#include "content/browser/user_metrics.h" #include "content/browser/user_metrics.h"
...@@ -642,7 +643,8 @@ TemplateURL::TemplateURL() ...@@ -642,7 +643,8 @@ TemplateURL::TemplateURL()
usage_count_(0), usage_count_(0),
search_engine_type_(SEARCH_ENGINE_OTHER), search_engine_type_(SEARCH_ENGINE_OTHER),
logo_id_(kNoSearchEngineLogo), logo_id_(kNoSearchEngineLogo),
prepopulate_id_(0) { prepopulate_id_(0),
sync_guid_(guid::GenerateGUID()) {
} }
TemplateURL::~TemplateURL() { TemplateURL::~TemplateURL() {
...@@ -730,10 +732,7 @@ GURL TemplateURL::GetFaviconURL() const { ...@@ -730,10 +732,7 @@ GURL TemplateURL::GetFaviconURL() const {
void TemplateURL::SetPrepopulateId(int id) { void TemplateURL::SetPrepopulateId(int id) {
prepopulate_id_ = id; prepopulate_id_ = id;
if (id > 0) SetTemplateURLRefsPrepopulated(id > 0);
SetTemplateURLRefsPrepopulated(true);
else
SetTemplateURLRefsPrepopulated(false);
} }
void TemplateURL::InvalidateCachedValues() const { void TemplateURL::InvalidateCachedValues() const {
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "chrome/browser/profiles/profile_keyed_service.h" #include "chrome/browser/profiles/profile_keyed_service.h"
#include "chrome/browser/search_engines/search_host_to_urls_map.h" #include "chrome/browser/search_engines/search_host_to_urls_map.h"
#include "chrome/browser/search_engines/template_url_id.h" #include "chrome/browser/search_engines/template_url_id.h"
#include "chrome/browser/sync/api/sync_change.h"
#include "chrome/browser/sync/api/syncable_service.h"
#include "chrome/browser/webdata/web_data_service.h" #include "chrome/browser/webdata/web_data_service.h"
#include "content/common/notification_observer.h" #include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h" #include "content/common/notification_registrar.h"
...@@ -28,6 +30,7 @@ class Profile; ...@@ -28,6 +30,7 @@ class Profile;
class PrefSetObserver; class PrefSetObserver;
class SearchHostToURLsMap; class SearchHostToURLsMap;
class SearchTermsData; class SearchTermsData;
class SyncData;
class TemplateURLServiceObserver; class TemplateURLServiceObserver;
class TemplateURLRef; class TemplateURLRef;
...@@ -58,12 +61,14 @@ struct URLVisitedDetails; ...@@ -58,12 +61,14 @@ struct URLVisitedDetails;
class TemplateURLService : public WebDataServiceConsumer, class TemplateURLService : public WebDataServiceConsumer,
public ProfileKeyedService, public ProfileKeyedService,
public NotificationObserver { public NotificationObserver,
public SyncableService {
public: public:
typedef std::map<std::string, std::string> QueryTerms; typedef std::map<std::string, std::string> QueryTerms;
typedef std::vector<const TemplateURL*> TemplateURLVector; typedef std::vector<const TemplateURL*> TemplateURLVector;
// Type for a static function pointer that acts as a time source. // Type for a static function pointer that acts as a time source.
typedef base::Time(TimeProvider)(); typedef base::Time(TimeProvider)();
typedef std::map<std::string, SyncData> SyncDataMap;
// Struct used for initializing the data store with fake data. // Struct used for initializing the data store with fake data.
// Each initializer is mapped to a TemplateURL. // Each initializer is mapped to a TemplateURL.
...@@ -124,6 +129,12 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -124,6 +129,12 @@ class TemplateURLService : public WebDataServiceConsumer,
// retains ownership of it. // retains ownership of it.
const TemplateURL* GetTemplateURLForKeyword(const string16& keyword) const; const TemplateURL* GetTemplateURLForKeyword(const string16& keyword) const;
// Looks up |sync_guid| and returns the element it maps to. Returns NULL if
// the guid was not found.
// The caller should not try to delete the returned pointer; the data store
// retains ownership of it.
const TemplateURL* GetTemplateURLForGUID(const std::string& sync_guid) const;
// Returns the first TemplateURL found with a URL using the specified |host|, // Returns the first TemplateURL found with a URL using the specified |host|,
// or NULL if there are no such TemplateURLs // or NULL if there are no such TemplateURLs
const TemplateURL* GetTemplateURLForHost(const std::string& host) const; const TemplateURL* GetTemplateURLForHost(const std::string& host) const;
...@@ -233,6 +244,34 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -233,6 +244,34 @@ class TemplateURLService : public WebDataServiceConsumer,
const NotificationSource& source, const NotificationSource& source,
const NotificationDetails& details); const NotificationDetails& details);
// SyncableService implementation.
// Returns all syncable TemplateURLs from this model as SyncData. This should
// include every search engine and no Extension keywords.
virtual SyncDataList GetAllSyncData(syncable::ModelType type) const OVERRIDE;
// Process new search engine changes from Sync, merging them into our local
// data. This may send notifications if local search engines are added,
// updated or removed.
virtual SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here,
const SyncChangeList& change_list) OVERRIDE;
// Merge initial search engine data from Sync and push any local changes up
// to Sync. This may send notifications if local search engines are added,
// updated or removed.
virtual SyncError MergeDataAndStartSyncing(
syncable::ModelType type,
const SyncDataList& initial_sync_data,
SyncChangeProcessor* sync_processor) OVERRIDE;
virtual void StopSyncing(syncable::ModelType type) OVERRIDE;
// Processes a local TemplateURL change for Sync. |turl| is the TemplateURL
// that has been modified, and |type| is the Sync ChangeType that took place.
// This may send a new SyncChange to the cloud. If our model has not yet been
// associated with Sync, or if this is triggered by a Sync change, then this
// does nothing.
void ProcessTemplateURLChange(const TemplateURL* turl,
SyncChange::SyncChangeType type);
Profile* profile() const { return profile_; } Profile* profile() const { return profile_; }
void SetSearchEngineDialogSlot(int slot) { void SetSearchEngineDialogSlot(int slot) {
...@@ -246,6 +285,18 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -246,6 +285,18 @@ class TemplateURLService : public WebDataServiceConsumer,
// Registers the preferences used to save a TemplateURL to prefs. // Registers the preferences used to save a TemplateURL to prefs.
static void RegisterUserPrefs(PrefService* prefs); static void RegisterUserPrefs(PrefService* prefs);
// Returns a SyncData with a sync representation of the search engine data
// from |turl|.
static SyncData CreateSyncDataFromTemplateURL(const TemplateURL& turl);
// Returns a heap-allocated TemplateURL, populated by |sync_data|'s fields.
// This does the opposite of CreateSyncDataFromTemplateURL. The caller owns
// the returned TemplateURL*.
static TemplateURL* CreateTemplateURLFromSyncData(const SyncData& sync_data);
// Returns a map mapping Sync GUIDs to pointers to SyncData.
static SyncDataMap CreateGUIDToSyncDataMap(const SyncDataList& sync_data);
#if defined(UNIT_TEST) #if defined(UNIT_TEST)
// Set a different time provider function, such as // Set a different time provider function, such as
// base::MockTimeProvider::StaticNow, when testing calls to base::Time::Now. // base::MockTimeProvider::StaticNow, when testing calls to base::Time::Now.
...@@ -272,9 +323,24 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -272,9 +323,24 @@ class TemplateURLService : public WebDataServiceConsumer,
DontUpdateKeywordSearchForNonReplaceable); DontUpdateKeywordSearchForNonReplaceable);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceTest, ChangeGoogleBaseValue); FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceTest, ChangeGoogleBaseValue);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceTest, MergeDeletesUnusedProviders); FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceTest, MergeDeletesUnusedProviders);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest,
CreateSyncDataFromTemplateURL);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest,
CreateTemplateURLFromSyncData);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest, UniquifyKeyword);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest,
ResolveSyncKeywordConflict);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest,
FindDuplicateOfSyncTemplateURL);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest,
MergeSyncAndLocalURLDuplicates);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest,
CreateGUIDToSyncDataMap);
friend class TemplateURLServiceTestUtil; friend class TemplateURLServiceTestUtil;
typedef std::map<string16, const TemplateURL*> KeywordToTemplateMap; typedef std::map<string16, const TemplateURL*> KeywordToTemplateMap;
typedef std::map<std::string, const TemplateURL*> GUIDToTemplateMap;
// Helper functor for FindMatchingKeywords(), for finding the range of // Helper functor for FindMatchingKeywords(), for finding the range of
// keywords which begin with a prefix. // keywords which begin with a prefix.
...@@ -395,11 +461,51 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -395,11 +461,51 @@ class TemplateURLService : public WebDataServiceConsumer,
const TemplateURL** default_search_provider, const TemplateURL** default_search_provider,
const TemplateURL* default_from_prefs); const TemplateURL* default_from_prefs);
// Resets the sync GUID of the specified TemplateURL and persists the change
// to the database. This does not notify observers.
void ResetTemplateURLGUID(const TemplateURL* url, const std::string& guid);
// Attempts to generate a unique keyword for |turl| based on its original
// keyword. If its keyword is already unique, that is returned. Otherwise, it
// tries to return the autogenerated keyword if that is unique to the Service,
// and finally it repeatedly appends special characters to the keyword until
// it is unique to the Service.
string16 UniquifyKeyword(const TemplateURL& turl) const;
// Given a TemplateURL from Sync, resolves any keyword conflicts by checking
// the local keywords and uniquifying either the cloud keyword or a
// conflicting local keyword (whichever is older). If the cloud TURL is
// changed, then an appropriate SyncChange is appended to |change_list|. If
// a local TURL is changed, the service is updated with the new keyword. If
// there was no conflict to begin with, this does nothing. In the case of tied
// last_modified dates, |sync_turl| wins. Returns true iff there was a
// conflict.
bool ResolveSyncKeywordConflict(TemplateURL* sync_turl,
SyncChangeList& change_list);
// Returns a TemplateURL from the service that has the same keyword and search
// URL as |sync_turl|, if it exists.
const TemplateURL* FindDuplicateOfSyncTemplateURL(
const TemplateURL& sync_turl);
// Given a TemplateURL from the cloud and a local matching duplicate found by
// FindDuplcateOfSyncTemplateURL, merges the two. If |sync_url| is newer, this
// replaces |local_url| with |sync_url| using the service's Remove and Add.
// If |local_url| is newer, this copies the GUID from |sync_url| over to
// |local_url| and adds an update to change_list to notify the server of the
// change.
void MergeSyncAndLocalURLDuplicates(TemplateURL* sync_url,
TemplateURL* local_url,
SyncChangeList& change_list);
NotificationRegistrar registrar_; NotificationRegistrar registrar_;
// Mapping from keyword to the TemplateURL. // Mapping from keyword to the TemplateURL.
KeywordToTemplateMap keyword_to_template_map_; KeywordToTemplateMap keyword_to_template_map_;
// Mapping from Sync GUIDs to the TemplateURL.
GUIDToTemplateMap guid_to_template_map_;
TemplateURLVector template_urls_; TemplateURLVector template_urls_;
ObserverList<TemplateURLServiceObserver> model_observers_; ObserverList<TemplateURLServiceObserver> model_observers_;
...@@ -457,6 +563,19 @@ class TemplateURLService : public WebDataServiceConsumer, ...@@ -457,6 +563,19 @@ class TemplateURLService : public WebDataServiceConsumer,
// Function returning current time in base::Time units. // Function returning current time in base::Time units.
TimeProvider* time_provider_; TimeProvider* time_provider_;
// Do we have an active association between the TemplateURLs and sync models?
// Set in MergeDataAndStartSyncing, reset in StopSyncing. While this is not
// set, we ignore any local search engine changes (when we start syncing we
// will look up the most recent values anyways).
bool models_associated_;
// Whether we're currently processing changes from the syncer. While this is
// true, we ignore any local search engine changes, since we triggered them.
bool processing_syncer_changes_;
// Sync's SyncChange handler. We push all our changes through this.
SyncChangeProcessor* sync_processor_;
DISALLOW_COPY_AND_ASSIGN(TemplateURLService); DISALLOW_COPY_AND_ASSIGN(TemplateURLService);
}; };
......
...@@ -152,6 +152,8 @@ TEST_F(TemplateURLTest, URLRefTestEncoding) { ...@@ -152,6 +152,8 @@ TEST_F(TemplateURLTest, URLRefTestEncoding) {
ASSERT_EQ("http://fooxxutf-8ya/", result.spec()); ASSERT_EQ("http://fooxxutf-8ya/", result.spec());
} }
// Test that setting the prepopulate ID from TemplateURL causes the stored
// TemplateURLRef to handle parsing the URL parameters differently.
TEST_F(TemplateURLTest, SetPrepopulatedAndParse) { TEST_F(TemplateURLTest, SetPrepopulatedAndParse) {
TemplateURL t_url; TemplateURL t_url;
t_url.SetURL("http://foo{fhqwhgads}", 0, 0); t_url.SetURL("http://foo{fhqwhgads}", 0, 0);
......
...@@ -42,3 +42,20 @@ SyncChange::SyncChangeType SyncChange::change_type() const { ...@@ -42,3 +42,20 @@ SyncChange::SyncChangeType SyncChange::change_type() const {
SyncData SyncChange::sync_data() const { SyncData SyncChange::sync_data() const {
return sync_data_; return sync_data_;
} }
// static
std::string SyncChange::ChangeTypeToString(SyncChangeType change_type) {
switch (change_type) {
case ACTION_INVALID:
return "ACTION_INVALID";
case ACTION_ADD:
return "ACTION_ADD";
case ACTION_UPDATE:
return "ACTION_UPDATE";
case ACTION_DELETE:
return "ACTION_DELETE";
default:
NOTREACHED();
}
return std::string();
}
...@@ -45,6 +45,9 @@ class SyncChange { ...@@ -45,6 +45,9 @@ class SyncChange {
SyncChangeType change_type() const; SyncChangeType change_type() const;
SyncData sync_data() const; SyncData sync_data() const;
// Returns a string representation of |change_type|.
static std::string ChangeTypeToString(SyncChangeType change_type);
private: private:
SyncChangeType change_type_; SyncChangeType change_type_;
......
...@@ -1640,6 +1640,7 @@ ...@@ -1640,6 +1640,7 @@
'browser/search_engines/template_url_fetcher_unittest.cc', 'browser/search_engines/template_url_fetcher_unittest.cc',
'browser/search_engines/template_url_service_test_util.cc', 'browser/search_engines/template_url_service_test_util.cc',
'browser/search_engines/template_url_service_test_util.h', 'browser/search_engines/template_url_service_test_util.h',
'browser/search_engines/template_url_service_sync_unittest.cc',
'browser/search_engines/template_url_service_unittest.cc', 'browser/search_engines/template_url_service_unittest.cc',
'browser/search_engines/template_url_parser_unittest.cc', 'browser/search_engines/template_url_parser_unittest.cc',
'browser/search_engines/template_url_prepopulate_data_unittest.cc', 'browser/search_engines/template_url_prepopulate_data_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment