Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(596)

Side by Side Diff: chrome/browser/history/in_memory_url_index_unittest.cc

Issue 10872032: Revert 152946 - Replace HistoryQuickProvider protobuf-based caching with an SQLite-based database. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/memory/ref_counted.h" 5 #include <algorithm>
6 #include <fstream>
7
8 #include "base/file_path.h"
9 #include "base/file_util.h"
10 #include "base/message_loop.h"
11 #include "base/path_service.h"
12 #include "base/scoped_temp_dir.h"
13 #include "base/string16.h"
6 #include "base/string_util.h" 14 #include "base/string_util.h"
7 #include "base/stringprintf.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/autocomplete/autocomplete_provider.h" 16 #include "chrome/browser/autocomplete/autocomplete_provider.h"
11 #include "chrome/browser/bookmarks/bookmark_model.h" 17 #include "chrome/browser/history/history.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 18 #include "chrome/browser/history/history_backend.h"
19 #include "chrome/browser/history/history_database.h"
13 #include "chrome/browser/history/history_notifications.h" 20 #include "chrome/browser/history/history_notifications.h"
14 #include "chrome/browser/history/in_memory_url_cache_database.h" 21 #include "chrome/browser/history/history_service_factory.h"
15 #include "chrome/browser/history/in_memory_url_index_base_unittest.h" 22 #include "chrome/browser/history/in_memory_url_index.h"
16 #include "chrome/browser/history/in_memory_url_index_types.h" 23 #include "chrome/browser/history/in_memory_url_index_types.h"
17 #include "chrome/browser/history/url_index_private_data.h" 24 #include "chrome/browser/history/url_index_private_data.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "chrome/common/chrome_notification_types.h" 25 #include "chrome/common/chrome_notification_types.h"
20 #include "chrome/test/base/ui_test_utils.h" 26 #include "chrome/common/chrome_paths.h"
21 #include "content/public/browser/notification_service.h" 27 #include "chrome/test/base/testing_profile.h"
28 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_source.h" 29 #include "content/public/browser/notification_source.h"
23 #include "sql/connection.h" 30 #include "content/public/test/test_browser_thread.h"
24 #include "third_party/sqlite/sqlite3.h" 31 #include "sql/transaction.h"
25 32 #include "testing/gtest/include/gtest/gtest.h"
26 using history::String16SetFromString16; 33
27 34 using content::BrowserThread;
28 //------------------------------------------------------------------------------ 35
29 36 // The test version of the history url database table ('url') is contained in
30 // This class overrides the standard TestingProfile's disabling of the 37 // a database file created from a text file('url_history_provider_test.db.txt').
31 // InMemoryURLIndexCacheDatabase. 38 // The only difference between this table and a live 'urls' table from a
32 class CacheTestingProfile : public TestingProfile { 39 // profile is that the last_visit_time column in the test table contains a
40 // number specifying the number of days relative to 'today' to which the
41 // absolute time should be set during the test setup stage.
42 //
43 // The format of the test database text file is of a SQLite .dump file.
44 // Note that only lines whose first character is an upper-case letter are
45 // processed when creating the test database.
46
47 namespace history {
48
49 // -----------------------------------------------------------------------------
50
51 // Observer class so the unit tests can wait while the cache is being saved.
52 class CacheFileSaverObserver : public InMemoryURLIndex::SaveCacheObserver {
33 public: 53 public:
34 // Creates a testing profile but enables the cache database. 54 explicit CacheFileSaverObserver(MessageLoop* loop);
35 bool InitHistoryService(HistoryService* history_service, 55 virtual void OnCacheSaveFinished(bool succeeded) OVERRIDE;
36 bool no_db) OVERRIDE; 56
57 MessageLoop* loop_;
58 bool succeeded_;
59 DISALLOW_COPY_AND_ASSIGN(CacheFileSaverObserver);
37 }; 60 };
38 61
39 bool CacheTestingProfile::InitHistoryService(HistoryService* history_service, 62 CacheFileSaverObserver::CacheFileSaverObserver(MessageLoop* loop)
40 bool no_db) { 63 : loop_(loop),
41 DCHECK(history_service); 64 succeeded_(false) {
42 return history_service->Init(GetPath(), 65 DCHECK(loop);
43 reinterpret_cast<BookmarkService*>( 66 }
44 BookmarkModelFactory::GetForProfile(this)), 67
45 no_db, false); 68 void CacheFileSaverObserver::OnCacheSaveFinished(bool succeeded) {
46 } 69 succeeded_ = succeeded;
47 70 loop_->Quit();
48 namespace history { 71 }
72
73 // Observer class so the unit tests can wait while the cache is being restored.
74 class CacheFileReaderObserver : public InMemoryURLIndex::RestoreCacheObserver {
75 public:
76 explicit CacheFileReaderObserver(MessageLoop* loop);
77 virtual void OnCacheRestoreFinished(bool succeeded) OVERRIDE;
78
79 MessageLoop* loop_;
80 bool succeeded_;
81 DISALLOW_COPY_AND_ASSIGN(CacheFileReaderObserver);
82 };
83
84 CacheFileReaderObserver::CacheFileReaderObserver(MessageLoop* loop)
85 : loop_(loop),
86 succeeded_(false) {
87 DCHECK(loop);
88 }
89
90 void CacheFileReaderObserver::OnCacheRestoreFinished(bool succeeded) {
91 succeeded_ = succeeded;
92 loop_->Quit();
93 }
49 94
50 // ----------------------------------------------------------------------------- 95 // -----------------------------------------------------------------------------
51 96
52 // Creates a URLRow with basic data for |url|, |title|, |visit_count|, 97 class InMemoryURLIndexTest : public testing::Test {
53 // |typed_count| and |id|. |last_visit_ago| gives the number of days from now 98 public:
54 // to which to set the URL's last_visit. 99 InMemoryURLIndexTest();
55 URLRow MakeURLRowWithID(const char* url, 100
56 const char* title,
57 int visit_count,
58 int last_visit_ago,
59 int typed_count,
60 URLID id);
61
62 class InMemoryURLIndexTest : public InMemoryURLIndexBaseTest {
63 protected: 101 protected:
64 void SetUp() OVERRIDE; 102 // Test setup.
65 103 virtual void SetUp();
66 // Provides custom test data file name. 104
67 virtual FilePath::StringType TestDBName() const OVERRIDE; 105 // Allows the database containing the test data to be customized by
106 // subclasses.
107 virtual FilePath::StringType TestDBName() const;
108
109 #if 0
110 // Convenience function to create a URLRow with basic data for |url|, |title|,
111 // |visit_count|, and |typed_count|. |last_visit_ago| gives the number of
112 // days from now to set the URL's last_visit.
113 URLRow MakeURLRow(const char* url,
114 const char* title,
115 int visit_count,
116 int last_visit_ago,
117 int typed_count);
118
119 // Convenience functions for easily creating vectors of search terms.
120 String16Vector Make1Term(const char* term) const;
121 String16Vector Make2Terms(const char* term_1, const char* term_2) const;
122
123 // Convenience function for GetTopicalityScore() that builds the
124 // term match and word break information automatically that are needed
125 // to call GetTopicalityScore(). It only works for scoring a single term,
126 // not multiple terms.
127 float GetTopicalityScoreOfTermAgainstURLAndTitle(const string16& term,
128 const string16& url,
129 const string16& title);
130 #endif
68 131
69 // Validates that the given |term| is contained in |cache| and that it is 132 // Validates that the given |term| is contained in |cache| and that it is
70 // marked as in-use. 133 // marked as in-use.
71 void CheckTerm(const URLIndexPrivateData::SearchTermCacheMap& cache, 134 void CheckTerm(const URLIndexPrivateData::SearchTermCacheMap& cache,
72 string16 term) const; 135 string16 term) const;
136
137 // Pass-through function to simplify our friendship with HistoryService.
138 sql::Connection& GetDB();
139
140 // Pass-through functions to simplify our friendship with InMemoryURLIndex.
141 URLIndexPrivateData* GetPrivateData() const;
142 void ClearPrivateData();
143 void set_history_dir(const FilePath& dir_path);
144 bool GetCacheFilePath(FilePath* file_path) const;
145 void PostRestoreFromCacheFileTask();
146 void PostSaveToCacheFileTask();
147 void Observe(int notification_type,
148 const content::NotificationSource& source,
149 const content::NotificationDetails& details);
150 const std::set<std::string>& scheme_whitelist();
151
152
153 // Pass-through functions to simplify our friendship with URLIndexPrivateData.
154 bool UpdateURL(const URLRow& row);
155 bool DeleteURL(const GURL& url);
156
157 // Data verification helper functions.
158 void ExpectPrivateDataNotEmpty(const URLIndexPrivateData& data);
159 void ExpectPrivateDataEmpty(const URLIndexPrivateData& data);
160 void ExpectPrivateDataEqual(const URLIndexPrivateData& expected,
161 const URLIndexPrivateData& actual);
162
163 MessageLoopForUI message_loop_;
164 content::TestBrowserThread ui_thread_;
165 content::TestBrowserThread file_thread_;
166 TestingProfile profile_;
167
168 scoped_ptr<InMemoryURLIndex> url_index_;
169 HistoryDatabase* history_database_;
73 }; 170 };
74 171
172 InMemoryURLIndexTest::InMemoryURLIndexTest()
173 : ui_thread_(content::BrowserThread::UI, &message_loop_),
174 file_thread_(content::BrowserThread::FILE, &message_loop_) {
175 }
176
177 sql::Connection& InMemoryURLIndexTest::GetDB() {
178 return history_database_->GetDB();
179 }
180
181 URLIndexPrivateData* InMemoryURLIndexTest::GetPrivateData() const {
182 DCHECK(url_index_->private_data());
183 return url_index_->private_data();
184 }
185
186 void InMemoryURLIndexTest::ClearPrivateData() {
187 return url_index_->ClearPrivateData();
188 }
189
190 void InMemoryURLIndexTest::set_history_dir(const FilePath& dir_path) {
191 return url_index_->set_history_dir(dir_path);
192 }
193
194 bool InMemoryURLIndexTest::GetCacheFilePath(FilePath* file_path) const {
195 DCHECK(file_path);
196 return url_index_->GetCacheFilePath(file_path);
197 }
198
199 void InMemoryURLIndexTest::PostRestoreFromCacheFileTask() {
200 url_index_->PostRestoreFromCacheFileTask();
201 }
202
203 void InMemoryURLIndexTest::PostSaveToCacheFileTask() {
204 url_index_->PostSaveToCacheFileTask();
205 }
206
207 void InMemoryURLIndexTest::Observe(
208 int notification_type,
209 const content::NotificationSource& source,
210 const content::NotificationDetails& details) {
211 url_index_->Observe(notification_type, source, details);
212 }
213
214 const std::set<std::string>& InMemoryURLIndexTest::scheme_whitelist() {
215 return url_index_->scheme_whitelist();
216 }
217
218 bool InMemoryURLIndexTest::UpdateURL(const URLRow& row) {
219 return GetPrivateData()->UpdateURL(row, url_index_->languages_,
220 url_index_->scheme_whitelist_);
221 }
222
223 bool InMemoryURLIndexTest::DeleteURL(const GURL& url) {
224 return GetPrivateData()->DeleteURL(url);
225 }
226
75 void InMemoryURLIndexTest::SetUp() { 227 void InMemoryURLIndexTest::SetUp() {
76 // Set things up without enabling the cache database. 228 // We cannot access the database until the backend has been loaded.
77 InMemoryURLIndexBaseTest::SetUp(); 229 profile_.CreateHistoryService(true, false);
78 LoadIndex(); 230 profile_.CreateBookmarkModel(true);
231 profile_.BlockUntilBookmarkModelLoaded();
232 profile_.BlockUntilHistoryProcessesPendingRequests();
233 HistoryService* history_service =
234 HistoryServiceFactory::GetForProfile(&profile_,
235 Profile::EXPLICIT_ACCESS);
236 ASSERT_TRUE(history_service);
237 HistoryBackend* backend = history_service->history_backend_.get();
238 history_database_ = backend->db();
239
240 // Create and populate a working copy of the URL history database.
241 FilePath history_proto_path;
242 PathService::Get(chrome::DIR_TEST_DATA, &history_proto_path);
243 history_proto_path = history_proto_path.Append(
244 FILE_PATH_LITERAL("History"));
245 history_proto_path = history_proto_path.Append(TestDBName());
246 EXPECT_TRUE(file_util::PathExists(history_proto_path));
247
248 std::ifstream proto_file(history_proto_path.value().c_str());
249 static const size_t kCommandBufferMaxSize = 2048;
250 char sql_cmd_line[kCommandBufferMaxSize];
251
252 sql::Connection& db(GetDB());
253 ASSERT_TRUE(db.is_open());
254 {
255 sql::Transaction transaction(&db);
256 transaction.Begin();
257 while (!proto_file.eof()) {
258 proto_file.getline(sql_cmd_line, kCommandBufferMaxSize);
259 if (!proto_file.eof()) {
260 // We only process lines which begin with a upper-case letter.
261 // TODO(mrossetti): Can iswupper() be used here?
262 if (sql_cmd_line[0] >= 'A' && sql_cmd_line[0] <= 'Z') {
263 std::string sql_cmd(sql_cmd_line);
264 sql::Statement sql_stmt(db.GetUniqueStatement(sql_cmd_line));
265 EXPECT_TRUE(sql_stmt.Run());
266 }
267 }
268 }
269 transaction.Commit();
270 }
271 proto_file.close();
272
273 // Update the last_visit_time table column
274 // such that it represents a time relative to 'now'.
275 sql::Statement statement(db.GetUniqueStatement(
276 "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls;"));
277 ASSERT_TRUE(statement.is_valid());
278 base::Time time_right_now = base::Time::NowFromSystemTime();
279 base::TimeDelta day_delta = base::TimeDelta::FromDays(1);
280 {
281 sql::Transaction transaction(&db);
282 transaction.Begin();
283 while (statement.Step()) {
284 URLRow row;
285 history_database_->FillURLRow(statement, &row);
286 base::Time last_visit = time_right_now;
287 for (int64 i = row.last_visit().ToInternalValue(); i > 0; --i)
288 last_visit -= day_delta;
289 row.set_last_visit(last_visit);
290 history_database_->UpdateURLRow(row.id(), row);
291 }
292 transaction.Commit();
293 }
294
295 url_index_.reset(
296 new InMemoryURLIndex(&profile_, FilePath(), "en,ja,hi,zh"));
297 url_index_->Init();
298 url_index_->RebuildFromHistory(history_database_);
79 } 299 }
80 300
81 FilePath::StringType InMemoryURLIndexTest::TestDBName() const { 301 FilePath::StringType InMemoryURLIndexTest::TestDBName() const {
82 return FILE_PATH_LITERAL("url_history_provider_test.db.txt"); 302 return FILE_PATH_LITERAL("url_history_provider_test.db.txt");
83 } 303 }
84 304
85 URLRow MakeURLRowWithID(const char* url, 305 #if 0
86 const char* title, 306 URLRow InMemoryURLIndexTest::MakeURLRow(const char* url,
87 int visit_count, 307 const char* title,
88 int last_visit_ago, 308 int visit_count,
89 int typed_count, 309 int last_visit_ago,
90 URLID id) { 310 int typed_count) {
91 URLRow row(GURL(url), id); 311 URLRow row(GURL(url), 0);
92 row.set_title(UTF8ToUTF16(title)); 312 row.set_title(UTF8ToUTF16(title));
93 row.set_visit_count(visit_count); 313 row.set_visit_count(visit_count);
94 row.set_typed_count(typed_count); 314 row.set_typed_count(typed_count);
95 row.set_last_visit(base::Time::NowFromSystemTime() - 315 row.set_last_visit(base::Time::NowFromSystemTime() -
96 base::TimeDelta::FromDays(last_visit_ago)); 316 base::TimeDelta::FromDays(last_visit_ago));
97 return row; 317 return row;
98 } 318 }
99 319
320 String16Vector InMemoryURLIndexTest::Make1Term(const char* term) const {
321 String16Vector original_terms;
322 original_terms.push_back(UTF8ToUTF16(term));
323 return original_terms;
324 }
325
326 String16Vector InMemoryURLIndexTest::Make2Terms(const char* term_1,
327 const char* term_2) const {
328 String16Vector original_terms;
329 original_terms.push_back(UTF8ToUTF16(term_1));
330 original_terms.push_back(UTF8ToUTF16(term_2));
331 return original_terms;
332 }
333
334 float InMemoryURLIndexTest::GetTopicalityScoreOfTermAgainstURLAndTitle(
335 const string16& term,
336 const string16& url,
337 const string16& title) {
338 TermMatches url_matches = MatchTermInString(term, url, 0);
339 TermMatches title_matches = MatchTermInString(term, title, 0);
340 RowWordStarts word_starts;
341 String16SetFromString16(url, &word_starts.url_word_starts_);
342 String16SetFromString16(title, &word_starts.title_word_starts_);
343 return ScoredHistoryMatch::GetTopicalityScore(
344 1, url, url_matches, title_matches, word_starts);
345 }
346 #endif
347
100 void InMemoryURLIndexTest::CheckTerm( 348 void InMemoryURLIndexTest::CheckTerm(
101 const URLIndexPrivateData::SearchTermCacheMap& cache, 349 const URLIndexPrivateData::SearchTermCacheMap& cache,
102 string16 term) const { 350 string16 term) const {
103 URLIndexPrivateData::SearchTermCacheMap::const_iterator cache_iter( 351 URLIndexPrivateData::SearchTermCacheMap::const_iterator cache_iter(
104 cache.find(term)); 352 cache.find(term));
105 ASSERT_TRUE(cache.end() != cache_iter) 353 ASSERT_TRUE(cache.end() != cache_iter)
106 << "Cache does not contain '" << term << "' but should."; 354 << "Cache does not contain '" << term << "' but should.";
107 URLIndexPrivateData::SearchTermCacheItem cache_item = cache_iter->second; 355 URLIndexPrivateData::SearchTermCacheItem cache_item = cache_iter->second;
108 EXPECT_TRUE(cache_item.used_) 356 EXPECT_TRUE(cache_item.used_)
109 << "Cache item '" << term << "' should be marked as being in use."; 357 << "Cache item '" << term << "' should be marked as being in use.";
110 } 358 }
111 359
360 void InMemoryURLIndexTest::ExpectPrivateDataNotEmpty(
361 const URLIndexPrivateData& data) {
362 EXPECT_FALSE(data.word_list_.empty());
363 // available_words_ will be empty since we have freshly built the
364 // data set for these tests.
365 EXPECT_TRUE(data.available_words_.empty());
366 EXPECT_FALSE(data.word_map_.empty());
367 EXPECT_FALSE(data.char_word_map_.empty());
368 EXPECT_FALSE(data.word_id_history_map_.empty());
369 EXPECT_FALSE(data.history_id_word_map_.empty());
370 EXPECT_FALSE(data.history_info_map_.empty());
371 }
372
373 void InMemoryURLIndexTest::ExpectPrivateDataEmpty(
374 const URLIndexPrivateData& data) {
375 EXPECT_TRUE(data.word_list_.empty());
376 EXPECT_TRUE(data.available_words_.empty());
377 EXPECT_TRUE(data.word_map_.empty());
378 EXPECT_TRUE(data.char_word_map_.empty());
379 EXPECT_TRUE(data.word_id_history_map_.empty());
380 EXPECT_TRUE(data.history_id_word_map_.empty());
381 EXPECT_TRUE(data.history_info_map_.empty());
382 }
383
384 // Helper function which compares two maps for equivalence. The maps' values
385 // are associative containers and their contents are compared as well.
386 template<typename T>
387 void ExpectMapOfContainersIdentical(const T& expected, const T& actual) {
388 ASSERT_EQ(expected.size(), actual.size());
389 for (typename T::const_iterator expected_iter = expected.begin();
390 expected_iter != expected.end(); ++expected_iter) {
391 typename T::const_iterator actual_iter = actual.find(expected_iter->first);
392 ASSERT_TRUE(actual.end() != actual_iter);
393 typename T::mapped_type const& expected_values(expected_iter->second);
394 typename T::mapped_type const& actual_values(actual_iter->second);
395 ASSERT_EQ(expected_values.size(), actual_values.size());
396 for (typename T::mapped_type::const_iterator set_iter =
397 expected_values.begin(); set_iter != expected_values.end(); ++set_iter)
398 EXPECT_EQ(actual_values.count(*set_iter),
399 expected_values.count(*set_iter));
400 }
401 }
402
403 void InMemoryURLIndexTest::ExpectPrivateDataEqual(
404 const URLIndexPrivateData& expected,
405 const URLIndexPrivateData& actual) {
406 EXPECT_EQ(expected.word_list_.size(), actual.word_list_.size());
407 EXPECT_EQ(expected.word_map_.size(), actual.word_map_.size());
408 EXPECT_EQ(expected.char_word_map_.size(), actual.char_word_map_.size());
409 EXPECT_EQ(expected.word_id_history_map_.size(),
410 actual.word_id_history_map_.size());
411 EXPECT_EQ(expected.history_id_word_map_.size(),
412 actual.history_id_word_map_.size());
413 EXPECT_EQ(expected.history_info_map_.size(), actual.history_info_map_.size());
414 EXPECT_EQ(expected.word_starts_map_.size(), actual.word_starts_map_.size());
415 // WordList must be index-by-index equal.
416 size_t count = expected.word_list_.size();
417 for (size_t i = 0; i < count; ++i)
418 EXPECT_EQ(expected.word_list_[i], actual.word_list_[i]);
419
420 ExpectMapOfContainersIdentical(expected.char_word_map_,
421 actual.char_word_map_);
422 ExpectMapOfContainersIdentical(expected.word_id_history_map_,
423 actual.word_id_history_map_);
424 ExpectMapOfContainersIdentical(expected.history_id_word_map_,
425 actual.history_id_word_map_);
426
427 for (HistoryInfoMap::const_iterator expected_info =
428 expected.history_info_map_.begin();
429 expected_info != expected.history_info_map_.end(); ++expected_info) {
430 HistoryInfoMap::const_iterator actual_info =
431 actual.history_info_map_.find(expected_info->first);
432 // NOTE(yfriedman): ASSERT_NE can't be used due to incompatibility between
433 // gtest and STLPort in the Android build. See
434 // http://code.google.com/p/googletest/issues/detail?id=359
435 ASSERT_TRUE(actual_info != actual.history_info_map_.end());
436 const URLRow& expected_row(expected_info->second);
437 const URLRow& actual_row(actual_info->second);
438 EXPECT_EQ(expected_row.visit_count(), actual_row.visit_count());
439 EXPECT_EQ(expected_row.typed_count(), actual_row.typed_count());
440 EXPECT_EQ(expected_row.last_visit(), actual_row.last_visit());
441 EXPECT_EQ(expected_row.url(), actual_row.url());
442 }
443
444 for (WordStartsMap::const_iterator expected_starts =
445 expected.word_starts_map_.begin();
446 expected_starts != expected.word_starts_map_.end();
447 ++expected_starts) {
448 WordStartsMap::const_iterator actual_starts =
449 actual.word_starts_map_.find(expected_starts->first);
450 // NOTE(yfriedman): ASSERT_NE can't be used due to incompatibility between
451 // gtest and STLPort in the Android build. See
452 // http://code.google.com/p/googletest/issues/detail?id=359
453 ASSERT_TRUE(actual_starts != actual.word_starts_map_.end());
454 const RowWordStarts& expected_word_starts(expected_starts->second);
455 const RowWordStarts& actual_word_starts(actual_starts->second);
456 EXPECT_EQ(expected_word_starts.url_word_starts_.size(),
457 actual_word_starts.url_word_starts_.size());
458 EXPECT_TRUE(std::equal(expected_word_starts.url_word_starts_.begin(),
459 expected_word_starts.url_word_starts_.end(),
460 actual_word_starts.url_word_starts_.begin()));
461 EXPECT_EQ(expected_word_starts.title_word_starts_.size(),
462 actual_word_starts.title_word_starts_.size());
463 EXPECT_TRUE(std::equal(expected_word_starts.title_word_starts_.begin(),
464 expected_word_starts.title_word_starts_.end(),
465 actual_word_starts.title_word_starts_.begin()));
466 }
467 }
468
112 //------------------------------------------------------------------------------ 469 //------------------------------------------------------------------------------
113 470
114 class LimitedInMemoryURLIndexTest : public InMemoryURLIndexTest { 471 class LimitedInMemoryURLIndexTest : public InMemoryURLIndexTest {
115 protected: 472 protected:
116 FilePath::StringType TestDBName() const OVERRIDE; 473 FilePath::StringType TestDBName() const;
117 }; 474 };
118 475
119 FilePath::StringType LimitedInMemoryURLIndexTest::TestDBName() const { 476 FilePath::StringType LimitedInMemoryURLIndexTest::TestDBName() const {
120 return FILE_PATH_LITERAL("url_history_provider_test_limited.db.txt"); 477 return FILE_PATH_LITERAL("url_history_provider_test_limited.db.txt");
121 } 478 }
122 479
123 TEST_F(LimitedInMemoryURLIndexTest, Initialization) { 480 TEST_F(LimitedInMemoryURLIndexTest, Initialization) {
124 // Verify that the database contains the expected number of items, which 481 // Verify that the database contains the expected number of items, which
125 // is the pre-filtered count, i.e. all of the items. 482 // is the pre-filtered count, i.e. all of the items.
126 sql::Statement statement( 483 sql::Statement statement(GetDB().GetUniqueStatement("SELECT * FROM urls;"));
127 history_database_->get_db_for_testing()->GetUniqueStatement(
128 "SELECT * FROM urls;"));
129 ASSERT_TRUE(statement.is_valid()); 484 ASSERT_TRUE(statement.is_valid());
130 uint64 row_count = 0; 485 uint64 row_count = 0;
131 while (statement.Step()) ++row_count; 486 while (statement.Step()) ++row_count;
132 EXPECT_EQ(1U, row_count); 487 EXPECT_EQ(1U, row_count);
488 url_index_.reset(
489 new InMemoryURLIndex(&profile_, FilePath(), "en,ja,hi,zh"));
490 url_index_->Init();
491 url_index_->RebuildFromHistory(history_database_);
492 URLIndexPrivateData& private_data(*GetPrivateData());
133 493
134 // history_info_map_ should have the same number of items as were filtered. 494 // history_info_map_ should have the same number of items as were filtered.
135 EXPECT_EQ(1U, url_index_->private_data_->history_info_map_.size()); 495 EXPECT_EQ(1U, private_data.history_info_map_.size());
136 EXPECT_EQ(35U, url_index_->private_data_->char_word_map_.size()); 496 EXPECT_EQ(35U, private_data.char_word_map_.size());
137 EXPECT_EQ(17U, url_index_->private_data_->word_map_.size()); 497 EXPECT_EQ(17U, private_data.word_map_.size());
138 } 498 }
139 499
140 //------------------------------------------------------------------------------
141
142 TEST_F(InMemoryURLIndexTest, Retrieval) { 500 TEST_F(InMemoryURLIndexTest, Retrieval) {
143 // See if a very specific term gives a single result. 501 // See if a very specific term gives a single result.
144 // Note that in each case the term will be lowercased by the search.
145 ScoredHistoryMatches matches = 502 ScoredHistoryMatches matches =
146 url_index_->HistoryItemsForTerms(ASCIIToUTF16("DrudgeReport")); 503 url_index_->HistoryItemsForTerms(ASCIIToUTF16("DrudgeReport"));
147 ASSERT_EQ(1U, matches.size()); 504 ASSERT_EQ(1U, matches.size());
148 505
149 // Verify that we got back the result we expected. 506 // Verify that we got back the result we expected.
150 EXPECT_EQ(5, matches[0].url_info.id()); 507 EXPECT_EQ(5, matches[0].url_info.id());
151 EXPECT_EQ("http://drudgereport.com/", matches[0].url_info.url().spec()); 508 EXPECT_EQ("http://drudgereport.com/", matches[0].url_info.url().spec());
152 EXPECT_EQ(ASCIIToUTF16("DRUDGE REPORT 2010"), matches[0].url_info.title()); 509 EXPECT_EQ(ASCIIToUTF16("DRUDGE REPORT 2010"), matches[0].url_info.title());
153 EXPECT_TRUE(matches[0].can_inline); 510 EXPECT_TRUE(matches[0].can_inline);
154 511
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 TEST_F(InMemoryURLIndexTest, HugeResultSet) { 643 TEST_F(InMemoryURLIndexTest, HugeResultSet) {
287 // Create a huge set of qualifying history items. 644 // Create a huge set of qualifying history items.
288 for (URLID row_id = 5000; row_id < 6000; ++row_id) { 645 for (URLID row_id = 5000; row_id < 6000; ++row_id) {
289 URLRow new_row(GURL("http://www.brokeandaloneinmanitoba.com/"), row_id); 646 URLRow new_row(GURL("http://www.brokeandaloneinmanitoba.com/"), row_id);
290 new_row.set_last_visit(base::Time::Now()); 647 new_row.set_last_visit(base::Time::Now());
291 EXPECT_TRUE(UpdateURL(new_row)); 648 EXPECT_TRUE(UpdateURL(new_row));
292 } 649 }
293 650
294 ScoredHistoryMatches matches = 651 ScoredHistoryMatches matches =
295 url_index_->HistoryItemsForTerms(ASCIIToUTF16("b")); 652 url_index_->HistoryItemsForTerms(ASCIIToUTF16("b"));
296 const URLIndexPrivateData* private_data(GetPrivateData()); 653 URLIndexPrivateData& private_data(*GetPrivateData());
297 ASSERT_EQ(AutocompleteProvider::kMaxMatches, matches.size()); 654 ASSERT_EQ(AutocompleteProvider::kMaxMatches, matches.size());
298 // There are 7 matches already in the database. 655 // There are 7 matches already in the database.
299 ASSERT_EQ(1008U, private_data->pre_filter_item_count_); 656 ASSERT_EQ(1008U, private_data.pre_filter_item_count_);
300 ASSERT_EQ(500U, private_data->post_filter_item_count_); 657 ASSERT_EQ(500U, private_data.post_filter_item_count_);
301 ASSERT_EQ(AutocompleteProvider::kMaxMatches, 658 ASSERT_EQ(AutocompleteProvider::kMaxMatches,
302 private_data->post_scoring_item_count_); 659 private_data.post_scoring_item_count_);
303 } 660 }
304 661
305 TEST_F(InMemoryURLIndexTest, TitleSearch) { 662 TEST_F(InMemoryURLIndexTest, TitleSearch) {
306 // Signal if someone has changed the test DB. 663 // Signal if someone has changed the test DB.
307 EXPECT_EQ(28U, GetPrivateData()->history_info_map_.size()); 664 EXPECT_EQ(28U, GetPrivateData()->history_info_map_.size());
308 665
309 // Ensure title is being searched. 666 // Ensure title is being searched.
310 ScoredHistoryMatches matches = 667 ScoredHistoryMatches matches =
311 url_index_->HistoryItemsForTerms(ASCIIToUTF16("MORTGAGE RATE DROPS")); 668 url_index_->HistoryItemsForTerms(ASCIIToUTF16("MORTGAGE RATE DROPS"));
312 ASSERT_EQ(1U, matches.size()); 669 ASSERT_EQ(1U, matches.size());
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 EXPECT_EQ(28, matches[0].url_info.id()); 739 EXPECT_EQ(28, matches[0].url_info.id());
383 } 740 }
384 741
385 TEST_F(InMemoryURLIndexTest, TypedCharacterCaching) { 742 TEST_F(InMemoryURLIndexTest, TypedCharacterCaching) {
386 // Verify that match results for previously typed characters are retained 743 // Verify that match results for previously typed characters are retained
387 // (in the term_char_word_set_cache_) and reused, if possible, in future 744 // (in the term_char_word_set_cache_) and reused, if possible, in future
388 // autocompletes. 745 // autocompletes.
389 typedef URLIndexPrivateData::SearchTermCacheMap::iterator CacheIter; 746 typedef URLIndexPrivateData::SearchTermCacheMap::iterator CacheIter;
390 typedef URLIndexPrivateData::SearchTermCacheItem CacheItem; 747 typedef URLIndexPrivateData::SearchTermCacheItem CacheItem;
391 748
392 const URLIndexPrivateData::SearchTermCacheMap& cache( 749 URLIndexPrivateData::SearchTermCacheMap& cache(
393 GetPrivateData()->search_term_cache_); 750 GetPrivateData()->search_term_cache_);
394 751
395 // The cache should be empty at this point. 752 // The cache should be empty at this point.
396 EXPECT_EQ(0U, cache.size()); 753 EXPECT_EQ(0U, cache.size());
397 754
398 // Now simulate typing search terms into the omnibox and check the state of 755 // Now simulate typing search terms into the omnibox and check the state of
399 // the cache as each item is 'typed'. 756 // the cache as each item is 'typed'.
400 757
401 // Simulate typing "r" giving "r" in the simulated omnibox. The results for 758 // Simulate typing "r" giving "r" in the simulated omnibox. The results for
402 // 'r' will be not cached because it is only 1 character long. 759 // 'r' will be not cached because it is only 1 character long.
(...skipping 28 matching lines...) Expand all
431 CheckTerm(cache, ASCIIToUTF16("mort")); 788 CheckTerm(cache, ASCIIToUTF16("mort"));
432 CheckTerm(cache, ASCIIToUTF16("reco")); 789 CheckTerm(cache, ASCIIToUTF16("reco"));
433 790
434 // Simulate a <DELETE> by removing the 'reco' and adding back the 'rec'. 791 // Simulate a <DELETE> by removing the 'reco' and adding back the 'rec'.
435 url_index_->HistoryItemsForTerms(ASCIIToUTF16("mort rec")); 792 url_index_->HistoryItemsForTerms(ASCIIToUTF16("mort rec"));
436 ASSERT_EQ(2U, cache.size()); 793 ASSERT_EQ(2U, cache.size());
437 CheckTerm(cache, ASCIIToUTF16("mort")); 794 CheckTerm(cache, ASCIIToUTF16("mort"));
438 CheckTerm(cache, ASCIIToUTF16("rec")); 795 CheckTerm(cache, ASCIIToUTF16("rec"));
439 } 796 }
440 797
798 #if 0
799 TEST_F(InMemoryURLIndexTest, Scoring) {
800 URLRow row_a(MakeURLRow("http://abcdef", "fedcba", 3, 30, 1));
801 // We use NowFromSystemTime() because MakeURLRow uses the same function
802 // to calculate last visit time when building a row.
803 base::Time now = base::Time::NowFromSystemTime();
804 RowWordStarts word_starts;
805 // Test scores based on position.
806 // TODO(mpearson): Test new_scoring if we're actually going to turn it
807 // on by default. This requires setting word_starts, which isn't done
808 // right now.
809 ScoredHistoryMatch scored_a(row_a, ASCIIToUTF16("abc"), Make1Term("abc"),
810 word_starts, now);
811 ScoredHistoryMatch scored_b(row_a, ASCIIToUTF16("bcd"), Make1Term("bcd"),
812 word_starts, now);
813 EXPECT_GT(scored_a.raw_score, scored_b.raw_score);
814 // Test scores based on length.
815 ScoredHistoryMatch scored_c(row_a, ASCIIToUTF16("abcd"), Make1Term("abcd"),
816 word_starts, now);
817 EXPECT_LT(scored_a.raw_score, scored_c.raw_score);
818 // Test scores based on order.
819 ScoredHistoryMatch scored_d(row_a, ASCIIToUTF16("abcdef"),
820 Make2Terms("abc", "def"), word_starts, now);
821 ScoredHistoryMatch scored_e(row_a, ASCIIToUTF16("def abc"),
822 Make2Terms("def", "abc"), word_starts, now);
823 EXPECT_GT(scored_d.raw_score, scored_e.raw_score);
824 // Test scores based on visit_count.
825 URLRow row_b(MakeURLRow("http://abcdef", "fedcba", 10, 30, 1));
826 ScoredHistoryMatch scored_f(row_b, ASCIIToUTF16("abc"), Make1Term("abc"),
827 word_starts, now);
828 EXPECT_GT(scored_f.raw_score, scored_a.raw_score);
829 // Test scores based on last_visit.
830 URLRow row_c(MakeURLRow("http://abcdef", "fedcba", 3, 10, 1));
831 ScoredHistoryMatch scored_g(row_c, ASCIIToUTF16("abc"), Make1Term("abc"),
832 word_starts, now);
833 EXPECT_GT(scored_g.raw_score, scored_a.raw_score);
834 // Test scores based on typed_count.
835 URLRow row_d(MakeURLRow("http://abcdef", "fedcba", 3, 30, 10));
836 ScoredHistoryMatch scored_h(row_d, ASCIIToUTF16("abc"), Make1Term("abc"),
837 word_starts, now);
838 EXPECT_GT(scored_h.raw_score, scored_a.raw_score);
839 // Test scores based on a terms appearing multiple times.
840 URLRow row_i(MakeURLRow("http://csi.csi.csi/csi_csi",
841 "CSI Guide to CSI Las Vegas, CSI New York, CSI Provo", 3, 30, 10));
842 ScoredHistoryMatch scored_i(row_i, ASCIIToUTF16("csi"), Make1Term("csi"),
843 word_starts, now);
844 EXPECT_LT(scored_i.raw_score, 1400);
845 }
846
847 TEST_F(InMemoryURLIndexTest, GetTopicalityScoreTrailingSlash) {
848 const float hostname = GetTopicalityScoreOfTermAgainstURLAndTitle(
849 ASCIIToUTF16("def"),
850 ASCIIToUTF16("http://abc.def.com/"),
851 ASCIIToUTF16("Non-Matching Title"));
852 const float hostname_no_slash = GetTopicalityScoreOfTermAgainstURLAndTitle(
853 ASCIIToUTF16("def"),
854 ASCIIToUTF16("http://abc.def.com"),
855 ASCIIToUTF16("Non-Matching Title"));
856 EXPECT_EQ(hostname_no_slash, hostname);
857 }
858
859 // This function only tests scoring of single terms that match exactly
860 // once somewhere in the URL or title.
861 TEST_F(InMemoryURLIndexTest, GetTopicalityScore) {
862 string16 url = ASCIIToUTF16("http://abc.def.com/path1/path2?"
863 "arg1=val1&arg2=val2#hash_component");
864 string16 title = ASCIIToUTF16("here is a title");
865 const float hostname_score =
866 GetTopicalityScoreOfTermAgainstURLAndTitle(
867 ASCIIToUTF16("abc"), url, title);
868 const float hostname_mid_word_score =
869 GetTopicalityScoreOfTermAgainstURLAndTitle(
870 ASCIIToUTF16("bc"), url, title);
871 const float path_score =
872 GetTopicalityScoreOfTermAgainstURLAndTitle(
873 ASCIIToUTF16("path1"), url, title);
874 const float path_mid_word_score =
875 GetTopicalityScoreOfTermAgainstURLAndTitle(
876 ASCIIToUTF16("ath1"), url, title);
877 const float arg_score =
878 GetTopicalityScoreOfTermAgainstURLAndTitle(
879 ASCIIToUTF16("arg2"), url, title);
880 const float arg_mid_word_score =
881 GetTopicalityScoreOfTermAgainstURLAndTitle(
882 ASCIIToUTF16("rg2"), url, title);
883 const float protocol_score =
884 GetTopicalityScoreOfTermAgainstURLAndTitle(
885 ASCIIToUTF16("htt"), url, title);
886 const float protocol_mid_word_score =
887 GetTopicalityScoreOfTermAgainstURLAndTitle(
888 ASCIIToUTF16("tt"), url, title);
889 const float title_score =
890 GetTopicalityScoreOfTermAgainstURLAndTitle(
891 ASCIIToUTF16("her"), url, title);
892 const float title_mid_word_score =
893 GetTopicalityScoreOfTermAgainstURLAndTitle(
894 ASCIIToUTF16("er"), url, title);
895 // Verify hostname > path > arg, and the same for the matches at
896 // non-word-boundaries.
897 EXPECT_GT(hostname_score, path_score);
898 EXPECT_GT(path_score, arg_score);
899 EXPECT_GT(hostname_mid_word_score, path_mid_word_score);
900 EXPECT_GT(path_mid_word_score, arg_mid_word_score);
901 // Also verify that the matches at non-word-boundaries all score
902 // worse than the matches at word boundaries. These two sets suffice.
903 EXPECT_GT(arg_score, hostname_mid_word_score);
904 EXPECT_GT(title_score, title_mid_word_score);
905 // Check that title matches fit somewhere reasonable compared to the
906 // various types of URL matches.
907 EXPECT_GT(title_score, arg_score);
908 EXPECT_GT(arg_score, hostname_mid_word_score);
909 EXPECT_GT(title_mid_word_score, arg_mid_word_score);
910 // Finally, verify that protocol matches score worse than everything
911 // (except possibly mid-word matches in the ?arg section of the URL--I
912 // can imagine scoring those pretty harshly as well).
913 EXPECT_GT(path_mid_word_score, protocol_score);
914 EXPECT_GT(path_mid_word_score, protocol_mid_word_score);
915 EXPECT_GT(title_mid_word_score, protocol_score);
916 EXPECT_GT(title_mid_word_score, protocol_mid_word_score);
917 }
918 #endif
919
441 TEST_F(InMemoryURLIndexTest, AddNewRows) { 920 TEST_F(InMemoryURLIndexTest, AddNewRows) {
442 // Verify that the row we're going to add does not already exist. 921 // Verify that the row we're going to add does not already exist.
443 URLID new_row_id = 87654321; 922 URLID new_row_id = 87654321;
444 // Newly created URLRows get a last_visit time of 'right now' so it should 923 // Newly created URLRows get a last_visit time of 'right now' so it should
445 // qualify as a quick result candidate. 924 // qualify as a quick result candidate.
446 EXPECT_TRUE(url_index_->HistoryItemsForTerms( 925 EXPECT_TRUE(url_index_->HistoryItemsForTerms(
447 ASCIIToUTF16("brokeandalone")).empty()); 926 ASCIIToUTF16("brokeandalone")).empty());
448 927
449 // Add a new row. 928 // Add a new row.
450 URLRow new_row(GURL("http://www.brokeandaloneinmanitoba.com/"), new_row_id++); 929 URLRow new_row(GURL("http://www.brokeandaloneinmanitoba.com/"), new_row_id++);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 TEST_F(InMemoryURLIndexTest, ExpireRow) { 964 TEST_F(InMemoryURLIndexTest, ExpireRow) {
486 ScoredHistoryMatches matches = 965 ScoredHistoryMatches matches =
487 url_index_->HistoryItemsForTerms(ASCIIToUTF16("DrudgeReport")); 966 url_index_->HistoryItemsForTerms(ASCIIToUTF16("DrudgeReport"));
488 ASSERT_EQ(1U, matches.size()); 967 ASSERT_EQ(1U, matches.size());
489 968
490 // Determine the row id for the result, remember that id, broadcast a 969 // Determine the row id for the result, remember that id, broadcast a
491 // delete notification, then ensure that the row has been deleted. 970 // delete notification, then ensure that the row has been deleted.
492 URLsDeletedDetails deleted_details; 971 URLsDeletedDetails deleted_details;
493 deleted_details.all_history = false; 972 deleted_details.all_history = false;
494 deleted_details.rows.push_back(matches[0].url_info); 973 deleted_details.rows.push_back(matches[0].url_info);
495 content::Source<InMemoryURLIndexTest> source(this); 974 Observe(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
496 url_index_->Observe( 975 content::Source<InMemoryURLIndexTest>(this),
497 chrome::NOTIFICATION_HISTORY_URLS_DELETED, 976 content::Details<history::HistoryDetails>(&deleted_details));
498 content::Source<InMemoryURLIndexTest>(this),
499 content::Details<history::HistoryDetails>(&deleted_details));
500 EXPECT_TRUE(url_index_->HistoryItemsForTerms( 977 EXPECT_TRUE(url_index_->HistoryItemsForTerms(
501 ASCIIToUTF16("DrudgeReport")).empty()); 978 ASCIIToUTF16("DrudgeReport")).empty());
502 } 979 }
503 980
504 TEST_F(InMemoryURLIndexTest, WhitelistedURLs) { 981 TEST_F(InMemoryURLIndexTest, WhitelistedURLs) {
505 struct TestData { 982 struct TestData {
506 const std::string url_spec; 983 const std::string url_spec;
507 const bool expected_is_whitelisted; 984 const bool expected_is_whitelisted;
508 } data[] = { 985 } data[] = {
509 // URLs with whitelisted schemes. 986 // URLs with whitelisted schemes.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 { "tftp://example.com/mystartupfile", false }, 1045 { "tftp://example.com/mystartupfile", false },
569 { "tip://123.123.123.123/?urn:xopen:xid", false }, 1046 { "tip://123.123.123.123/?urn:xopen:xid", false },
570 { "tv:nbc.com", false }, 1047 { "tv:nbc.com", false },
571 { "urn:foo:A123,456", false }, 1048 { "urn:foo:A123,456", false },
572 { "vemmi://zeus.mctel.fr/demo", false }, 1049 { "vemmi://zeus.mctel.fr/demo", false },
573 { "wais://www.mydomain.net:8765/mydatabase", false }, 1050 { "wais://www.mydomain.net:8765/mydatabase", false },
574 { "xmpp:node@example.com", false }, 1051 { "xmpp:node@example.com", false },
575 { "xmpp://guest@example.com", false }, 1052 { "xmpp://guest@example.com", false },
576 }; 1053 };
577 1054
578 std::set<std::string> whitelist; 1055 URLIndexPrivateData& private_data(*GetPrivateData());
579 URLIndexPrivateData::InitializeSchemeWhitelistForTesting(&whitelist); 1056 const std::set<std::string>& whitelist(scheme_whitelist());
580 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { 1057 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
581 GURL url(data[i].url_spec); 1058 GURL url(data[i].url_spec);
582 EXPECT_EQ(data[i].expected_is_whitelisted, 1059 EXPECT_EQ(data[i].expected_is_whitelisted,
583 URLIndexPrivateData::URLSchemeIsWhitelisted(url, whitelist)); 1060 private_data.URLSchemeIsWhitelisted(url, whitelist));
584 } 1061 }
585 } 1062 }
586 1063
587 // InMemoryURLIndexCacheTest --------------------------------------------------- 1064 TEST_F(InMemoryURLIndexTest, CacheSaveRestore) {
1065 ScopedTempDir temp_directory;
1066 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
1067 set_history_dir(temp_directory.path());
588 1068
589 class InMemoryURLIndexCacheTest : public InMemoryURLIndexBaseTest { 1069 URLIndexPrivateData& private_data(*GetPrivateData());
1070
1071 // Ensure that there is really something there to be saved.
1072 EXPECT_FALSE(private_data.word_list_.empty());
1073 // available_words_ will already be empty since we have freshly built the
1074 // data set for this test.
1075 EXPECT_TRUE(private_data.available_words_.empty());
1076 EXPECT_FALSE(private_data.word_map_.empty());
1077 EXPECT_FALSE(private_data.char_word_map_.empty());
1078 EXPECT_FALSE(private_data.word_id_history_map_.empty());
1079 EXPECT_FALSE(private_data.history_id_word_map_.empty());
1080 EXPECT_FALSE(private_data.history_info_map_.empty());
1081 EXPECT_FALSE(private_data.word_starts_map_.empty());
1082
1083 // Capture the current private data for later comparison to restored data.
1084 scoped_refptr<URLIndexPrivateData> old_data(private_data.Duplicate());
1085
1086 // Save then restore our private data.
1087 CacheFileSaverObserver save_observer(&message_loop_);
1088 url_index_->set_save_cache_observer(&save_observer);
1089 PostSaveToCacheFileTask();
1090 message_loop_.Run();
1091 EXPECT_TRUE(save_observer.succeeded_);
1092
1093 // Clear and then prove it's clear before restoring.
1094 ClearPrivateData();
1095 EXPECT_TRUE(private_data.word_list_.empty());
1096 EXPECT_TRUE(private_data.available_words_.empty());
1097 EXPECT_TRUE(private_data.word_map_.empty());
1098 EXPECT_TRUE(private_data.char_word_map_.empty());
1099 EXPECT_TRUE(private_data.word_id_history_map_.empty());
1100 EXPECT_TRUE(private_data.history_id_word_map_.empty());
1101 EXPECT_TRUE(private_data.history_info_map_.empty());
1102 EXPECT_TRUE(private_data.word_starts_map_.empty());
1103
1104 CacheFileReaderObserver read_observer(&message_loop_);
1105 url_index_->set_restore_cache_observer(&read_observer);
1106 PostRestoreFromCacheFileTask();
1107 message_loop_.Run();
1108 EXPECT_TRUE(read_observer.succeeded_);
1109
1110 URLIndexPrivateData& new_data(*GetPrivateData());
1111
1112 // Compare the captured and restored for equality.
1113 ExpectPrivateDataEqual(*old_data, new_data);
1114 }
1115
1116 class InMemoryURLIndexCacheTest : public testing::Test {
590 public: 1117 public:
591 // A test helper class which captures the state of the URL index and cache 1118 InMemoryURLIndexCacheTest() {}
592 // prior to the addition, update or delete of a history URL visit, determines
593 // the expected state after the URL change, and verifies the actual state.
594 class CacheChecker {
595 public:
596 enum ChangeType {
597 URL_ADDED,
598 URL_UPDATED,
599 URL_REMOVED,
600 };
601 1119
602 // Captures the state of the index and cache and the changes which are 1120 protected:
603 // expected to be made. |index| points to the test index. |change_type| 1121 virtual void SetUp() OVERRIDE;
604 // specifies the kind of history URL visit change that will take place.
605 // |existing_words| lists the words that are referenced by the history item
606 // (both URL and page title) which are expected to already be recorded in
607 // the index. |added_words| gives terms which are not currently in the index
608 // but will be added for this history item. |removed_words| gives words in
609 // the index but which are not referenced by any other history item and
610 // which will be removed by the test action.
611 CacheChecker(InMemoryURLIndex* index,
612 ChangeType change_type,
613 URLID history_id,
614 const String16Set& existing_words,
615 const String16Set& added_words,
616 const String16Set& removed_words);
617 virtual ~CacheChecker();
618 1122
619 // Initializes and destroys things in a way that the standard gtest 1123 // Pass-through functions to simplify our friendship with InMemoryURLIndex.
620 // EXPECT_xxx macros can be used since those macros cannot be used in 1124 void set_history_dir(const FilePath& dir_path);
621 // constructors and destructors. 1125 bool GetCacheFilePath(FilePath* file_path) const;
622 void Init();
623 void Destroy();
624 1126
625 private: 1127 ScopedTempDir temp_dir_;
626 // A helper struct that records index current state for words in the list of 1128 scoped_ptr<InMemoryURLIndex> url_index_;
627 // |existing_words| and |removed_words|.
628 struct ExistingWord {
629 ExistingWord() : word_id(0), word_map_count(0), word_table_count(0) {}
630 ExistingWord(WordID word_id,
631 size_t word_map_count,
632 size_t word_table_count)
633 : word_id(word_id),
634 word_map_count(word_map_count),
635 word_table_count(word_table_count) {}
636
637 WordID word_id; // Used for removed_words only.
638 size_t word_map_count;
639 size_t word_table_count;
640 };
641
642 // Table names.
643 static const char* kWordsTableName;
644 static const char* kWordHistoryTableName;
645 static const char* kURLsTableName;
646 static const char* kURLWordStartsTableName;
647 static const char* kTitleWordStartsTableName;
648 // Field names.
649 static const char* kWord;
650 static const char* kWordID;
651 static const char* kHistoryID;
652 static const char* kWordStart;
653
654 // Helper functions that perform a COUNT query of the cache database with
655 // the given criteria and return the number of rows meeting that criteria.
656 // |table| specifies the name of the table in which the SELECT will be
657 // performed. |column| gives the column against which the desired |word|,
658 // |word_id| or |history_id| will be matched.
659 int SelectCount(const char* table);
660 int SelectCount(const char* table,
661 const char* column,
662 const string16& word);
663 int SelectCount(const char* table,
664 const char* column,
665 WordID word_id);
666 int SelectCount(const char* table,
667 const char* column,
668 HistoryID history_id);
669
670 InMemoryURLIndex& index_;
671 sql::Connection* db_;
672 // Information about the changes that the test is expected to cause.
673 ChangeType change_type_;
674 URLID history_id_;
675 String16Set existing_words_;
676 String16Set added_words_;
677 String16Set removed_words_;
678 // Current state information about the index.
679 size_t word_list_count_;
680 size_t word_table_count;
681 size_t history_id_word_map_count_;
682 size_t available_words_count_;
683 std::map<string16, ExistingWord> existing_words_and_counts_;
684 std::map<string16, ExistingWord> removed_words_and_counts_;
685 };
686
687 void SetUp() OVERRIDE;
688
689 // Provides custom test data file name.
690 virtual FilePath::StringType TestDBName() const OVERRIDE;
691 }; 1129 };
692 1130
693 // InMemoryURLIndexCacheTest::CacheChecker ------------------------------------- 1131 void InMemoryURLIndexCacheTest::SetUp() {
694 1132 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
695 // Cache database table names. See in_memory_url_cache_database.cc. 1133 FilePath path(temp_dir_.path());
696 typedef InMemoryURLIndexCacheTest::CacheChecker CacheChecker; 1134 url_index_.reset(
697 const char* CacheChecker::kWordsTableName = "words"; 1135 new InMemoryURLIndex(NULL, path, "en,ja,hi,zh"));
698 const char* CacheChecker::kWordHistoryTableName = "word_history";
699 const char* CacheChecker::kURLsTableName = "urls";
700 const char* CacheChecker::kURLWordStartsTableName = "url_word_starts";
701 const char* CacheChecker::kTitleWordStartsTableName = "title_word_starts";
702
703 // Cache database table field names.
704 const char* CacheChecker::kWord = "word";
705 const char* CacheChecker::kWordID = "word_id";
706 const char* CacheChecker::kHistoryID = "history_id";
707 const char* CacheChecker::kWordStart = "word_start";
708
709 CacheChecker::CacheChecker(
710 InMemoryURLIndex* index,
711 ChangeType change_type,
712 URLID history_id,
713 const String16Set& existing_words,
714 const String16Set& added_words,
715 const String16Set& removed_words)
716 : index_(*index),
717 db_(index_.private_data_->cache_db()->get_db_for_testing()),
718 change_type_(change_type),
719 history_id_(history_id),
720 existing_words_(existing_words),
721 added_words_(added_words),
722 removed_words_(removed_words),
723 // Remember the old word count, the old word table count, the old history
724 // ID count, and how many unused words are available for reuse.
725 word_list_count_(index_.private_data_->word_list_.size()),
726 word_table_count(SelectCount(kWordsTableName)),
727 history_id_word_map_count_(
728 index_.private_data_->history_id_word_map_.size()),
729 available_words_count_(index_.private_data_->available_words_.size()) {
730 DCHECK(db_);
731 Init();
732 } 1136 }
733 1137
734 void CacheChecker::Init() { 1138 void InMemoryURLIndexCacheTest::set_history_dir(const FilePath& dir_path) {
735 // Verify that the existing words exist and remember their counts. 1139 return url_index_->set_history_dir(dir_path);
736 URLIndexPrivateData* private_data(index_.private_data_.get());
737 for (String16Set::iterator word_iter = existing_words_.begin();
738 word_iter != existing_words_.end(); ++word_iter) {
739 string16 word(*word_iter);
740 ASSERT_NE(0U, private_data->word_map_.count(word))
741 << "Existing word '" << word << "' not found.";
742 EXPECT_GT(SelectCount(kWordsTableName, kWord, word), 0)
743 << "Existing word '" << word << "' not found in words table.";
744 WordID word_id = private_data->word_map_[word];
745 EXPECT_GT(SelectCount(kWordHistoryTableName, kWordID, word_id), 0)
746 << "Existing word '" << word << "' not found in word_history table.";
747 existing_words_and_counts_[word] =
748 ExistingWord(word_id, private_data->word_id_history_map_[word_id].
749 size(),
750 SelectCount(kWordHistoryTableName, kWordID, word_id));
751 }
752
753 // Verify that the added words don't already exist.
754 for (String16Set::iterator word_iter = added_words_.begin();
755 word_iter != added_words_.end(); ++word_iter) {
756 string16 word(*word_iter);
757 EXPECT_EQ(0U, private_data->word_map_.count(word))
758 << "Word '" << word << "' to be added is already there.";
759 EXPECT_EQ(0, SelectCount(kWordsTableName, kWord, word))
760 << "Word '" << word << "' to be added is already in words table.";
761 }
762
763 // Verify that the removed words exist and remember their counts.
764 for (String16Set::iterator word_iter = removed_words_.begin();
765 word_iter != removed_words_.end(); ++word_iter) {
766 string16 word(*word_iter);
767 ASSERT_EQ(1U, private_data->word_map_.count(word))
768 << "Word '" << word << "' to be removed not found.";
769 WordID word_id = private_data->word_map_[word];
770 EXPECT_GT(private_data->word_id_history_map_[word_id].size(), 0U);
771 EXPECT_GT(SelectCount(kWordsTableName, kWord, word), 0)
772 << "Word '" << word << "' to be removed not found in words table.";
773 EXPECT_GT(SelectCount(kWordHistoryTableName, kWordID, word_id), 0)
774 << "Word '" << word << "' to remove not found in word_history table.";
775 removed_words_and_counts_[word] =
776 ExistingWord(word_id, private_data->word_id_history_map_[word_id].
777 size(),
778 SelectCount(kWordHistoryTableName, kWordID, word_id));
779 EXPECT_EQ(removed_words_and_counts_[word].word_map_count,
780 removed_words_and_counts_[word].word_table_count);
781 }
782 } 1140 }
783 1141
784 CacheChecker::~CacheChecker() { 1142 bool InMemoryURLIndexCacheTest::GetCacheFilePath(FilePath* file_path) const {
785 Destroy(); 1143 DCHECK(file_path);
1144 return url_index_->GetCacheFilePath(file_path);
786 } 1145 }
787 1146
788 void CacheChecker::Destroy() { 1147 TEST_F(InMemoryURLIndexCacheTest, CacheFilePath) {
789 // Verify that the existing words still exist and their counts have 1148 FilePath expectedPath =
790 // incremented by 1. 1149 temp_dir_.path().Append(FILE_PATH_LITERAL("History Provider Cache"));
791 URLIndexPrivateData* private_data(index_.private_data_.get()); 1150 std::vector<FilePath::StringType> expected_parts;
792 for (String16Set::iterator word_iter = existing_words_.begin(); 1151 expectedPath.GetComponents(&expected_parts);
793 word_iter != existing_words_.end(); ++word_iter) { 1152 FilePath full_file_path;
794 string16 word(*word_iter); 1153 ASSERT_TRUE(GetCacheFilePath(&full_file_path));
795 const ExistingWord& existing_word(existing_words_and_counts_[word]); 1154 std::vector<FilePath::StringType> actual_parts;
796 size_t expected_count = existing_word.word_map_count; 1155 full_file_path.GetComponents(&actual_parts);
797 if (change_type_ == URL_ADDED) 1156 ASSERT_EQ(expected_parts.size(), actual_parts.size());
798 ++expected_count; 1157 size_t count = expected_parts.size();
799 WordID word_id = private_data->word_map_[word]; 1158 for (size_t i = 0; i < count; ++i)
800 EXPECT_EQ(expected_count, 1159 EXPECT_EQ(expected_parts[i], actual_parts[i]);
801 private_data->word_id_history_map_[word_id].size()) 1160 // Must clear the history_dir_ to satisfy the dtor's DCHECK.
802 << "Occurrence count for existing word '" << word 1161 set_history_dir(FilePath());
803 << "' in the word_id_history_map_ is incorrect.";
804 EXPECT_EQ(static_cast<int>(expected_count),
805 SelectCount(kWordHistoryTableName, kWordID, word_id))
806 << "Occurrence count for existing word '" << word << "' in "
807 "the word_history database table is incorrect.";
808 }
809
810 // Verify the added words have been added and their counts are 1.
811 for (String16Set::iterator word_iter = added_words_.begin();
812 word_iter != added_words_.end(); ++word_iter) {
813 string16 word(*word_iter);
814 ASSERT_EQ(1U, private_data->word_map_.count(word));
815 WordID word_id = private_data->word_map_[word];
816 EXPECT_EQ(1U, private_data->word_id_history_map_[word_id].size())
817 << "Count for added word '" << word << "' not 1.";
818 EXPECT_EQ(1, SelectCount(kWordsTableName, kWord, word))
819 << "Word '" << word << "' not added to words table.";
820 EXPECT_EQ(1, SelectCount(kWordHistoryTableName, kWordID, word_id))
821 << "Word '" << word << "' not added to word_history table.";
822 }
823
824 switch (change_type_) {
825 case URL_ADDED:
826 ASSERT_EQ(0U, removed_words_.size())
827 << "BAD TEST DATA -- removed_words must be empty for URL_ADDED.";
828 // Fall through.
829 case URL_UPDATED: {
830 // There should be added-words + existing-words - removed-words entries
831 // in the word_history table for the history ID.
832 size_t word_count_for_id = existing_words_.size() + added_words_.size();
833 EXPECT_EQ(word_count_for_id,
834 private_data->history_id_word_map_[history_id_].size());
835 EXPECT_EQ(static_cast<int>(word_count_for_id),
836 SelectCount(kWordHistoryTableName, kHistoryID, history_id_));
837 EXPECT_EQ(1U, private_data->history_id_word_map_.count(history_id_));
838 EXPECT_EQ(1, SelectCount(kURLsTableName, kHistoryID, history_id_));
839 }
840 break;
841 case URL_REMOVED:
842 // There should be no entries in the word_history table for the history
843 // ID.
844 ASSERT_EQ(0U, added_words_.size())
845 << "BAD TEST DATA -- added_words must be empty for URL_REMOVED.";
846 EXPECT_EQ(0U, private_data->history_id_word_map_.count(history_id_));
847 EXPECT_EQ(0, SelectCount(kWordHistoryTableName, kHistoryID, history_id_));
848 EXPECT_EQ(0, SelectCount(kURLsTableName, kHistoryID, history_id_));
849 break;
850 }
851
852 // Verify that the count for removed words has been decremented or that
853 // they have been deleted if their count has dropped to 0.
854 int completely_removed = 0;
855 for (String16Set::iterator word_iter = removed_words_.begin();
856 word_iter != removed_words_.end(); ++word_iter) {
857 string16 word(*word_iter);
858 const ExistingWord& removed_word(removed_words_and_counts_[word]);
859 size_t expected_word_count = removed_word.word_map_count - 1;
860 if (expected_word_count > 0) {
861 EXPECT_EQ(1, SelectCount(kWordsTableName, kWord, word))
862 << "Word '" << word << "' not removed from words table.";
863 ASSERT_EQ(1U, private_data->word_map_.count(word))
864 << "Word '" << word << "' is gone but should still be there.";
865 EXPECT_EQ(expected_word_count,
866 private_data->word_id_history_map_[removed_word.word_id].size())
867 << "Count for existing word '" << word << "' not decremented. A";
868 EXPECT_EQ(static_cast<int>(expected_word_count),
869 SelectCount(kWordHistoryTableName, kWordID,
870 removed_word.word_id))
871 << "Count for existing word '" << word << "' not decremented. B";
872 } else {
873 EXPECT_EQ(0, SelectCount(kWordsTableName, kWord, word))
874 << "Word '" << word << "' not removed from words table.";
875 EXPECT_EQ(0U, private_data->word_map_.count(word))
876 << "Word '" << word << "' to be removed is still there.";
877 ++completely_removed;
878 }
879 }
880
881 // Verify that the size of the in-memory and on-disk database tables have
882 // changed as expected.
883 EXPECT_EQ(std::max(0, static_cast<int>(available_words_count_) +
884 completely_removed - static_cast<int>(added_words_.size())),
885 static_cast<int>(private_data->available_words_.size()));
886 // The in-memory table will never get smaller as we remember the freed-up
887 // slots and reuse them.
888 EXPECT_EQ(static_cast<int>(word_list_count_) + std::max(0,
889 static_cast<int>(added_words_.size()) - completely_removed),
890 static_cast<int>(private_data->word_list_.size()));
891 EXPECT_EQ(static_cast<int>(word_table_count) +
892 static_cast<int>(added_words_.size()) - completely_removed,
893 SelectCount(kWordsTableName));
894 }
895
896 int CacheChecker::SelectCount(const char* table) {
897 std::string sql(StringPrintf("SELECT COUNT(*) FROM %s", table));
898 sql::Statement statement(db_->GetUniqueStatement(sql.c_str()));
899 return (statement.Step()) ? statement.ColumnInt(0) : -1;
900 }
901
902 int CacheChecker::SelectCount(const char* table,
903 const char* column,
904 const string16& word) {
905 std::string sql(StringPrintf("SELECT COUNT(*) FROM %s WHERE %s = ?",
906 table, column));
907 sql::Statement statement(db_->GetUniqueStatement(sql.c_str()));
908 statement.BindString16(0, word);
909 return (statement.Step()) ? statement.ColumnInt(0) : -1;
910 }
911
912 int CacheChecker::SelectCount(
913 const char* table,
914 const char* column,
915 WordID word_id) {
916 std::string sql(StringPrintf("SELECT COUNT(*) FROM %s WHERE %s = ?",
917 table, column));
918 sql::Statement statement(db_->GetUniqueStatement(sql.c_str()));
919 statement.BindInt(0, word_id);
920 return (statement.Step()) ? statement.ColumnInt(0) : -1;
921 }
922
923 int CacheChecker::SelectCount(const char* table,
924 const char* column,
925 HistoryID history_id) {
926 std::string sql(StringPrintf("SELECT COUNT(*) FROM %s WHERE %s = ?",
927 table, column));
928 sql::Statement statement(db_->GetUniqueStatement(sql.c_str()));
929 statement.BindInt(0, history_id);
930 return (statement.Step()) ? statement.ColumnInt(0) : -1;
931 }
932
933 // InMemoryURLIndexCacheTest ---------------------------------------------------
934
935 void InMemoryURLIndexCacheTest::SetUp() {
936 profile_.reset(new CacheTestingProfile);
937 InMemoryURLIndexBaseTest::SetUp();
938 LoadIndex();
939 DCHECK(url_index_->index_available());
940 }
941
942 FilePath::StringType InMemoryURLIndexCacheTest::TestDBName() const {
943 return FILE_PATH_LITERAL("url_history_provider_test.db.txt");
944 }
945
946 TEST_F(InMemoryURLIndexCacheTest, CacheAddRemove) {
947 // Initialize the cache then add and remove some history items.
948 const URLID kNewRowID = 250;
949 URLRow new_row(MakeURLRowWithID("http://www.frank-and-earnest.com/",
950 "Frank and Earnest Go Crash in Washington",
951 10, 0, 5, kNewRowID));
952
953 {
954 // Add a new URL.
955 String16Set existing_words(String16SetFromString16(
956 UTF8ToUTF16("http www and com crash in"), NULL));
957 // New words: frank, earnest, go, washington.
958 String16Set added_words(String16SetFromString16(
959 UTF8ToUTF16("frank earnest go washington"), NULL));
960 String16Set removed_words;
961 CacheChecker cache_checker(url_index_, CacheChecker::URL_ADDED,
962 kNewRowID, existing_words, added_words, removed_words);
963 UpdateURL(new_row);
964 }
965
966 URLRow old_row(new_row);
967 {
968 // Update an existing URL resulting in a net addition of words.
969 old_row.set_title(UTF8ToUTF16(
970 "Frank and Earnest Go Crazy in Draper Utah USA"));
971 String16Set existing_words(String16SetFromString16(
972 UTF8ToUTF16("http www and com in frank earnest go"), NULL));
973 String16Set added_words(String16SetFromString16(
974 UTF8ToUTF16("crazy draper utah usa"), NULL));
975 String16Set removed_words(String16SetFromString16(
976 UTF8ToUTF16("washington crash"), NULL));
977 CacheChecker cache_checker(url_index_, CacheChecker::URL_UPDATED,
978 kNewRowID, existing_words, added_words, removed_words);
979 UpdateURL(old_row);
980 }
981
982 {
983 // Update an existing URL resulting in a net removal of words.
984 old_row.set_title(UTF8ToUTF16("Frank and Earnest Go Crazy Crazy"));
985 String16Set existing_words(String16SetFromString16(
986 UTF8ToUTF16("http www and com frank earnest go crazy"), NULL));
987 String16Set added_words;
988 String16Set removed_words(String16SetFromString16(
989 UTF8ToUTF16("in draper utah usa"), NULL));
990 CacheChecker cache_checker(url_index_, CacheChecker::URL_UPDATED,
991 kNewRowID, existing_words, added_words, removed_words);
992 UpdateURL(old_row);
993 }
994
995 {
996 // Delete an existing URL.
997 old_row.set_title(UTF8ToUTF16("Frank and Earnest Go Crazy Crazy"));
998 String16Set existing_words;
999 String16Set added_words;
1000 String16Set removed_words(String16SetFromString16(
1001 UTF8ToUTF16("http www and com frank earnest go crazy"), NULL));
1002 CacheChecker cache_checker(url_index_, CacheChecker::URL_REMOVED,
1003 kNewRowID, existing_words, added_words, removed_words);
1004 DeleteURL(old_row.url());
1005 }
1006 }
1007
1008 // InterposingCacheDatabase ----------------------------------------------------
1009
1010 // This class allows certain InMemoryURLCacheDatabase methods to be intercepted
1011 // for purposes of recording or simulating failures.
1012 class InterposingCacheDatabase : public InMemoryURLCacheDatabase {
1013 public:
1014 InterposingCacheDatabase();
1015
1016 virtual bool Reset() OVERRIDE;
1017 virtual bool Refresh(const URLIndexPrivateData& index_data) OVERRIDE;
1018 virtual void AddWordToWordsTask(WordID word_id,
1019 const string16& uni_word) OVERRIDE;
1020
1021 void set_simulate_update_fail(bool fail) { simulate_update_fail_ = fail; }
1022 void set_simulate_refresh_fail(bool fail) { simulate_refresh_fail_ = fail; }
1023 void set_tracking_calls(bool tracking) { tracking_calls_ = tracking; }
1024 int reset_calling_sequence() const { return reset_calling_sequence_; }
1025 int refresh_calling_sequence() const { return refresh_calling_sequence_; }
1026 void set_update_error(int error) { update_error_ = error; }
1027 bool failure_occurred() const { return update_error_ != SQLITE_OK; }
1028
1029 private:
1030 virtual ~InterposingCacheDatabase() {}
1031
1032 bool simulate_update_fail_;
1033 bool simulate_refresh_fail_;
1034 int next_calling_sequence_;
1035 bool tracking_calls_;
1036 int reset_calling_sequence_;
1037 int refresh_calling_sequence_;
1038 };
1039
1040 InterposingCacheDatabase::InterposingCacheDatabase()
1041 : simulate_update_fail_(false),
1042 simulate_refresh_fail_(false),
1043 next_calling_sequence_(0),
1044 tracking_calls_(false),
1045 reset_calling_sequence_(-1),
1046 refresh_calling_sequence_(-1) {
1047 }
1048
1049 bool InterposingCacheDatabase::Reset() {
1050 bool success = InMemoryURLCacheDatabase::Reset();
1051 if (tracking_calls_)
1052 reset_calling_sequence_ = next_calling_sequence_++;
1053 return success;
1054 }
1055
1056 bool InterposingCacheDatabase::Refresh(
1057 const URLIndexPrivateData& index_data) {
1058 bool success =
1059 !simulate_refresh_fail_ && InMemoryURLCacheDatabase::Refresh(index_data);
1060 if (tracking_calls_)
1061 refresh_calling_sequence_ = next_calling_sequence_++;
1062 return success;
1063 }
1064
1065 void InterposingCacheDatabase::AddWordToWordsTask(
1066 WordID word_id,
1067 const string16& uni_word) {
1068 if (simulate_update_fail_)
1069 set_update_error(SQLITE_CORRUPT);
1070 else
1071 InMemoryURLCacheDatabase::AddWordToWordsTask(word_id, uni_word);
1072 }
1073
1074 // IntercessionaryIndexTest ----------------------------------------------------
1075
1076 // Tests which intercede in some way with the normal operation of the index,
1077 // its private data, and/or the cache database.
1078 class IntercessionaryIndexTest : public InMemoryURLIndexBaseTest {
1079 public:
1080 IntercessionaryIndexTest();
1081 ~IntercessionaryIndexTest() {}
1082
1083 void SetUp() OVERRIDE;
1084
1085 // Provides custom test data file name.
1086 virtual FilePath::StringType TestDBName() const OVERRIDE;
1087
1088 protected:
1089 scoped_refptr<InterposingCacheDatabase> test_db_;
1090 URLIndexPrivateData* private_data_;
1091 };
1092
1093 IntercessionaryIndexTest::IntercessionaryIndexTest()
1094 : test_db_(new InterposingCacheDatabase) {
1095 }
1096
1097 void IntercessionaryIndexTest::SetUp() {
1098 // Set things up without enabling the cache database.
1099 InMemoryURLIndexBaseTest::SetUp();
1100 LoadIndex();
1101 DCHECK(url_index_->index_available());
1102
1103 // Enabled our custom database and refresh it.
1104 FilePath dir_path;
1105 private_data_ = GetPrivateData();
1106 DCHECK(private_data_->GetCacheDBPath(&dir_path));
1107 base::SequencedWorkerPool::SequenceToken sequence_token =
1108 url_index_->sequence_token_for_testing();
1109 content::BrowserThread::GetBlockingPool()->PostWorkerTask(FROM_HERE,
1110 base::Bind(base::IgnoreResult(&InMemoryURLCacheDatabase::Init),
1111 test_db_, dir_path, sequence_token));
1112 content::BrowserThread::GetBlockingPool()->FlushForTesting();
1113 private_data_->SetCacheDatabaseForTesting(test_db_);
1114 private_data_->set_cache_enabled(true);
1115 content::BrowserThread::GetBlockingPool()->PostWorkerTask(FROM_HERE,
1116 base::Bind(&URLIndexPrivateData::RefreshCacheTask, private_data_));
1117 content::BrowserThread::GetBlockingPool()->FlushForTesting();
1118 test_db_->set_tracking_calls(true);
1119 }
1120
1121 FilePath::StringType IntercessionaryIndexTest::TestDBName() const {
1122 return FILE_PATH_LITERAL("url_history_provider_test.db.txt");
1123 }
1124
1125 TEST_F(IntercessionaryIndexTest, CacheDatabaseFailure) {
1126 // Perform an update but do not fail.
1127 const URLID kNewRowID = 250;
1128 URLRow new_row(MakeURLRowWithID("http://www.frank-and-earnest.com/",
1129 "Frank and Earnest Go Crash in Washington",
1130 10, 0, 5, kNewRowID));
1131 UpdateURL(new_row);
1132 EXPECT_EQ(-1, test_db_->reset_calling_sequence());
1133 EXPECT_EQ(-1, test_db_->refresh_calling_sequence());
1134 EXPECT_FALSE(test_db_->failure_occurred());
1135 EXPECT_TRUE(private_data_->cache_enabled());
1136
1137 // Perform an update that fails but remediation succeeds.
1138 test_db_->set_simulate_update_fail(true);
1139 URLRow old_row(new_row);
1140 old_row.set_title(UTF8ToUTF16(
1141 "Frank and Earnest Go Crazy in Draper Utah USA"));
1142 content::WindowedNotificationObserver update_failure_observer(
1143 chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE,
1144 content::NotificationService::AllSources());
1145 UpdateURL(old_row);
1146 update_failure_observer.Wait();
1147 // Wait for the pending reset and refresh to complete.
1148 content::BrowserThread::GetBlockingPool()->FlushForTesting();
1149 EXPECT_EQ(0, test_db_->reset_calling_sequence());
1150 EXPECT_EQ(1, test_db_->refresh_calling_sequence());
1151 EXPECT_TRUE(test_db_->failure_occurred());
1152 EXPECT_TRUE(private_data_->cache_enabled());
1153
1154 // Perform an update that fails and remediation fails.
1155 test_db_->set_simulate_update_fail(true);
1156 test_db_->set_simulate_refresh_fail(true);
1157 test_db_->set_update_error(SQLITE_OK);
1158 old_row.set_title(UTF8ToUTF16(
1159 "Frank and Earnest Light Up Dizzy World"));
1160 content::WindowedNotificationObserver refresh_failure_observer(
1161 chrome::NOTIFICATION_IN_MEMORY_URL_CACHE_DATABASE_FAILURE,
1162 content::NotificationService::AllSources());
1163 UpdateURL(old_row);
1164 refresh_failure_observer.Wait();
1165 // Wait for the pending reset and refresh to complete.
1166 content::BrowserThread::GetBlockingPool()->FlushForTesting();
1167 EXPECT_EQ(2, test_db_->reset_calling_sequence());
1168 EXPECT_EQ(3, test_db_->refresh_calling_sequence());
1169 EXPECT_TRUE(test_db_->failure_occurred());
1170 EXPECT_FALSE(private_data_->cache_enabled());
1171 }
1172
1173 TEST_F(IntercessionaryIndexTest, ShutdownDuringCacheRefresh) {
1174 // Pretend that the cache is dysfunctional.
1175 private_data_->set_cache_enabled(false);
1176 // Kick off a refresh and immediately shut down.
1177 url_index_->PostRefreshCacheTask();
1178 url_index_->Shutdown();
1179 // The index should still be viable but the cache should have been shut down.
1180 EXPECT_FALSE(private_data_->cache_enabled());
1181 EXPECT_TRUE(url_index_->index_available());
1182 } 1162 }
1183 1163
1184 } // namespace history 1164 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/in_memory_url_index_types_unittest.cc ('k') | chrome/browser/history/scored_history_match.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698