diff options
author | stevet@chromium.org <stevet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-28 14:29:06 +0000 |
---|---|---|
committer | stevet@chromium.org <stevet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-28 14:29:06 +0000 |
commit | c4996f76eb3298229264f2402aeb62f56f8f4790 (patch) | |
tree | 79fae951e6c178d5b8edcad89a7a2c5bf015cdce /chrome/browser | |
parent | f9f39163edfe72a91cdeb3c62d5c209914696a96 (diff) | |
download | chromium_src-c4996f76eb3298229264f2402aeb62f56f8f4790.zip chromium_src-c4996f76eb3298229264f2402aeb62f56f8f4790.tar.gz chromium_src-c4996f76eb3298229264f2402aeb62f56f8f4790.tar.bz2 |
Added last_modified field to TemplateURL and database. Updated unit tests, including refactoring MockTimeProvider out of media/.
BUG=None
TEST=No visible changes. Ensure that changed unittests all pass.
Review URL: http://codereview.chromium.org/7232023
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90764 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
12 files changed, 173 insertions, 43 deletions
diff --git a/chrome/browser/importer/profile_import_process_messages.h b/chrome/browser/importer/profile_import_process_messages.h index d7d9048..8e6d848 100644 --- a/chrome/browser/importer/profile_import_process_messages.h +++ b/chrome/browser/importer/profile_import_process_messages.h @@ -274,6 +274,7 @@ struct ParamTraits<TemplateURL> { WriteParam(m, p.languages()); WriteParam(m, p.input_encodings()); WriteParam(m, p.date_created()); + WriteParam(m, p.last_modified()); WriteParam(m, p.usage_count()); WriteParam(m, p.prepopulate_id()); } @@ -291,6 +292,7 @@ struct ParamTraits<TemplateURL> { std::vector<string16> languages; std::vector<std::string> input_encodings; base::Time date_created; + base::Time last_modified; int usage_count; int prepopulate_id; @@ -332,6 +334,7 @@ struct ParamTraits<TemplateURL> { if (!ReadParam(m, iter, &languages) || !ReadParam(m, iter, &input_encodings) || !ReadParam(m, iter, &date_created) || + !ReadParam(m, iter, &last_modified) || !ReadParam(m, iter, &usage_count) || !ReadParam(m, iter, &prepopulate_id)) return false; @@ -355,6 +358,7 @@ struct ParamTraits<TemplateURL> { } p->set_input_encodings(input_encodings); p->set_date_created(date_created); + p->set_last_modified(last_modified); p->set_usage_count(usage_count); p->set_prepopulate_id(prepopulate_id); return true; diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc index 6a5808b..56db39c 100644 --- a/chrome/browser/search_engines/template_url.cc +++ b/chrome/browser/search_engines/template_url.cc @@ -594,6 +594,7 @@ TemplateURL::TemplateURL() safe_for_autoreplace_(false), id_(0), date_created_(base::Time::Now()), + last_modified_(base::Time::Now()), created_by_policy_(false), usage_count_(0), search_engine_type_(SEARCH_ENGINE_OTHER), diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h index 5fe6a96..fc60674 100644 --- a/chrome/browser/search_engines/template_url.h +++ b/chrome/browser/search_engines/template_url.h @@ -142,6 +142,7 @@ class TemplateURLRef { friend class TemplateURLTest; FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterKnown); FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterUnknown); + FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterReallyUnknown); FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLEmpty); FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLNoTemplateEnd); FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLNoKnownParameters); @@ -425,6 +426,12 @@ class TemplateURL { void set_date_created(base::Time time) { date_created_ = time; } base::Time date_created() const { return date_created_; } + // The last time this keyword was modified by a user, since creation. + // + // NOTE: Like date_created above, this may be 0. + void set_last_modified(base::Time time) { last_modified_ = time; } + base::Time last_modified() const { return last_modified_; } + // True if this TemplateURL was automatically created by the administrator via // group policy. void set_created_by_policy(bool created_by_policy) { @@ -510,6 +517,7 @@ class TemplateURL { std::vector<std::string> input_encodings_; TemplateURLID id_; base::Time date_created_; + base::Time last_modified_; bool created_by_policy_; int usage_count_; SearchEngineType search_engine_type_; diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc index 0a8aa90..587d10e 100644 --- a/chrome/browser/search_engines/template_url_prepopulate_data.cc +++ b/chrome/browser/search_engines/template_url_prepopulate_data.cc @@ -3394,6 +3394,7 @@ TemplateURL* MakePrepopulatedTemplateURL(const wchar_t* name, new_turl->set_show_in_default_list(true); new_turl->set_safe_for_autoreplace(true); new_turl->set_date_created(Time()); + new_turl->set_last_modified(Time()); std::vector<std::string> turl_encodings; turl_encodings.push_back(encoding); new_turl->set_input_encodings(turl_encodings); diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc index 3e99e85..b98278c 100644 --- a/chrome/browser/search_engines/template_url_service.cc +++ b/chrome/browser/search_engines/template_url_service.cc @@ -102,7 +102,8 @@ TemplateURLService::TemplateURLService(Profile* profile) load_handle_(0), default_search_provider_(NULL), is_default_search_managed_(false), - next_id_(1) { + next_id_(1), + time_provider_(&base::Time::Now) { DCHECK(profile_); Init(NULL, 0); } @@ -116,7 +117,8 @@ TemplateURLService::TemplateURLService(const Initializer* initializers, service_(NULL), default_search_provider_(NULL), is_default_search_managed_(false), - next_id_(1) { + next_id_(1), + time_provider_(&base::Time::Now) { Init(initializers, count); } @@ -399,6 +401,7 @@ void TemplateURLService::ResetTemplateURL(const TemplateURL* url, new_url.SetURL(search_url, 0, 0); } new_url.set_safe_for_autoreplace(false); + new_url.set_last_modified(time_provider_()); UpdateNoNotify(url, new_url); NotifyObservers(); } diff --git a/chrome/browser/search_engines/template_url_service.h b/chrome/browser/search_engines/template_url_service.h index f5c6264..d029d86 100644 --- a/chrome/browser/search_engines/template_url_service.h +++ b/chrome/browser/search_engines/template_url_service.h @@ -62,6 +62,8 @@ class TemplateURLService : public WebDataServiceConsumer, public: typedef std::map<std::string, std::string> QueryTerms; typedef std::vector<const TemplateURL*> TemplateURLVector; + // Type for a static function pointer that acts as a time source. + typedef base::Time(TimeProvider)(); // Struct used for initializing the data store with fake data. // Each initializer is mapped to a TemplateURL. @@ -240,6 +242,14 @@ class TemplateURLService : public WebDataServiceConsumer, // Registers the preferences used to save a TemplateURL to prefs. static void RegisterUserPrefs(PrefService* prefs); +#if defined(UNIT_TEST) + // Set a different time provider function, such as + // base::MockTimeProvider::StaticNow, when testing calls to base::Time::Now. + void set_time_provider(TimeProvider* time_provider) { + time_provider_ = time_provider; + } +#endif + protected: // Cover method for the method of the same name on the HistoryService. // url is the one that was visited with the given search terms. @@ -440,6 +450,9 @@ class TemplateURLService : public WebDataServiceConsumer, // List of extension IDs waiting for Load to have keywords registered. std::vector<std::string> pending_extension_ids_; + // Function returning current time in base::Time units. + TimeProvider* time_provider_; + DISALLOW_COPY_AND_ASSIGN(TemplateURLService); }; diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc index d62bb5d..16936e8 100644 --- a/chrome/browser/search_engines/template_url_service_unittest.cc +++ b/chrome/browser/search_engines/template_url_service_unittest.cc @@ -5,6 +5,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_vector.h" +#include "base/test/mock_time_provider.h" #include "base/string_split.h" #include "base/string_util.h" #include "base/threading/thread.h" @@ -28,6 +29,8 @@ using base::Time; using base::TimeDelta; +using ::testing::Return; +using ::testing::StrictMock; // Test the GenerateSearchURL on a thread or the main thread. class TestGenerateSearchURL @@ -93,6 +96,7 @@ static TemplateURL* CreatePreloadedTemplateURL() { GURL favicon_url("http://favicon.url"); t_url->SetFaviconURL(favicon_url); t_url->set_date_created(Time::FromTimeT(100)); + t_url->set_last_modified(Time::FromTimeT(100)); t_url->set_prepopulate_id(999999); return t_url; } @@ -117,7 +121,8 @@ class TemplateURLServiceTest : public testing::Test { const std::string& encodings, const std::string& short_name, bool safe_for_autoreplace, - Time created_date) { + Time created_date, + Time last_modified) { TemplateURL* template_url = new TemplateURL(); template_url->SetURL(url, 0, 0); template_url->SetSuggestionsURL(suggest_url, 0, 0); @@ -129,6 +134,7 @@ class TemplateURLServiceTest : public testing::Test { base::SplitString(encodings, ';', &encodings_vector); template_url->set_input_encodings(encodings_vector); template_url->set_date_created(created_date); + template_url->set_last_modified(last_modified); template_url->set_safe_for_autoreplace(safe_for_autoreplace); model()->Add(template_url); EXPECT_NE(0, template_url->id()); @@ -158,10 +164,11 @@ class TemplateURLServiceTest : public testing::Test { ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace()); ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list()); ASSERT_TRUE(expected.date_created() == actual.date_created()); + ASSERT_TRUE(expected.last_modified() == actual.last_modified()); } - // Checks that the two TemplateURLs are similar. It does not check the id - // and the date_created. Neither pointer should be NULL. + // Checks that the two TemplateURLs are similar. It does not check the id, the + // date_created or the last_modified time. Neither pointer should be NULL. void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) { ASSERT_TRUE(expected != NULL); ASSERT_TRUE(actual != NULL); @@ -387,6 +394,7 @@ TEST_F(TemplateURLServiceTest, AddUpdateRemove) { GURL favicon_url("http://favicon.url"); t_url->SetFaviconURL(favicon_url); t_url->set_date_created(Time::FromTimeT(100)); + t_url->set_last_modified(Time::FromTimeT(100)); t_url->set_safe_for_autoreplace(true); model()->Add(t_url); ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), @@ -410,6 +418,14 @@ TEST_F(TemplateURLServiceTest, AddUpdateRemove) { ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(), NULL)); + // We expect the last_modified time to be updated to the present time on an + // explicit reset. We have to set up the expectation here because ResetModel + // resets the TimeProvider in the TemplateURLService. + StrictMock<base::MockTimeProvider> mock_time; + model()->set_time_provider(&base::MockTimeProvider::StaticNow); + EXPECT_CALL(mock_time, Now()) + .WillOnce(Return(base::Time::FromDoubleT(1337))); + // Mutate an element and verify it succeeded. model()->ResetTemplateURL(loaded_url, ASCIIToUTF16("a"), ASCIIToUTF16("b"), "c"); @@ -427,6 +443,9 @@ TEST_F(TemplateURLServiceTest, AddUpdateRemove) { loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("b")); ASSERT_TRUE(loaded_url != NULL); AssertEquals(cloned_url, *loaded_url); + // We changed a TemplateURL in the service, so ensure that the time was + // updated. + ASSERT_EQ(loaded_url->last_modified(), base::Time::FromDoubleT(1337)); // Remove an element and verify it succeeded. model()->Remove(loaded_url); @@ -492,21 +511,23 @@ TEST_F(TemplateURLServiceTest, ClearBrowsingData_Keywords) { // Create one with a 0 time. AddKeywordWithDate("key1", false, "http://foo1", "http://suggest1", - "http://icon1", "UTF-8;UTF-16", "name1", true, Time()); + "http://icon1", "UTF-8;UTF-16", "name1", true, Time(), + Time()); // Create one for now and +/- 1 day. AddKeywordWithDate("key2", false, "http://foo2", "http://suggest2", "http://icon2", "UTF-8;UTF-16", "name2", true, - now - one_day); + now - one_day, Time()); AddKeywordWithDate("key3", false, "http://foo3", "", "", "", "name3", - true, now); + true, now, Time()); AddKeywordWithDate("key4", false, "http://foo4", "", "", "", "name4", - true, now + one_day); + true, now + one_day, Time()); // Try the other three states. AddKeywordWithDate("key5", false, "http://foo5", "http://suggest5", - "http://icon5", "UTF-8;UTF-16", "name5", false, now); + "http://icon5", "UTF-8;UTF-16", "name5", false, now, + Time()); AddKeywordWithDate("key6", false, "http://foo6", "http://suggest6", "http://icon6", "UTF-8;UTF-16", "name6", false, - month_ago); + month_ago, Time()); // We just added a few items, validate them. EXPECT_EQ(6U, model()->GetTemplateURLs().size()); @@ -553,11 +574,17 @@ TEST_F(TemplateURLServiceTest, Reset) { GURL favicon_url("http://favicon.url"); t_url->SetFaviconURL(favicon_url); t_url->set_date_created(Time::FromTimeT(100)); + t_url->set_last_modified(Time::FromTimeT(100)); model()->Add(t_url); VerifyObserverCount(1); BlockTillServiceProcessesRequests(); + StrictMock<base::MockTimeProvider> mock_time; + model()->set_time_provider(&base::MockTimeProvider::StaticNow); + EXPECT_CALL(mock_time, Now()) + .WillOnce(Return(base::Time::FromDoubleT(1337))); + // Reset the short name, keyword, url and make sure it takes. const string16 new_short_name(ASCIIToUTF16("a")); const string16 new_keyword(ASCIIToUTF16("b")); @@ -581,6 +608,7 @@ TEST_F(TemplateURLServiceTest, Reset) { const TemplateURL* read_url = model()->GetTemplateURLForKeyword(new_keyword); ASSERT_TRUE(read_url); AssertEquals(last_url, *read_url); + ASSERT_EQ(read_url->last_modified(), base::Time::FromDoubleT(1337)); } TEST_F(TemplateURLServiceTest, DefaultSearchProvider) { @@ -588,7 +616,8 @@ TEST_F(TemplateURLServiceTest, DefaultSearchProvider) { VerifyLoad(); const size_t initial_count = model()->GetTemplateURLs().size(); TemplateURL* t_url = AddKeywordWithDate("key1", false, "http://foo1", - "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time()); + "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time(), + Time()); test_util_.ResetObserverCount(); model()->SetDefaultSearchProvider(t_url); @@ -620,7 +649,7 @@ TEST_F(TemplateURLServiceTest, TemplateURLWithNoKeyword) { const size_t initial_count = model()->GetTemplateURLs().size(); AddKeywordWithDate("", false, "http://foo1", "http://sugg1", - "http://icon1", "UTF-8;UTF-16", "name1", true, Time()); + "http://icon1", "UTF-8;UTF-16", "name1", true, Time(), Time()); // We just added a few items, validate them. ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size()); @@ -644,7 +673,8 @@ TEST_F(TemplateURLServiceTest, CantReplaceWithSameKeyword) { ChangeModelToLoadState(); ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL(), NULL)); TemplateURL* t_url = AddKeywordWithDate("foo", false, "http://foo1", - "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time()); + "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time(), + Time()); // Can still replace, newly added template url is marked safe to replace. ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), @@ -653,7 +683,7 @@ TEST_F(TemplateURLServiceTest, CantReplaceWithSameKeyword) { // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should // no longer be replaceable. model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(), - t_url->url()->url()); + t_url->url()->url()); ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL("http://foo2"), NULL)); @@ -664,7 +694,8 @@ TEST_F(TemplateURLServiceTest, CantReplaceWithSameHosts) { ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL("http://foo.com"), NULL)); TemplateURL* t_url = AddKeywordWithDate("foo", false, "http://foo.com", - "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time()); + "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time(), + Time()); // Can still replace, newly added template url is marked safe to replace. ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"), @@ -673,7 +704,7 @@ TEST_F(TemplateURLServiceTest, CantReplaceWithSameHosts) { // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should // no longer be replaceable. model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(), - t_url->url()->url()); + t_url->url()->url()); ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"), GURL("http://foo.com"), NULL)); @@ -699,6 +730,7 @@ TEST_F(TemplateURLServiceTest, DefaultSearchProviderLoadedFromPrefs) { template_url->set_short_name(ASCIIToUTF16("a")); template_url->set_safe_for_autoreplace(true); template_url->set_date_created(Time::FromTimeT(100)); + template_url->set_last_modified(Time::FromTimeT(100)); model()->Add(template_url); @@ -799,7 +831,8 @@ TEST_F(TemplateURLServiceTest, UpdateKeywordSearchTermsForURL) { ChangeModelToLoadState(); AddKeywordWithDate("x", false, "http://x/foo?q={searchTerms}", - "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name", false, Time()); + "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name", false, Time(), + Time()); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { history::URLVisitedDetails details; @@ -821,7 +854,7 @@ TEST_F(TemplateURLServiceTest, DontUpdateKeywordSearchForNonReplaceable) { ChangeModelToLoadState(); AddKeywordWithDate("x", false, "http://x/foo", "http://sugg1", - "http://icon1", "UTF-8;UTF-16", "name", false, Time()); + "http://icon1", "UTF-8;UTF-16", "name", false, Time(), Time()); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { history::URLVisitedDetails details; @@ -840,7 +873,7 @@ TEST_F(TemplateURLServiceTest, ChangeGoogleBaseValue) { SetGoogleBaseURL("http://google.com/"); const TemplateURL* t_url = AddKeywordWithDate("", true, "{google:baseURL}?q={searchTerms}", "http://sugg1", "http://icon1", - "UTF-8;UTF-16", "name", false, Time()); + "UTF-8;UTF-16", "name", false, Time(), Time()); ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com")); EXPECT_EQ("google.com", t_url->url()->GetHost()); EXPECT_EQ(ASCIIToUTF16("google.com"), t_url->keyword()); @@ -887,7 +920,7 @@ TEST_F(TemplateURLServiceTest, GenerateVisitOnKeyword) { TemplateURL* t_url = AddKeywordWithDate( "keyword", false, "http://foo.com/foo?query={searchTerms}", "http://sugg1", "http://icon1", "UTF-8;UTF-16", "keyword", - true, base::Time::Now()); + true, base::Time::Now(), base::Time::Now()); // Add a visit that matches the url of the keyword. HistoryService* history = @@ -1102,7 +1135,7 @@ TEST_F(TemplateURLServiceTest, TestManagedDefaultSearch) { // Set a regular default search provider. TemplateURL* regular_default = AddKeywordWithDate("key1", false, "http://foo1", "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", - true, Time()); + true, Time(), Time()); VerifyObserverCount(1); model()->SetDefaultSearchProvider(regular_default); // Adding the URL and setting the default search provider should have caused @@ -1196,7 +1229,8 @@ TEST_F(TemplateURLServiceTest, TestManagedDefaultSearch) { RemoveManagedDefaultSearchPreferences(); ResetModel(true); TemplateURL* t_url = AddKeywordWithDate("key1", false, "http://foo1", - "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time()); + "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time(), + Time()); model()->SetDefaultSearchProvider(t_url); EXPECT_EQ(t_url, model()->GetDefaultSearchProvider()); diff --git a/chrome/browser/webdata/keyword_table.cc b/chrome/browser/webdata/keyword_table.cc index 2e31a8a..5d93869 100644 --- a/chrome/browser/webdata/keyword_table.cc +++ b/chrome/browser/webdata/keyword_table.cc @@ -18,7 +18,7 @@ using base::Time; namespace { // ID of the url column in keywords. -const int kUrlIdPosition = 16; +const int kUrlIdPosition = 17; // Keys used in the meta table. const char* kDefaultSearchProviderKey = "Default Search Provider ID"; @@ -54,6 +54,7 @@ void BindURLToStatement(const TemplateURL& url, sql::Statement* s) { s->BindBool(14, url.created_by_policy()); s->BindString(15, url.instant_url() ? url.instant_url()->url() : std::string()); + s->BindInt64(16, url.last_modified().ToTimeT()); } } // anonymous namespace @@ -78,7 +79,8 @@ bool KeywordTable::Init() { "autogenerate_keyword INTEGER DEFAULT 0," "logo_id INTEGER DEFAULT 0," "created_by_policy INTEGER DEFAULT 0," - "instant_url VARCHAR)")) { + "instant_url VARCHAR," + "last_modified INTEGER DEFAULT 0)")) { NOTREACHED(); return false; } @@ -99,8 +101,8 @@ bool KeywordTable::AddKeyword(const TemplateURL& url) { "originating_url, date_created, usage_count, input_encodings, " "show_in_default_list, suggest_url, prepopulate_id, " "autogenerate_keyword, logo_id, created_by_policy, instant_url, " - "id) VALUES " - "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); + "last_modified, id) VALUES " + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); if (!s) { NOTREACHED() << "Statement prepare failed"; return false; @@ -132,7 +134,7 @@ bool KeywordTable::GetKeywords(std::vector<TemplateURL*>* urls) { "safe_for_autoreplace, originating_url, date_created, " "usage_count, input_encodings, show_in_default_list, " "suggest_url, prepopulate_id, autogenerate_keyword, logo_id, " - "created_by_policy, instant_url " + "created_by_policy, instant_url, last_modified " "FROM keywords ORDER BY id ASC")); if (!s) { NOTREACHED() << "Statement prepare failed"; @@ -183,6 +185,8 @@ bool KeywordTable::GetKeywords(std::vector<TemplateURL*>* urls) { template_url->SetInstantURL(s.ColumnString(16), 0, 0); + template_url->set_last_modified(Time::FromTimeT(s.ColumnInt64(17))); + urls->push_back(template_url); } return s.Succeeded(); @@ -197,7 +201,8 @@ bool KeywordTable::UpdateKeyword(const TemplateURL& url) { "safe_for_autoreplace=?, originating_url=?, date_created=?, " "usage_count=?, input_encodings=?, show_in_default_list=?, " "suggest_url=?, prepopulate_id=?, autogenerate_keyword=?, " - "logo_id=?, created_by_policy=?, instant_url=? WHERE id=?")); + "logo_id=?, created_by_policy=?, instant_url=?, last_modified=? " + "WHERE id=?")); if (!s) { NOTREACHED() << "Statement prepare failed"; return false; @@ -291,3 +296,8 @@ bool KeywordTable::MigrateToVersion29InstantUrlToSupportsInstant() { return true; } + +bool KeywordTable::MigrateToVersion38AddLastModifiedColumn() { + return db_->Execute( + "ALTER TABLE keywords ADD COLUMN last_modified INTEGER DEFAULT 0"); +} diff --git a/chrome/browser/webdata/keyword_table.h b/chrome/browser/webdata/keyword_table.h index fc31433..dda570d 100644 --- a/chrome/browser/webdata/keyword_table.h +++ b/chrome/browser/webdata/keyword_table.h @@ -47,6 +47,8 @@ class Time; // in version 26. // instant_url See TemplateURL::instant_url. This was added // in version 29. +// last_modified See TemplateURL::last_modified. This was added in +// version 38. // class KeywordTable : public WebDatabaseTable { public: @@ -87,6 +89,7 @@ class KeywordTable : public WebDatabaseTable { bool MigrateToVersion26AddCreatedByPolicyColumn(); bool MigrateToVersion28SupportsInstantColumn(); bool MigrateToVersion29InstantUrlToSupportsInstant(); + bool MigrateToVersion38AddLastModifiedColumn(); private: DISALLOW_COPY_AND_ASSIGN(KeywordTable); diff --git a/chrome/browser/webdata/keyword_table_unittest.cc b/chrome/browser/webdata/keyword_table_unittest.cc index e2ae690..a668ae1 100644 --- a/chrome/browser/webdata/keyword_table_unittest.cc +++ b/chrome/browser/webdata/keyword_table_unittest.cc @@ -13,6 +13,7 @@ #include "testing/gtest/include/gtest/gtest.h" using base::Time; +using base::TimeDelta; class KeywordTableTest : public testing::Test { public: @@ -71,6 +72,8 @@ TEST_F(KeywordTableTest, Keywords) { template_url.set_safe_for_autoreplace(true); Time created_time = Time::Now(); template_url.set_date_created(created_time); + Time last_modified_time = created_time + TimeDelta::FromSeconds(10); + template_url.set_last_modified(last_modified_time); template_url.set_show_in_default_list(true); template_url.set_originating_url(originating_url); template_url.set_usage_count(32); @@ -103,6 +106,9 @@ TEST_F(KeywordTableTest, Keywords) { // The database stores time only at the resolution of a second. EXPECT_EQ(created_time.ToTimeT(), restored_url->date_created().ToTimeT()); + EXPECT_EQ(last_modified_time.ToTimeT(), + restored_url->last_modified().ToTimeT()); + EXPECT_TRUE(restored_url->show_in_default_list()); EXPECT_EQ(GetID(&template_url), GetID(restored_url)); diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc index 45a06a8..9ad3613 100644 --- a/chrome/browser/webdata/web_database.cc +++ b/chrome/browser/webdata/web_database.cc @@ -16,8 +16,8 @@ namespace { // Current version number. Note: when changing the current version number, // corresponding changes must happen in the unit tests, and new migration test // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. -const int kCurrentVersionNumber = 37; -const int kCompatibleVersionNumber = 37; +const int kCurrentVersionNumber = 38; +const int kCompatibleVersionNumber = 38; // Change the version number and possibly the compatibility version of // |meta_table_|. @@ -279,6 +279,13 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() { ChangeVersion(&meta_table_, 37, true); // FALL THROUGH + case 37: + if (!keyword_table_->MigrateToVersion38AddLastModifiedColumn()) + return FailedMigrationTo(38); + + ChangeVersion(&meta_table_, 38, true); + // FALL THROUGH + // Add successive versions here. Each should set the version number and // compatible version number as appropriate, then fall through to the next // case. diff --git a/chrome/browser/webdata/web_database_migration_unittest.cc b/chrome/browser/webdata/web_database_migration_unittest.cc index 19613d4..bb6dad0 100644 --- a/chrome/browser/webdata/web_database_migration_unittest.cc +++ b/chrome/browser/webdata/web_database_migration_unittest.cc @@ -41,7 +41,7 @@ void AutofillProfile31FromStatement(const sql::Statement& s, *unique_id = s.ColumnInt(1); profile->SetInfo(NAME_FIRST, s.ColumnString16(2)); profile->SetInfo(NAME_MIDDLE, s.ColumnString16(3)); - profile->SetInfo(NAME_LAST,s.ColumnString16(4)); + profile->SetInfo(NAME_LAST, s.ColumnString16(4)); profile->SetInfo(EMAIL_ADDRESS, s.ColumnString16(5)); profile->SetInfo(COMPANY_NAME, s.ColumnString16(6)); profile->SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(7)); @@ -186,7 +186,7 @@ class WebDatabaseMigrationTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest); }; -const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 37; +const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 38; void WebDatabaseMigrationTest::LoadDatabase(const FilePath::StringType& file) { std::string contents; @@ -454,7 +454,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) { // Check version. EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - // |keywords| |logo_id| column should have been added. + // |keywords| |created_by_policy| column should have been added. EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy")); } @@ -587,7 +587,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringIDs) { // Check version. EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - // |keywords| |logo_id| column should have been added. + // |keywords| |created_by_policy| column should have been added. EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy")); EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address")); @@ -601,7 +601,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringIDs) { EXPECT_EQ("Jack", s.ColumnString(1)); EXPECT_EQ(2, s.ColumnInt(2)); EXPECT_EQ(2012, s.ColumnInt(3)); - // Column 5 is encrypted credit card number blob. + // Column 5 is encrypted credit card number blo b. // Column 6 is date_modified. } } @@ -1169,7 +1169,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) { // John Doe fax. ASSERT_TRUE(s4.Step()); EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s4.ColumnString(0)); - EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means phone. + EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means phone. EXPECT_EQ(ASCIIToUTF16("4153334444"), s4.ColumnString16(2)); // John P. Doe phone. @@ -1183,25 +1183,25 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) { // 2 Main Street phone. ASSERT_TRUE(s4.Step()); EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0)); - EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. + EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2)); // 2 Main Street fax. ASSERT_TRUE(s4.Step()); EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0)); - EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax. + EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax. EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2)); // 2 Main St phone. ASSERT_TRUE(s4.Step()); EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0)); - EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. + EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2)); // 2 Main St fax. ASSERT_TRUE(s4.Step()); EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0)); - EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax. + EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax. EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2)); // Note no phone or fax for Alfred E Newman. @@ -1209,13 +1209,13 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) { // 3 Main St phone. ASSERT_TRUE(s4.Step()); EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0)); - EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. + EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone. EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2)); // 2 Main St fax. ASSERT_TRUE(s4.Step()); EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0)); - EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax. + EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax. EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2)); // Should be all. @@ -1424,3 +1424,43 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion35ToCurrent) { ASSERT_FALSE(s2.Step()); } } + +// Tests that the |keywords| |last_modified| column gets added to the schema for +// a version 37 database. +TEST_F(WebDatabaseMigrationTest, MigrateVersion37ToCurrent) { + // This schema is taken from a build prior to the addition of the |keywords| + // |last_modified| column. + ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_37.sql"))); + + // Verify pre-conditions. These are expectations for version 37 of the + // database. + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + + // Columns existing and not existing before current version. + ASSERT_TRUE(connection.DoesColumnExist("keywords", "id")); + ASSERT_FALSE(connection.DoesColumnExist("keywords", "last_modified")); + } + + // Load the database via the WebDatabase class and migrate the database to + // the current version. + { + WebDatabase db; + ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath())); + } + + // Verify post-conditions. These are expectations for current version of the + // database. + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + + // Check version. + EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); + + // |keywords| |last_modified| column should have been added. + EXPECT_TRUE(connection.DoesColumnExist("keywords", "id")); + EXPECT_TRUE(connection.DoesColumnExist("keywords", "last_modified")); + } +} |