| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <set> | |
| 6 | |
| 7 #include "base/file_util.h" | |
| 8 #include "base/files/file_path.h" | |
| 9 #include "base/message_loop/message_loop.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "chrome/browser/history/text_database_manager.h" | |
| 12 #include "chrome/browser/history/visit_database.h" | |
| 13 #include "sql/connection.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 using base::Time; | |
| 17 using base::TimeDelta; | |
| 18 using base::TimeTicks; | |
| 19 | |
| 20 namespace history { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 const char* kURL1 = "http://www.google.com/asdf"; | |
| 25 const char* kTitle1 = "Google A"; | |
| 26 const char* kBody1 = "FOO page one."; | |
| 27 | |
| 28 const char* kURL2 = "http://www.google.com/qwer"; | |
| 29 const char* kTitle2 = "Google B"; | |
| 30 const char* kBody2 = "FOO two."; | |
| 31 | |
| 32 const char* kURL3 = "http://www.google.com/zxcv"; | |
| 33 const char* kTitle3 = "Google C"; | |
| 34 const char* kBody3 = "FOO drei"; | |
| 35 | |
| 36 const char* kURL4 = "http://www.google.com/hjkl"; | |
| 37 const char* kTitle4 = "Google D"; | |
| 38 const char* kBody4 = "FOO lalala four."; | |
| 39 | |
| 40 const char* kURL5 = "http://www.google.com/uiop"; | |
| 41 const char* kTitle5 = "Google cinq"; | |
| 42 const char* kBody5 = "FOO page one."; | |
| 43 | |
| 44 // This provides a simple implementation of a URL+VisitDatabase using an | |
| 45 // in-memory sqlite connection. The text database manager expects to be able to | |
| 46 // update the visit database to keep in sync. | |
| 47 class InMemDB : public URLDatabase, public VisitDatabase { | |
| 48 public: | |
| 49 InMemDB() { | |
| 50 EXPECT_TRUE(db_.OpenInMemory()); | |
| 51 CreateURLTable(false); | |
| 52 InitVisitTable(); | |
| 53 } | |
| 54 virtual ~InMemDB() { | |
| 55 } | |
| 56 | |
| 57 private: | |
| 58 virtual sql::Connection& GetDB() OVERRIDE { return db_; } | |
| 59 | |
| 60 sql::Connection db_; | |
| 61 | |
| 62 DISALLOW_COPY_AND_ASSIGN(InMemDB); | |
| 63 }; | |
| 64 | |
| 65 // Adds all the pages once, and the first page once more in the next month. | |
| 66 // The times of all the pages will be filled into |*times|. | |
| 67 void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db, | |
| 68 std::vector<Time>* times) { | |
| 69 Time::Exploded exploded; | |
| 70 memset(&exploded, 0, sizeof(Time::Exploded)); | |
| 71 | |
| 72 // Put the visits in two different months so it will query across databases. | |
| 73 exploded.year = 2008; | |
| 74 exploded.month = 1; | |
| 75 exploded.day_of_month = 3; | |
| 76 | |
| 77 VisitRow visit_row; | |
| 78 visit_row.url_id = 1; | |
| 79 visit_row.visit_time = Time::FromUTCExploded(exploded); | |
| 80 visit_row.referring_visit = 0; | |
| 81 visit_row.transition = content::PageTransitionFromInt(0); | |
| 82 visit_row.segment_id = 0; | |
| 83 visit_row.is_indexed = false; | |
| 84 visit_db->AddVisit(&visit_row, SOURCE_BROWSED); | |
| 85 | |
| 86 times->push_back(visit_row.visit_time); | |
| 87 manager.AddPageData(GURL(kURL1), visit_row.url_id, visit_row.visit_id, | |
| 88 visit_row.visit_time, UTF8ToUTF16(kTitle1), | |
| 89 UTF8ToUTF16(kBody1)); | |
| 90 | |
| 91 exploded.day_of_month++; | |
| 92 visit_row.url_id = 2; | |
| 93 visit_row.visit_time = Time::FromUTCExploded(exploded); | |
| 94 visit_db->AddVisit(&visit_row, SOURCE_BROWSED); | |
| 95 times->push_back(visit_row.visit_time); | |
| 96 manager.AddPageData(GURL(kURL2), visit_row.url_id, visit_row.visit_id, | |
| 97 visit_row.visit_time, UTF8ToUTF16(kTitle2), | |
| 98 UTF8ToUTF16(kBody2)); | |
| 99 | |
| 100 exploded.day_of_month++; | |
| 101 visit_row.url_id = 2; | |
| 102 visit_row.visit_time = Time::FromUTCExploded(exploded); | |
| 103 visit_db->AddVisit(&visit_row, SOURCE_BROWSED); | |
| 104 times->push_back(visit_row.visit_time); | |
| 105 manager.AddPageData(GURL(kURL3), visit_row.url_id, visit_row.visit_id, | |
| 106 visit_row.visit_time, UTF8ToUTF16(kTitle3), | |
| 107 UTF8ToUTF16(kBody3)); | |
| 108 | |
| 109 // Put the next ones in the next month. | |
| 110 exploded.month++; | |
| 111 visit_row.url_id = 2; | |
| 112 visit_row.visit_time = Time::FromUTCExploded(exploded); | |
| 113 visit_db->AddVisit(&visit_row, SOURCE_BROWSED); | |
| 114 times->push_back(visit_row.visit_time); | |
| 115 manager.AddPageData(GURL(kURL4), visit_row.url_id, visit_row.visit_id, | |
| 116 visit_row.visit_time, UTF8ToUTF16(kTitle4), | |
| 117 UTF8ToUTF16(kBody4)); | |
| 118 | |
| 119 exploded.day_of_month++; | |
| 120 visit_row.url_id = 2; | |
| 121 visit_row.visit_time = Time::FromUTCExploded(exploded); | |
| 122 visit_db->AddVisit(&visit_row, SOURCE_BROWSED); | |
| 123 times->push_back(visit_row.visit_time); | |
| 124 manager.AddPageData(GURL(kURL5), visit_row.url_id, visit_row.visit_id, | |
| 125 visit_row.visit_time, UTF8ToUTF16(kTitle5), | |
| 126 UTF8ToUTF16(kBody5)); | |
| 127 | |
| 128 // Put the first one in again in the second month. | |
| 129 exploded.day_of_month++; | |
| 130 visit_row.url_id = 2; | |
| 131 visit_row.visit_time = Time::FromUTCExploded(exploded); | |
| 132 visit_db->AddVisit(&visit_row, SOURCE_BROWSED); | |
| 133 times->push_back(visit_row.visit_time); | |
| 134 manager.AddPageData(GURL(kURL1), visit_row.url_id, visit_row.visit_id, | |
| 135 visit_row.visit_time, UTF8ToUTF16(kTitle1), | |
| 136 UTF8ToUTF16(kBody1)); | |
| 137 } | |
| 138 | |
| 139 bool ResultsHaveURL(const std::vector<TextDatabase::Match>& results, | |
| 140 const char* url) { | |
| 141 GURL gurl(url); | |
| 142 for (size_t i = 0; i < results.size(); i++) { | |
| 143 if (results[i].url == gurl) | |
| 144 return true; | |
| 145 } | |
| 146 return false; | |
| 147 } | |
| 148 | |
| 149 } // namespace | |
| 150 | |
| 151 class TextDatabaseManagerTest : public testing::Test { | |
| 152 public: | |
| 153 // Called manually by the test so it can report failure to initialize. | |
| 154 bool Init() { | |
| 155 return file_util::CreateNewTempDirectory( | |
| 156 FILE_PATH_LITERAL("TestSearchTest"), &dir_); | |
| 157 } | |
| 158 | |
| 159 protected: | |
| 160 virtual void SetUp() { | |
| 161 } | |
| 162 | |
| 163 virtual void TearDown() { | |
| 164 base::DeleteFile(dir_, true); | |
| 165 } | |
| 166 | |
| 167 base::MessageLoop message_loop_; | |
| 168 | |
| 169 // Directory containing the databases. | |
| 170 base::FilePath dir_; | |
| 171 }; | |
| 172 | |
| 173 // Tests basic querying. | |
| 174 TEST_F(TextDatabaseManagerTest, InsertQuery) { | |
| 175 ASSERT_TRUE(Init()); | |
| 176 InMemDB visit_db; | |
| 177 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 178 ASSERT_TRUE(manager.Init(NULL)); | |
| 179 | |
| 180 std::vector<Time> times; | |
| 181 AddAllPages(manager, &visit_db, ×); | |
| 182 | |
| 183 QueryOptions options; | |
| 184 options.begin_time = times[0] - TimeDelta::FromDays(100); | |
| 185 options.end_time = times[times.size() - 1] + TimeDelta::FromDays(100); | |
| 186 std::vector<TextDatabase::Match> results; | |
| 187 Time first_time_searched; | |
| 188 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, | |
| 189 &results, &first_time_searched); | |
| 190 | |
| 191 // We should have matched every page. | |
| 192 EXPECT_EQ(6U, results.size()); | |
| 193 EXPECT_TRUE(ResultsHaveURL(results, kURL1)); | |
| 194 EXPECT_TRUE(ResultsHaveURL(results, kURL2)); | |
| 195 EXPECT_TRUE(ResultsHaveURL(results, kURL3)); | |
| 196 EXPECT_TRUE(ResultsHaveURL(results, kURL4)); | |
| 197 EXPECT_TRUE(ResultsHaveURL(results, kURL5)); | |
| 198 | |
| 199 // The first time searched should have been the first page's time or before | |
| 200 // (it could have eliminated some time for us). | |
| 201 EXPECT_TRUE(first_time_searched <= times[0]); | |
| 202 } | |
| 203 | |
| 204 // Tests that adding page components piecemeal will get them added properly. | |
| 205 // This does not supply a visit to update, this mode is used only by the unit | |
| 206 // tests right now, but we test it anyway. | |
| 207 TEST_F(TextDatabaseManagerTest, InsertCompleteNoVisit) { | |
| 208 ASSERT_TRUE(Init()); | |
| 209 InMemDB visit_db; | |
| 210 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 211 ASSERT_TRUE(manager.Init(NULL)); | |
| 212 | |
| 213 // First add one without a visit. | |
| 214 const GURL url(kURL1); | |
| 215 manager.AddPageURL(url, 0, 0, Time::Now()); | |
| 216 manager.AddPageTitle(url, UTF8ToUTF16(kTitle1)); | |
| 217 manager.AddPageContents(url, UTF8ToUTF16(kBody1)); | |
| 218 | |
| 219 // Check that the page got added. | |
| 220 QueryOptions options; | |
| 221 std::vector<TextDatabase::Match> results; | |
| 222 Time first_time_searched; | |
| 223 | |
| 224 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, | |
| 225 &results, &first_time_searched); | |
| 226 ASSERT_EQ(1U, results.size()); | |
| 227 EXPECT_EQ(kTitle1, UTF16ToUTF8(results[0].title)); | |
| 228 } | |
| 229 | |
| 230 // Like InsertCompleteNoVisit but specifies a visit to update. We check that the | |
| 231 // visit was updated properly. | |
| 232 TEST_F(TextDatabaseManagerTest, InsertCompleteVisit) { | |
| 233 ASSERT_TRUE(Init()); | |
| 234 InMemDB visit_db; | |
| 235 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 236 ASSERT_TRUE(manager.Init(NULL)); | |
| 237 | |
| 238 // First add a visit to a page. We can just make up a URL ID since there is | |
| 239 // not actually any URL database around. | |
| 240 VisitRow visit; | |
| 241 visit.url_id = 1; | |
| 242 visit.visit_time = Time::Now(); | |
| 243 visit.referring_visit = 0; | |
| 244 visit.transition = content::PAGE_TRANSITION_LINK; | |
| 245 visit.segment_id = 0; | |
| 246 visit.is_indexed = false; | |
| 247 visit_db.AddVisit(&visit, SOURCE_BROWSED); | |
| 248 | |
| 249 // Add a full text indexed entry for that visit. | |
| 250 const GURL url(kURL2); | |
| 251 manager.AddPageURL(url, visit.url_id, visit.visit_id, visit.visit_time); | |
| 252 manager.AddPageContents(url, UTF8ToUTF16(kBody2)); | |
| 253 manager.AddPageTitle(url, UTF8ToUTF16(kTitle2)); | |
| 254 | |
| 255 // Check that the page got added. | |
| 256 QueryOptions options; | |
| 257 std::vector<TextDatabase::Match> results; | |
| 258 Time first_time_searched; | |
| 259 | |
| 260 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, | |
| 261 &results, &first_time_searched); | |
| 262 ASSERT_EQ(1U, results.size()); | |
| 263 EXPECT_EQ(kTitle2, UTF16ToUTF8(results[0].title)); | |
| 264 | |
| 265 // Check that the visit got updated for its new indexed state. | |
| 266 VisitRow out_visit; | |
| 267 ASSERT_TRUE(visit_db.GetRowForVisit(visit.visit_id, &out_visit)); | |
| 268 EXPECT_TRUE(out_visit.is_indexed); | |
| 269 } | |
| 270 | |
| 271 // Tests that partial inserts that expire are added to the database. | |
| 272 TEST_F(TextDatabaseManagerTest, InsertPartial) { | |
| 273 ASSERT_TRUE(Init()); | |
| 274 InMemDB visit_db; | |
| 275 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 276 ASSERT_TRUE(manager.Init(NULL)); | |
| 277 | |
| 278 // Add the first one with just a URL. | |
| 279 GURL url1(kURL1); | |
| 280 manager.AddPageURL(url1, 0, 0, Time::Now()); | |
| 281 | |
| 282 // Now add a second one with a URL and title. | |
| 283 GURL url2(kURL2); | |
| 284 manager.AddPageURL(url2, 0, 0, Time::Now()); | |
| 285 manager.AddPageTitle(url2, UTF8ToUTF16(kTitle2)); | |
| 286 | |
| 287 // The third one has a URL and body. | |
| 288 GURL url3(kURL3); | |
| 289 manager.AddPageURL(url3, 0, 0, Time::Now()); | |
| 290 manager.AddPageContents(url3, UTF8ToUTF16(kBody3)); | |
| 291 | |
| 292 // Expire stuff very fast. This assumes that the time between the first | |
| 293 // AddPageURL and this line is less than the expiration time (20 seconds). | |
| 294 TimeTicks added_time = TimeTicks::Now(); | |
| 295 TimeTicks expire_time = added_time + TimeDelta::FromSeconds(5); | |
| 296 manager.FlushOldChangesForTime(expire_time); | |
| 297 | |
| 298 // Do a query, nothing should be added yet. | |
| 299 QueryOptions options; | |
| 300 std::vector<TextDatabase::Match> results; | |
| 301 Time first_time_searched; | |
| 302 manager.GetTextMatches(UTF8ToUTF16("google"), options, | |
| 303 &results, &first_time_searched); | |
| 304 ASSERT_EQ(0U, results.size()); | |
| 305 | |
| 306 // Compute a time threshold that will cause everything to be flushed, and | |
| 307 // poke at the manager's internals to cause this to happen. | |
| 308 expire_time = added_time + TimeDelta::FromDays(1); | |
| 309 manager.FlushOldChangesForTime(expire_time); | |
| 310 | |
| 311 // Now we should have all 3 URLs added. | |
| 312 manager.GetTextMatches(UTF8ToUTF16("google"), options, | |
| 313 &results, &first_time_searched); | |
| 314 ASSERT_EQ(3U, results.size()); | |
| 315 EXPECT_TRUE(ResultsHaveURL(results, kURL1)); | |
| 316 EXPECT_TRUE(ResultsHaveURL(results, kURL2)); | |
| 317 EXPECT_TRUE(ResultsHaveURL(results, kURL3)); | |
| 318 } | |
| 319 | |
| 320 // Tests that partial inserts (due to timeouts) will still get updated if the | |
| 321 // data comes in later. | |
| 322 TEST_F(TextDatabaseManagerTest, PartialComplete) { | |
| 323 ASSERT_TRUE(Init()); | |
| 324 InMemDB visit_db; | |
| 325 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 326 ASSERT_TRUE(manager.Init(NULL)); | |
| 327 | |
| 328 Time added_time = Time::Now(); | |
| 329 GURL url(kURL1); | |
| 330 | |
| 331 // We have to have the URL in the URL and visit databases for this test to | |
| 332 // work. | |
| 333 URLRow url_row(url); | |
| 334 url_row.set_title(UTF8ToUTF16("chocolate")); | |
| 335 URLID url_id = visit_db.AddURL(url_row); | |
| 336 ASSERT_TRUE(url_id); | |
| 337 VisitRow visit_row; | |
| 338 visit_row.url_id = url_id; | |
| 339 visit_row.visit_time = added_time; | |
| 340 visit_db.AddVisit(&visit_row, SOURCE_BROWSED); | |
| 341 | |
| 342 // Add a URL with no title or body, and say that it expired. | |
| 343 manager.AddPageURL(url, 0, 0, added_time); | |
| 344 TimeTicks expire_time = TimeTicks::Now() + TimeDelta::FromDays(1); | |
| 345 manager.FlushOldChangesForTime(expire_time); | |
| 346 | |
| 347 // Add the title. We should be able to query based on that. The title in the | |
| 348 // URL row we set above should not come into the picture. | |
| 349 manager.AddPageTitle(url, UTF8ToUTF16("Some unique title")); | |
| 350 Time first_time_searched; | |
| 351 QueryOptions options; | |
| 352 std::vector<TextDatabase::Match> results; | |
| 353 manager.GetTextMatches(UTF8ToUTF16("unique"), options, | |
| 354 &results, &first_time_searched); | |
| 355 EXPECT_EQ(1U, results.size()); | |
| 356 manager.GetTextMatches(UTF8ToUTF16("chocolate"), options, | |
| 357 &results, &first_time_searched); | |
| 358 EXPECT_EQ(0U, results.size()); | |
| 359 | |
| 360 // Now add the body, which should be queryable. | |
| 361 manager.AddPageContents(url, UTF8ToUTF16("Very awesome body")); | |
| 362 manager.GetTextMatches(UTF8ToUTF16("awesome"), options, &results, &first_time_
searched); | |
| 363 EXPECT_EQ(1U, results.size()); | |
| 364 | |
| 365 // Adding the body will actually copy the title from the URL table rather | |
| 366 // than the previously indexed row (we made them not match above). This isn't | |
| 367 // necessarily what we want, but it's how it's implemented, and we don't want | |
| 368 // to regress it. | |
| 369 manager.GetTextMatches(UTF8ToUTF16("chocolate"), options, &results, &first_tim
e_searched); | |
| 370 EXPECT_EQ(1U, results.size()); | |
| 371 } | |
| 372 | |
| 373 // Tests that changes get properly committed to disk. | |
| 374 TEST_F(TextDatabaseManagerTest, Writing) { | |
| 375 ASSERT_TRUE(Init()); | |
| 376 | |
| 377 QueryOptions options; | |
| 378 std::vector<TextDatabase::Match> results; | |
| 379 Time first_time_searched; | |
| 380 | |
| 381 InMemDB visit_db; | |
| 382 | |
| 383 // Create the manager and write some stuff to it. | |
| 384 { | |
| 385 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 386 ASSERT_TRUE(manager.Init(NULL)); | |
| 387 | |
| 388 std::vector<Time> times; | |
| 389 AddAllPages(manager, &visit_db, ×); | |
| 390 | |
| 391 // We should have matched every page. | |
| 392 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, &results, &first_time_se
arched); | |
| 393 EXPECT_EQ(6U, results.size()); | |
| 394 } | |
| 395 results.clear(); | |
| 396 | |
| 397 // Recreate the manager and make sure it finds the written stuff. | |
| 398 { | |
| 399 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 400 ASSERT_TRUE(manager.Init(NULL)); | |
| 401 | |
| 402 // We should have matched every page again. | |
| 403 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, | |
| 404 &results, &first_time_searched); | |
| 405 EXPECT_EQ(6U, results.size()); | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 // Tests that changes get properly committed to disk, as in the Writing test | |
| 410 // above, but when there is a transaction around the adds. | |
| 411 TEST_F(TextDatabaseManagerTest, WritingTransaction) { | |
| 412 ASSERT_TRUE(Init()); | |
| 413 | |
| 414 QueryOptions options; | |
| 415 std::vector<TextDatabase::Match> results; | |
| 416 Time first_time_searched; | |
| 417 | |
| 418 InMemDB visit_db; | |
| 419 | |
| 420 // Create the manager and write some stuff to it. | |
| 421 { | |
| 422 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 423 ASSERT_TRUE(manager.Init(NULL)); | |
| 424 | |
| 425 std::vector<Time> times; | |
| 426 manager.BeginTransaction(); | |
| 427 AddAllPages(manager, &visit_db, ×); | |
| 428 // "Forget" to commit, it should be autocommittedd for us. | |
| 429 | |
| 430 // We should have matched every page. | |
| 431 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, | |
| 432 &results, &first_time_searched); | |
| 433 EXPECT_EQ(6U, results.size()); | |
| 434 } | |
| 435 results.clear(); | |
| 436 | |
| 437 // Recreate the manager and make sure it finds the written stuff. | |
| 438 { | |
| 439 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 440 ASSERT_TRUE(manager.Init(NULL)); | |
| 441 | |
| 442 // We should have matched every page again. | |
| 443 manager.GetTextMatches(UTF8ToUTF16("FOO"), options, | |
| 444 &results, &first_time_searched); | |
| 445 EXPECT_EQ(6U, results.size()); | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 // Tests querying where the maximum number of items is met. | |
| 450 TEST_F(TextDatabaseManagerTest, QueryMax) { | |
| 451 ASSERT_TRUE(Init()); | |
| 452 InMemDB visit_db; | |
| 453 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 454 ASSERT_TRUE(manager.Init(NULL)); | |
| 455 | |
| 456 std::vector<Time> times; | |
| 457 AddAllPages(manager, &visit_db, ×); | |
| 458 | |
| 459 string16 foo = UTF8ToUTF16("FOO"); | |
| 460 | |
| 461 QueryOptions options; | |
| 462 options.begin_time = times[0] - TimeDelta::FromDays(100); | |
| 463 options.end_time = times[times.size() - 1] + TimeDelta::FromDays(100); | |
| 464 options.max_count = 2; | |
| 465 std::vector<TextDatabase::Match> results; | |
| 466 Time first_time_searched; | |
| 467 manager.GetTextMatches(foo, options, &results, &first_time_searched); | |
| 468 | |
| 469 // We should have gotten the last two pages as results (the first page is | |
| 470 // also the last). | |
| 471 EXPECT_EQ(2U, results.size()); | |
| 472 EXPECT_TRUE(first_time_searched <= times[4]); | |
| 473 EXPECT_TRUE(ResultsHaveURL(results, kURL5)); | |
| 474 EXPECT_TRUE(ResultsHaveURL(results, kURL1)); | |
| 475 | |
| 476 // Asking for 4 pages, the first one should be in another DB. | |
| 477 options.max_count = 4; | |
| 478 manager.GetTextMatches(foo, options, &results, &first_time_searched); | |
| 479 | |
| 480 EXPECT_EQ(4U, results.size()); | |
| 481 EXPECT_TRUE(first_time_searched <= times[4]); | |
| 482 EXPECT_TRUE(ResultsHaveURL(results, kURL3)); | |
| 483 EXPECT_TRUE(ResultsHaveURL(results, kURL4)); | |
| 484 EXPECT_TRUE(ResultsHaveURL(results, kURL5)); | |
| 485 EXPECT_TRUE(ResultsHaveURL(results, kURL1)); | |
| 486 } | |
| 487 | |
| 488 // Tests querying backwards in time in chunks. | |
| 489 TEST_F(TextDatabaseManagerTest, QueryBackwards) { | |
| 490 ASSERT_TRUE(Init()); | |
| 491 InMemDB visit_db; | |
| 492 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 493 ASSERT_TRUE(manager.Init(NULL)); | |
| 494 | |
| 495 std::vector<Time> times; | |
| 496 AddAllPages(manager, &visit_db, ×); | |
| 497 | |
| 498 string16 foo = UTF8ToUTF16("FOO"); | |
| 499 | |
| 500 // First do a query for all time, but with a max of 2. This will give us the | |
| 501 // last two results and will tell us where to start searching when we want | |
| 502 // to go back in time. | |
| 503 QueryOptions options; | |
| 504 options.begin_time = times[0] - TimeDelta::FromDays(100); | |
| 505 options.end_time = times[times.size() - 1] + TimeDelta::FromDays(100); | |
| 506 options.max_count = 2; | |
| 507 std::vector<TextDatabase::Match> results; | |
| 508 Time first_time_searched; | |
| 509 manager.GetTextMatches(foo, options, &results, &first_time_searched); | |
| 510 | |
| 511 // Check that we got the last two results. | |
| 512 EXPECT_EQ(2U, results.size()); | |
| 513 EXPECT_TRUE(first_time_searched <= times[4]); | |
| 514 EXPECT_TRUE(ResultsHaveURL(results, kURL5)); | |
| 515 EXPECT_TRUE(ResultsHaveURL(results, kURL1)); | |
| 516 | |
| 517 // Query the previous two URLs and make sure we got the correct ones. | |
| 518 options.end_time = first_time_searched; | |
| 519 manager.GetTextMatches(foo, options, &results, &first_time_searched); | |
| 520 EXPECT_EQ(2U, results.size()); | |
| 521 EXPECT_TRUE(first_time_searched <= times[2]); | |
| 522 EXPECT_TRUE(ResultsHaveURL(results, kURL3)); | |
| 523 EXPECT_TRUE(ResultsHaveURL(results, kURL4)); | |
| 524 | |
| 525 // Query the previous two URLs... | |
| 526 options.end_time = first_time_searched; | |
| 527 manager.GetTextMatches(foo, options, &results, &first_time_searched); | |
| 528 EXPECT_EQ(2U, results.size()); | |
| 529 EXPECT_TRUE(first_time_searched <= times[0]); | |
| 530 EXPECT_TRUE(ResultsHaveURL(results, kURL2)); | |
| 531 EXPECT_TRUE(ResultsHaveURL(results, kURL1)); | |
| 532 | |
| 533 // Try to query some more, there should be no results. | |
| 534 options.end_time = first_time_searched; | |
| 535 manager.GetTextMatches(foo, options, &results, &first_time_searched); | |
| 536 EXPECT_EQ(0U, results.size()); | |
| 537 } | |
| 538 | |
| 539 // Tests deletion of uncommitted entries. | |
| 540 TEST_F(TextDatabaseManagerTest, DeleteUncommitted) { | |
| 541 ASSERT_TRUE(Init()); | |
| 542 InMemDB visit_db; | |
| 543 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 544 ASSERT_TRUE(manager.Init(NULL)); | |
| 545 | |
| 546 manager.AddPageURL(GURL(kURL1), 0, 0, Time::FromInternalValue(1)); | |
| 547 manager.AddPageURL(GURL(kURL2), 0, 0, Time::FromInternalValue(2)); | |
| 548 manager.AddPageURL(GURL(kURL3), 0, 0, Time::FromInternalValue(3)); | |
| 549 manager.AddPageURL(GURL(kURL4), 0, 0, Time::FromInternalValue(4)); | |
| 550 manager.AddPageURL(GURL(kURL5), 0, 0, Time::FromInternalValue(5)); | |
| 551 | |
| 552 EXPECT_EQ(5u, manager.GetUncommittedEntryCountForTest()); | |
| 553 | |
| 554 // Should delete the first two entries. | |
| 555 manager.DeleteFromUncommitted(std::set<GURL>(), | |
| 556 Time::FromInternalValue(1), | |
| 557 Time::FromInternalValue(3)); | |
| 558 | |
| 559 EXPECT_EQ(3u, manager.GetUncommittedEntryCountForTest()); | |
| 560 | |
| 561 // Should delete the third entry. | |
| 562 { | |
| 563 std::set<GURL> urls; | |
| 564 urls.insert(GURL(kURL3)); | |
| 565 manager.DeleteFromUncommitted(urls, Time(), Time()); | |
| 566 } | |
| 567 | |
| 568 EXPECT_EQ(2u, manager.GetUncommittedEntryCountForTest()); | |
| 569 } | |
| 570 | |
| 571 // Tests deletion of uncommitted entries by time. | |
| 572 TEST_F(TextDatabaseManagerTest, DeleteUncommittedForTimes) { | |
| 573 ASSERT_TRUE(Init()); | |
| 574 InMemDB visit_db; | |
| 575 TextDatabaseManager manager(dir_, &visit_db, &visit_db); | |
| 576 ASSERT_TRUE(manager.Init(NULL)); | |
| 577 | |
| 578 manager.AddPageURL(GURL(kURL1), 0, 0, Time::FromInternalValue(2)); | |
| 579 manager.AddPageURL(GURL(kURL2), 0, 0, Time::FromInternalValue(3)); | |
| 580 manager.AddPageURL(GURL(kURL3), 0, 0, Time::FromInternalValue(4)); | |
| 581 manager.AddPageURL(GURL(kURL4), 0, 0, Time::FromInternalValue(5)); | |
| 582 manager.AddPageURL(GURL(kURL5), 0, 0, Time::FromInternalValue(6)); | |
| 583 | |
| 584 EXPECT_EQ(5u, manager.GetUncommittedEntryCountForTest()); | |
| 585 | |
| 586 std::vector<base::Time> times; | |
| 587 times.push_back(Time::FromInternalValue(9)); | |
| 588 times.push_back(Time::FromInternalValue(7)); | |
| 589 times.push_back(Time::FromInternalValue(5)); | |
| 590 times.push_back(Time::FromInternalValue(5)); | |
| 591 times.push_back(Time::FromInternalValue(3)); | |
| 592 times.push_back(Time::FromInternalValue(1)); | |
| 593 manager.DeleteFromUncommittedForTimes(times); | |
| 594 | |
| 595 EXPECT_EQ(3u, manager.GetUncommittedEntryCountForTest()); | |
| 596 } | |
| 597 | |
| 598 } // namespace history | |
| OLD | NEW |