Home | History | Annotate | Download | only in history
      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
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 #include <set>
      7 #include <vector>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/command_line.h"
     13 #include "base/file_util.h"
     14 #include "base/files/file_path.h"
     15 #include "base/memory/ref_counted.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/path_service.h"
     18 #include "base/platform_file.h"
     19 #include "base/strings/string16.h"
     20 #include "base/strings/string_number_conversions.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "chrome/browser/bookmarks/bookmark_model.h"
     23 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
     24 #include "chrome/browser/bookmarks/bookmark_utils.h"
     25 #include "chrome/browser/history/history_backend.h"
     26 #include "chrome/browser/history/history_notifications.h"
     27 #include "chrome/browser/history/history_service.h"
     28 #include "chrome/browser/history/history_service_factory.h"
     29 #include "chrome/browser/history/in_memory_database.h"
     30 #include "chrome/browser/history/in_memory_history_backend.h"
     31 #include "chrome/browser/history/visit_filter.h"
     32 #include "chrome/common/chrome_constants.h"
     33 #include "chrome/common/chrome_paths.h"
     34 #include "chrome/common/chrome_switches.h"
     35 #include "chrome/common/importer/imported_favicon_usage.h"
     36 #include "chrome/common/thumbnail_score.h"
     37 #include "chrome/test/base/testing_profile.h"
     38 #include "chrome/test/base/ui_test_utils.h"
     39 #include "chrome/tools/profiles/thumbnail-inl.h"
     40 #include "content/public/browser/notification_details.h"
     41 #include "content/public/browser/notification_source.h"
     42 #include "content/public/test/test_browser_thread.h"
     43 #include "testing/gtest/include/gtest/gtest.h"
     44 #include "third_party/skia/include/core/SkBitmap.h"
     45 #include "ui/gfx/codec/jpeg_codec.h"
     46 #include "ui/gfx/image/image.h"
     47 #include "url/gurl.h"
     48 
     49 using base::Time;
     50 using base::TimeDelta;
     51 
     52 // This file only tests functionality where it is most convenient to call the
     53 // backend directly. Most of the history backend functions are tested by the
     54 // history unit test. Because of the elaborate callbacks involved, this is no
     55 // harder than calling it directly for many things.
     56 
     57 namespace {
     58 
     59 // data we'll put into the thumbnail database
     60 static const unsigned char blob1[] =
     61     "12346102356120394751634516591348710478123649165419234519234512349134";
     62 
     63 static const gfx::Size kTinySize = gfx::Size(10, 10);
     64 static const gfx::Size kSmallSize = gfx::Size(16, 16);
     65 static const gfx::Size kLargeSize = gfx::Size(32, 32);
     66 
     67 // Comparison functions as to make it easier to check results of
     68 // GetFaviconBitmaps() and GetIconMappingsForPageURL().
     69 bool IconMappingLessThan(const history::IconMapping& a,
     70                          const history::IconMapping& b) {
     71   return a.icon_url < b.icon_url;
     72 }
     73 
     74 bool FaviconBitmapLessThan(const history::FaviconBitmap& a,
     75                            const history::FaviconBitmap& b) {
     76   return a.pixel_size.GetArea() < b.pixel_size.GetArea();
     77 }
     78 
     79 }  // namespace
     80 
     81 namespace history {
     82 
     83 class HistoryBackendTest;
     84 
     85 // This must be a separate object since HistoryBackend manages its lifetime.
     86 // This just forwards the messages we're interested in to the test object.
     87 class HistoryBackendTestDelegate : public HistoryBackend::Delegate {
     88  public:
     89   explicit HistoryBackendTestDelegate(HistoryBackendTest* test) : test_(test) {}
     90 
     91   virtual void NotifyProfileError(int backend_id,
     92                                   sql::InitStatus init_status) OVERRIDE {}
     93   virtual void SetInMemoryBackend(int backend_id,
     94                                   InMemoryHistoryBackend* backend) OVERRIDE;
     95   virtual void BroadcastNotifications(int type,
     96                                       HistoryDetails* details) OVERRIDE;
     97   virtual void DBLoaded(int backend_id) OVERRIDE;
     98   virtual void StartTopSitesMigration(int backend_id) OVERRIDE;
     99   virtual void NotifyVisitDBObserversOnAddVisit(
    100       const BriefVisitInfo& info) OVERRIDE {}
    101 
    102  private:
    103   // Not owned by us.
    104   HistoryBackendTest* test_;
    105 
    106   DISALLOW_COPY_AND_ASSIGN(HistoryBackendTestDelegate);
    107 };
    108 
    109 class HistoryBackendCancelableRequest
    110     : public CancelableRequestProvider,
    111       public CancelableRequestConsumerTSimple<int> {
    112  public:
    113   HistoryBackendCancelableRequest() {}
    114 
    115   template<class RequestType>
    116   CancelableRequestProvider::Handle MockScheduleOfRequest(
    117       RequestType* request) {
    118     AddRequest(request, this);
    119     return request->handle();
    120   }
    121 };
    122 
    123 class HistoryBackendTest : public testing::Test {
    124  public:
    125   HistoryBackendTest()
    126       : bookmark_model_(NULL),
    127         loaded_(false),
    128         num_broadcasted_notifications_(0),
    129         ui_thread_(content::BrowserThread::UI, &message_loop_) {
    130   }
    131 
    132   virtual ~HistoryBackendTest() {
    133   }
    134 
    135   // Callback for QueryMostVisited.
    136   void OnQueryMostVisited(CancelableRequestProvider::Handle handle,
    137                           history::MostVisitedURLList data) {
    138     most_visited_list_.swap(data);
    139   }
    140 
    141   // Callback for QueryFiltered.
    142   void OnQueryFiltered(CancelableRequestProvider::Handle handle,
    143                        const history::FilteredURLList& data) {
    144     filtered_list_ = data;
    145   }
    146 
    147   const history::MostVisitedURLList& get_most_visited_list() const {
    148     return most_visited_list_;
    149   }
    150 
    151   const history::FilteredURLList& get_filtered_list() const {
    152     return filtered_list_;
    153   }
    154 
    155   int num_broadcasted_notifications() const {
    156     return num_broadcasted_notifications_;
    157   }
    158 
    159  protected:
    160   scoped_refptr<HistoryBackend> backend_;  // Will be NULL on init failure.
    161   scoped_ptr<InMemoryHistoryBackend> mem_backend_;
    162 
    163   void AddRedirectChain(const char* sequence[], int page_id) {
    164     AddRedirectChainWithTransitionAndTime(sequence, page_id,
    165                                           content::PAGE_TRANSITION_LINK,
    166                                           Time::Now());
    167   }
    168 
    169   void AddRedirectChainWithTransitionAndTime(
    170       const char* sequence[],
    171       int page_id,
    172       content::PageTransition transition,
    173       base::Time time) {
    174     history::RedirectList redirects;
    175     for (int i = 0; sequence[i] != NULL; ++i)
    176       redirects.push_back(GURL(sequence[i]));
    177 
    178     int int_scope = 1;
    179     void* scope = 0;
    180     memcpy(&scope, &int_scope, sizeof(int_scope));
    181     history::HistoryAddPageArgs request(
    182         redirects.back(), time, scope, page_id, GURL(),
    183         redirects, transition, history::SOURCE_BROWSED,
    184         true);
    185     backend_->AddPage(request);
    186   }
    187 
    188   // Adds CLIENT_REDIRECT page transition.
    189   // |url1| is the source URL and |url2| is the destination.
    190   // |did_replace| is true if the transition is non-user initiated and the
    191   // navigation entry for |url2| has replaced that for |url1|. The possibly
    192   // updated transition code of the visit records for |url1| and |url2| is
    193   // returned by filling in |*transition1| and |*transition2|, respectively.
    194   // |time| is a time of the redirect.
    195   void  AddClientRedirect(const GURL& url1, const GURL& url2, bool did_replace,
    196                           base::Time time,
    197                           int* transition1, int* transition2) {
    198     void* const dummy_scope = reinterpret_cast<void*>(0x87654321);
    199     history::RedirectList redirects;
    200     if (url1.is_valid())
    201       redirects.push_back(url1);
    202     if (url2.is_valid())
    203       redirects.push_back(url2);
    204     HistoryAddPageArgs request(
    205         url2, time, dummy_scope, 0, url1,
    206         redirects, content::PAGE_TRANSITION_CLIENT_REDIRECT,
    207         history::SOURCE_BROWSED, did_replace);
    208     backend_->AddPage(request);
    209 
    210     *transition1 = getTransition(url1);
    211     *transition2 = getTransition(url2);
    212   }
    213 
    214   int getTransition(const GURL& url) {
    215     if (!url.is_valid())
    216       return 0;
    217     URLRow row;
    218     URLID id = backend_->db()->GetRowForURL(url, &row);
    219     VisitVector visits;
    220     EXPECT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
    221     return visits[0].transition;
    222   }
    223 
    224   base::FilePath getTestDir() {
    225     return test_dir_;
    226   }
    227 
    228   // Returns a gfx::Size vector with small size.
    229   const std::vector<gfx::Size> GetSizesSmall() {
    230     std::vector<gfx::Size> sizes_small;
    231     sizes_small.push_back(kSmallSize);
    232     return sizes_small;
    233   }
    234 
    235   // Returns a gfx::Size vector with large size.
    236   const std::vector<gfx::Size> GetSizesLarge() {
    237     std::vector<gfx::Size> sizes_large;
    238     sizes_large.push_back(kLargeSize);
    239     return sizes_large;
    240   }
    241 
    242   // Returns a gfx::Size vector with small and large sizes.
    243   const std::vector<gfx::Size> GetSizesSmallAndLarge() {
    244     std::vector<gfx::Size> sizes_small_and_large;
    245     sizes_small_and_large.push_back(kSmallSize);
    246     sizes_small_and_large.push_back(kLargeSize);
    247     return sizes_small_and_large;
    248   }
    249 
    250   // Returns a gfx::Size vector with tiny, small and large sizes.
    251   const std::vector<gfx::Size> GetSizesTinySmallAndLarge() {
    252     std::vector<gfx::Size> sizes_tiny_small_and_large;
    253     sizes_tiny_small_and_large.push_back(kTinySize);
    254     sizes_tiny_small_and_large.push_back(kSmallSize);
    255     sizes_tiny_small_and_large.push_back(kLargeSize);
    256     return sizes_tiny_small_and_large;
    257   }
    258 
    259   // Returns 1x and 2x scale factors.
    260   const std::vector<ui::ScaleFactor> GetScaleFactors1x2x() {
    261     std::vector<ui::ScaleFactor> scale_factors_1x_2x;
    262     scale_factors_1x_2x.push_back(ui::SCALE_FACTOR_100P);
    263     scale_factors_1x_2x.push_back(ui::SCALE_FACTOR_200P);
    264     return scale_factors_1x_2x;
    265   }
    266 
    267   // Returns the number of icon mappings of |icon_type| to |page_url|.
    268   size_t NumIconMappingsForPageURL(const GURL& page_url,
    269                                    chrome::IconType icon_type) {
    270     std::vector<IconMapping> icon_mappings;
    271     backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type,
    272                                                        &icon_mappings);
    273     return icon_mappings.size();
    274   }
    275 
    276   // Returns the icon mappings for |page_url| sorted alphabetically by icon
    277   // URL in ascending order. Returns true if there is at least one icon
    278   // mapping.
    279   bool GetSortedIconMappingsForPageURL(
    280       const GURL& page_url,
    281       std::vector<IconMapping>* icon_mappings) {
    282     if (!backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
    283         icon_mappings)) {
    284       return false;
    285     }
    286     std::sort(icon_mappings->begin(), icon_mappings->end(),
    287               IconMappingLessThan);
    288     return true;
    289   }
    290 
    291   // Returns the favicon bitmaps for |icon_id| sorted by pixel size in
    292   // ascending order. Returns true if there is at least one favicon bitmap.
    293   bool GetSortedFaviconBitmaps(chrome::FaviconID icon_id,
    294                                std::vector<FaviconBitmap>* favicon_bitmaps) {
    295     if (!backend_->thumbnail_db_->GetFaviconBitmaps(icon_id, favicon_bitmaps))
    296       return false;
    297     std::sort(favicon_bitmaps->begin(), favicon_bitmaps->end(),
    298               FaviconBitmapLessThan);
    299     return true;
    300   }
    301 
    302   // Returns true if there is exactly one favicon bitmap associated to
    303   // |favicon_id|. If true, returns favicon bitmap in output parameter.
    304   bool GetOnlyFaviconBitmap(const chrome::FaviconID icon_id,
    305                             FaviconBitmap* favicon_bitmap) {
    306     std::vector<FaviconBitmap> favicon_bitmaps;
    307     if (!backend_->thumbnail_db_->GetFaviconBitmaps(icon_id, &favicon_bitmaps))
    308       return false;
    309     if (favicon_bitmaps.size() != 1)
    310       return false;
    311     *favicon_bitmap = favicon_bitmaps[0];
    312     return true;
    313   }
    314 
    315   // Generates |favicon_bitmap_data| with entries for the icon_urls and sizes
    316   // specified. The bitmap_data for entries are lowercase letters of the
    317   // alphabet starting at 'a' for the entry at index 0.
    318   void GenerateFaviconBitmapData(
    319       const GURL& icon_url1,
    320       const std::vector<gfx::Size>& icon_url1_sizes,
    321       std::vector<chrome::FaviconBitmapData>* favicon_bitmap_data) {
    322     GenerateFaviconBitmapData(icon_url1, icon_url1_sizes, GURL(),
    323                               std::vector<gfx::Size>(), favicon_bitmap_data);
    324   }
    325 
    326   void GenerateFaviconBitmapData(
    327       const GURL& icon_url1,
    328       const std::vector<gfx::Size>& icon_url1_sizes,
    329       const GURL& icon_url2,
    330       const std::vector<gfx::Size>& icon_url2_sizes,
    331       std::vector<chrome::FaviconBitmapData>* favicon_bitmap_data) {
    332     favicon_bitmap_data->clear();
    333 
    334     char bitmap_char = 'a';
    335     for (size_t i = 0; i < icon_url1_sizes.size(); ++i) {
    336       std::vector<unsigned char> data;
    337       data.push_back(bitmap_char);
    338       chrome::FaviconBitmapData bitmap_data_element;
    339       bitmap_data_element.bitmap_data =
    340           base::RefCountedBytes::TakeVector(&data);
    341       bitmap_data_element.pixel_size = icon_url1_sizes[i];
    342       bitmap_data_element.icon_url = icon_url1;
    343       favicon_bitmap_data->push_back(bitmap_data_element);
    344 
    345       ++bitmap_char;
    346     }
    347 
    348     for (size_t i = 0; i < icon_url2_sizes.size(); ++i) {
    349       std::vector<unsigned char> data;
    350       data.push_back(bitmap_char);
    351       chrome::FaviconBitmapData bitmap_data_element;
    352       bitmap_data_element.bitmap_data =
    353           base::RefCountedBytes::TakeVector(&data);
    354       bitmap_data_element.pixel_size = icon_url2_sizes[i];
    355       bitmap_data_element.icon_url = icon_url2;
    356       favicon_bitmap_data->push_back(bitmap_data_element);
    357 
    358       ++bitmap_char;
    359     }
    360   }
    361 
    362   // Returns true if |bitmap_data| is equal to |expected_data|.
    363   bool BitmapDataEqual(char expected_data,
    364                        scoped_refptr<base::RefCountedMemory> bitmap_data) {
    365     return bitmap_data.get() &&
    366            bitmap_data->size() == 1u &&
    367            *bitmap_data->front() == expected_data;
    368   }
    369 
    370   BookmarkModel bookmark_model_;
    371 
    372  protected:
    373   // testing::Test
    374   virtual void SetUp() {
    375     if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("BackendTest"),
    376                                            &test_dir_))
    377       return;
    378     backend_ = new HistoryBackend(test_dir_,
    379                                   0,
    380                                   new HistoryBackendTestDelegate(this),
    381                                   &bookmark_model_);
    382     backend_->Init(std::string(), false);
    383   }
    384 
    385   bool loaded_;
    386 
    387  private:
    388   friend class HistoryBackendTestDelegate;
    389 
    390   virtual void TearDown() {
    391     if (backend_.get())
    392       backend_->Closing();
    393     backend_ = NULL;
    394     mem_backend_.reset();
    395     base::DeleteFile(test_dir_, true);
    396     base::RunLoop().RunUntilIdle();
    397   }
    398 
    399   void SetInMemoryBackend(int backend_id, InMemoryHistoryBackend* backend) {
    400     mem_backend_.reset(backend);
    401   }
    402 
    403   void BroadcastNotifications(int type,
    404                               HistoryDetails* details) {
    405     ++num_broadcasted_notifications_;
    406 
    407     // Send the notifications directly to the in-memory database.
    408     content::Details<HistoryDetails> det(details);
    409     mem_backend_->Observe(type, content::Source<HistoryBackendTest>(NULL), det);
    410 
    411     // The backend passes ownership of the details pointer to us.
    412     delete details;
    413   }
    414 
    415   // The number of notifications which were broadcasted.
    416   int num_broadcasted_notifications_;
    417 
    418   base::MessageLoop message_loop_;
    419   base::FilePath test_dir_;
    420   history::MostVisitedURLList most_visited_list_;
    421   history::FilteredURLList filtered_list_;
    422   content::TestBrowserThread ui_thread_;
    423 };
    424 
    425 void HistoryBackendTestDelegate::SetInMemoryBackend(int backend_id,
    426     InMemoryHistoryBackend* backend) {
    427   test_->SetInMemoryBackend(backend_id, backend);
    428 }
    429 
    430 void HistoryBackendTestDelegate::BroadcastNotifications(
    431     int type,
    432     HistoryDetails* details) {
    433   test_->BroadcastNotifications(type, details);
    434 }
    435 
    436 void HistoryBackendTestDelegate::DBLoaded(int backend_id) {
    437   test_->loaded_ = true;
    438 }
    439 
    440 void HistoryBackendTestDelegate::StartTopSitesMigration(int backend_id) {
    441   test_->backend_->MigrateThumbnailsDatabase();
    442 }
    443 
    444 // http://crbug.com/114287
    445 #if defined(OS_WIN)
    446 #define MAYBE_Loaded DISABLED_Loaded
    447 #else
    448 #define MAYBE_Loaded Loaded
    449 #endif // defined(OS_WIN)
    450 TEST_F(HistoryBackendTest, MAYBE_Loaded) {
    451   ASSERT_TRUE(backend_.get());
    452   ASSERT_TRUE(loaded_);
    453 }
    454 
    455 TEST_F(HistoryBackendTest, DeleteAll) {
    456   ASSERT_TRUE(backend_.get());
    457 
    458   // Add two favicons, each with two bitmaps. Note that we add favicon2 before
    459   // adding favicon1. This is so that favicon1 one gets ID 2 autoassigned to
    460   // the database, which will change when the other one is deleted. This way
    461   // we can test that updating works properly.
    462   GURL favicon_url1("http://www.google.com/favicon.ico");
    463   GURL favicon_url2("http://news.google.com/favicon.ico");
    464   chrome::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon(favicon_url2,
    465       chrome::FAVICON);
    466   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(favicon_url1,
    467       chrome::FAVICON);
    468 
    469   std::vector<unsigned char> data;
    470   data.push_back('a');
    471   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1,
    472       new base::RefCountedBytes(data), Time::Now(), kSmallSize));
    473   data[0] = 'b';
    474   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1,
    475      new base::RefCountedBytes(data), Time::Now(), kLargeSize));
    476 
    477   data[0] = 'c';
    478   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2,
    479       new base::RefCountedBytes(data), Time::Now(), kSmallSize));
    480   data[0] = 'd';
    481   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2,
    482      new base::RefCountedBytes(data), Time::Now(), kLargeSize));
    483 
    484   // First visit two URLs.
    485   URLRow row1(GURL("http://www.google.com/"));
    486   row1.set_visit_count(2);
    487   row1.set_typed_count(1);
    488   row1.set_last_visit(Time::Now());
    489   backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1);
    490 
    491   URLRow row2(GURL("http://news.google.com/"));
    492   row2.set_visit_count(1);
    493   row2.set_last_visit(Time::Now());
    494   backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2);
    495 
    496   URLRows rows;
    497   rows.push_back(row2);  // Reversed order for the same reason as favicons.
    498   rows.push_back(row1);
    499   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    500 
    501   URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
    502   URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
    503 
    504   // Get the two visits for the URLs we just added.
    505   VisitVector visits;
    506   backend_->db_->GetVisitsForURL(row1_id, &visits);
    507   ASSERT_EQ(1U, visits.size());
    508 
    509   visits.clear();
    510   backend_->db_->GetVisitsForURL(row2_id, &visits);
    511   ASSERT_EQ(1U, visits.size());
    512 
    513   // The in-memory backend should have been set and it should have gotten the
    514   // typed URL.
    515   ASSERT_TRUE(mem_backend_.get());
    516   URLRow outrow1;
    517   EXPECT_TRUE(mem_backend_->db_->GetRowForURL(row1.url(), NULL));
    518 
    519   // Add thumbnails for each page. The |Images| take ownership of SkBitmap
    520   // created from decoding the images.
    521   ThumbnailScore score(0.25, true, true);
    522   scoped_ptr<SkBitmap> google_bitmap(
    523       gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));
    524 
    525   gfx::Image google_image = gfx::Image::CreateFrom1xBitmap(*google_bitmap);
    526 
    527   Time time;
    528   GURL gurl;
    529   backend_->thumbnail_db_->SetPageThumbnail(gurl, row1_id, &google_image,
    530                                             score, time);
    531   scoped_ptr<SkBitmap> weewar_bitmap(
    532      gfx::JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail)));
    533   gfx::Image weewar_image = gfx::Image::CreateFrom1xBitmap(*weewar_bitmap);
    534   backend_->thumbnail_db_->SetPageThumbnail(gurl, row2_id, &weewar_image,
    535                                             score, time);
    536 
    537   // Star row1.
    538   bookmark_model_.AddURL(
    539       bookmark_model_.bookmark_bar_node(), 0, string16(), row1.url());
    540 
    541   // Now finally clear all history.
    542   backend_->DeleteAllHistory();
    543 
    544   // The first URL should be preserved but the time should be cleared.
    545   EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1));
    546   EXPECT_EQ(row1.url(), outrow1.url());
    547   EXPECT_EQ(0, outrow1.visit_count());
    548   EXPECT_EQ(0, outrow1.typed_count());
    549   EXPECT_TRUE(Time() == outrow1.last_visit());
    550 
    551   // The second row should be deleted.
    552   URLRow outrow2;
    553   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &outrow2));
    554 
    555   // All visits should be deleted for both URLs.
    556   VisitVector all_visits;
    557   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    558   ASSERT_EQ(0U, all_visits.size());
    559 
    560   // All thumbnails should be deleted.
    561   std::vector<unsigned char> out_data;
    562   EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(outrow1.id(),
    563                                                          &out_data));
    564   EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(row2_id, &out_data));
    565 
    566   // We should have a favicon and favicon bitmaps for the first URL only. We
    567   // look them up by favicon URL since the IDs may have changed.
    568   chrome::FaviconID out_favicon1 = backend_->thumbnail_db_->
    569       GetFaviconIDForFaviconURL(favicon_url1, chrome::FAVICON, NULL);
    570   EXPECT_TRUE(out_favicon1);
    571 
    572   std::vector<FaviconBitmap> favicon_bitmaps;
    573   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
    574       out_favicon1, &favicon_bitmaps));
    575   ASSERT_EQ(2u, favicon_bitmaps.size());
    576 
    577   FaviconBitmap favicon_bitmap1 = favicon_bitmaps[0];
    578   FaviconBitmap favicon_bitmap2 = favicon_bitmaps[1];
    579 
    580   // Favicon bitmaps do not need to be in particular order.
    581   if (favicon_bitmap1.pixel_size == kLargeSize) {
    582     FaviconBitmap tmp_favicon_bitmap = favicon_bitmap1;
    583     favicon_bitmap1 = favicon_bitmap2;
    584     favicon_bitmap2 = tmp_favicon_bitmap;
    585   }
    586 
    587   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap1.bitmap_data));
    588   EXPECT_EQ(kSmallSize, favicon_bitmap1.pixel_size);
    589 
    590   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap2.bitmap_data));
    591   EXPECT_EQ(kLargeSize, favicon_bitmap2.pixel_size);
    592 
    593   chrome::FaviconID out_favicon2 = backend_->thumbnail_db_->
    594       GetFaviconIDForFaviconURL(favicon_url2, chrome::FAVICON, NULL);
    595   EXPECT_FALSE(out_favicon2) << "Favicon not deleted";
    596 
    597   // The remaining URL should still reference the same favicon, even if its
    598   // ID has changed.
    599   std::vector<IconMapping> mappings;
    600   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
    601       outrow1.url(), chrome::FAVICON, &mappings));
    602   EXPECT_EQ(1u, mappings.size());
    603   EXPECT_EQ(out_favicon1, mappings[0].icon_id);
    604 
    605   // The first URL should still be bookmarked.
    606   EXPECT_TRUE(bookmark_model_.IsBookmarked(row1.url()));
    607 }
    608 
    609 // Checks that adding a visit, then calling DeleteAll, and then trying to add
    610 // data for the visited page works.  This can happen when clearing the history
    611 // immediately after visiting a page.
    612 TEST_F(HistoryBackendTest, DeleteAllThenAddData) {
    613   ASSERT_TRUE(backend_.get());
    614 
    615   Time visit_time = Time::Now();
    616   GURL url("http://www.google.com/");
    617   HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
    618                              history::RedirectList(),
    619                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
    620                              history::SOURCE_BROWSED, false);
    621   backend_->AddPage(request);
    622 
    623   // Check that a row was added.
    624   URLRow outrow;
    625   EXPECT_TRUE(backend_->db_->GetRowForURL(url, &outrow));
    626 
    627   // Check that the visit was added.
    628   VisitVector all_visits;
    629   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    630   ASSERT_EQ(1U, all_visits.size());
    631 
    632   // Clear all history.
    633   backend_->DeleteAllHistory();
    634 
    635   // The row should be deleted.
    636   EXPECT_FALSE(backend_->db_->GetRowForURL(url, &outrow));
    637 
    638   // The visit should be deleted.
    639   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    640   ASSERT_EQ(0U, all_visits.size());
    641 
    642   // Try and set the title.
    643   backend_->SetPageTitle(url, UTF8ToUTF16("Title"));
    644 
    645   // The row should still be deleted.
    646   EXPECT_FALSE(backend_->db_->GetRowForURL(url, &outrow));
    647 
    648   // The visit should still be deleted.
    649   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    650   ASSERT_EQ(0U, all_visits.size());
    651 }
    652 
    653 TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
    654   GURL favicon_url1("http://www.google.com/favicon.ico");
    655   GURL favicon_url2("http://news.google.com/favicon.ico");
    656 
    657   std::vector<unsigned char> data;
    658   data.push_back('1');
    659   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
    660       favicon_url1,
    661       chrome::FAVICON,
    662       new base::RefCountedBytes(data),
    663       Time::Now(),
    664       gfx::Size());
    665 
    666   data[0] = '2';
    667   chrome::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon(
    668       favicon_url2,
    669       chrome::FAVICON,
    670       new base::RefCountedBytes(data),
    671       Time::Now(),
    672       gfx::Size());
    673 
    674   // First visit two URLs.
    675   URLRow row1(GURL("http://www.google.com/"));
    676   row1.set_visit_count(2);
    677   row1.set_typed_count(1);
    678   row1.set_last_visit(Time::Now());
    679   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
    680 
    681   URLRow row2(GURL("http://news.google.com/"));
    682   row2.set_visit_count(1);
    683   row2.set_last_visit(Time::Now());
    684   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2));
    685 
    686   URLRows rows;
    687   rows.push_back(row2);  // Reversed order for the same reason as favicons.
    688   rows.push_back(row1);
    689   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    690 
    691   URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
    692   URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
    693 
    694   // Star the two URLs.
    695   bookmark_utils::AddIfNotBookmarked(&bookmark_model_, row1.url(), string16());
    696   bookmark_utils::AddIfNotBookmarked(&bookmark_model_, row2.url(), string16());
    697 
    698   // Delete url 2. Because url 2 is starred this won't delete the URL, only
    699   // the visits.
    700   backend_->expirer_.DeleteURL(row2.url());
    701 
    702   // Make sure url 2 is still valid, but has no visits.
    703   URLRow tmp_url_row;
    704   EXPECT_EQ(row2_id, backend_->db_->GetRowForURL(row2.url(), NULL));
    705   VisitVector visits;
    706   backend_->db_->GetVisitsForURL(row2_id, &visits);
    707   EXPECT_EQ(0U, visits.size());
    708   // The favicon should still be valid.
    709   EXPECT_EQ(favicon2,
    710       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url2,
    711                                                          chrome::FAVICON,
    712                                                          NULL));
    713 
    714   // Unstar row2.
    715   bookmark_utils::RemoveAllBookmarks(&bookmark_model_, row2.url());
    716 
    717   // Tell the backend it was unstarred. We have to explicitly do this as
    718   // BookmarkModel isn't wired up to the backend during testing.
    719   std::set<GURL> unstarred_urls;
    720   unstarred_urls.insert(row2.url());
    721   backend_->URLsNoLongerBookmarked(unstarred_urls);
    722 
    723   // The URL should no longer exist.
    724   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row));
    725   // And the favicon should be deleted.
    726   EXPECT_EQ(0,
    727       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url2,
    728                                                          chrome::FAVICON,
    729                                                          NULL));
    730 
    731   // Unstar row 1.
    732   bookmark_utils::RemoveAllBookmarks(&bookmark_model_, row1.url());
    733   // Tell the backend it was unstarred. We have to explicitly do this as
    734   // BookmarkModel isn't wired up to the backend during testing.
    735   unstarred_urls.clear();
    736   unstarred_urls.insert(row1.url());
    737   backend_->URLsNoLongerBookmarked(unstarred_urls);
    738 
    739   // The URL should still exist (because there were visits).
    740   EXPECT_EQ(row1_id, backend_->db_->GetRowForURL(row1.url(), NULL));
    741 
    742   // There should still be visits.
    743   visits.clear();
    744   backend_->db_->GetVisitsForURL(row1_id, &visits);
    745   EXPECT_EQ(1U, visits.size());
    746 
    747   // The favicon should still be valid.
    748   EXPECT_EQ(favicon1,
    749       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url1,
    750                                                          chrome::FAVICON,
    751                                                          NULL));
    752 }
    753 
    754 // Tests a handful of assertions for a navigation with a type of
    755 // KEYWORD_GENERATED.
    756 TEST_F(HistoryBackendTest, KeywordGenerated) {
    757   ASSERT_TRUE(backend_.get());
    758 
    759   GURL url("http://google.com");
    760 
    761   Time visit_time = Time::Now() - base::TimeDelta::FromDays(1);
    762   HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
    763                              history::RedirectList(),
    764                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
    765                              history::SOURCE_BROWSED, false);
    766   backend_->AddPage(request);
    767 
    768   // A row should have been added for the url.
    769   URLRow row;
    770   URLID url_id = backend_->db()->GetRowForURL(url, &row);
    771   ASSERT_NE(0, url_id);
    772 
    773   // The typed count should be 1.
    774   ASSERT_EQ(1, row.typed_count());
    775 
    776   // KEYWORD_GENERATED urls should not be added to the segment db.
    777   std::string segment_name = VisitSegmentDatabase::ComputeSegmentName(url);
    778   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment_name));
    779 
    780   // One visit should be added.
    781   VisitVector visits;
    782   EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
    783   EXPECT_EQ(1U, visits.size());
    784 
    785   // But no visible visits.
    786   visits.clear();
    787   QueryOptions query_options;
    788   query_options.max_count = 1;
    789   backend_->db()->GetVisibleVisitsInRange(query_options, &visits);
    790   EXPECT_TRUE(visits.empty());
    791 
    792   // Expire the visits.
    793   std::set<GURL> restrict_urls;
    794   backend_->expire_backend()->ExpireHistoryBetween(restrict_urls,
    795                                                    visit_time, Time::Now());
    796 
    797   // The visit should have been nuked.
    798   visits.clear();
    799   EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
    800   EXPECT_TRUE(visits.empty());
    801 
    802   // As well as the url.
    803   ASSERT_EQ(0, backend_->db()->GetRowForURL(url, &row));
    804 }
    805 
    806 TEST_F(HistoryBackendTest, ClientRedirect) {
    807   ASSERT_TRUE(backend_.get());
    808 
    809   int transition1;
    810   int transition2;
    811 
    812   // Initial transition to page A.
    813   GURL url_a("http://google.com/a");
    814   AddClientRedirect(GURL(), url_a, false, base::Time(),
    815                     &transition1, &transition2);
    816   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
    817 
    818   // User initiated redirect to page B.
    819   GURL url_b("http://google.com/b");
    820   AddClientRedirect(url_a, url_b, false, base::Time(),
    821                     &transition1, &transition2);
    822   EXPECT_TRUE(transition1 & content::PAGE_TRANSITION_CHAIN_END);
    823   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
    824 
    825   // Non-user initiated redirect to page C.
    826   GURL url_c("http://google.com/c");
    827   AddClientRedirect(url_b, url_c, true, base::Time(),
    828                     &transition1, &transition2);
    829   EXPECT_FALSE(transition1 & content::PAGE_TRANSITION_CHAIN_END);
    830   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
    831 }
    832 
    833 TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
    834   // Setup test data - two Urls in the history, one with favicon assigned and
    835   // one without.
    836   GURL favicon_url1("http://www.google.com/favicon.ico");
    837   std::vector<unsigned char> data;
    838   data.push_back('1');
    839   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
    840       favicon_url1,
    841       chrome::FAVICON,
    842       base::RefCountedBytes::TakeVector(&data),
    843       Time::Now(),
    844       gfx::Size());
    845   URLRow row1(GURL("http://www.google.com/"));
    846   row1.set_visit_count(1);
    847   row1.set_last_visit(Time::Now());
    848   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
    849 
    850   URLRow row2(GURL("http://news.google.com/"));
    851   row2.set_visit_count(1);
    852   row2.set_last_visit(Time::Now());
    853   URLRows rows;
    854   rows.push_back(row1);
    855   rows.push_back(row2);
    856   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    857   URLRow url_row1, url_row2;
    858   EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
    859   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
    860   EXPECT_EQ(1u, NumIconMappingsForPageURL(row1.url(), chrome::FAVICON));
    861   EXPECT_EQ(0u, NumIconMappingsForPageURL(row2.url(), chrome::FAVICON));
    862 
    863   // Now provide one imported favicon for both URLs already in the registry.
    864   // The new favicon should only be used with the URL that doesn't already have
    865   // a favicon.
    866   std::vector<ImportedFaviconUsage> favicons;
    867   ImportedFaviconUsage favicon;
    868   favicon.favicon_url = GURL("http://news.google.com/favicon.ico");
    869   favicon.png_data.push_back('2');
    870   favicon.urls.insert(row1.url());
    871   favicon.urls.insert(row2.url());
    872   favicons.push_back(favicon);
    873   backend_->SetImportedFavicons(favicons);
    874   EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
    875   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
    876 
    877   std::vector<IconMapping> mappings;
    878   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
    879       row1.url(), chrome::FAVICON, &mappings));
    880   EXPECT_EQ(1u, mappings.size());
    881   EXPECT_EQ(favicon1, mappings[0].icon_id);
    882   EXPECT_EQ(favicon_url1, mappings[0].icon_url);
    883 
    884   mappings.clear();
    885   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
    886     row2.url(), chrome::FAVICON, &mappings));
    887   EXPECT_EQ(1u, mappings.size());
    888   EXPECT_EQ(favicon.favicon_url, mappings[0].icon_url);
    889 
    890   // A URL should not be added to history (to store favicon), if
    891   // the URL is not bookmarked.
    892   GURL url3("http://mail.google.com");
    893   favicons.clear();
    894   favicon.favicon_url = GURL("http://mail.google.com/favicon.ico");
    895   favicon.png_data.push_back('3');
    896   favicon.urls.insert(url3);
    897   favicons.push_back(favicon);
    898   backend_->SetImportedFavicons(favicons);
    899   URLRow url_row3;
    900   EXPECT_TRUE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
    901 
    902   // If the URL is bookmarked, it should get added to history with 0 visits.
    903   bookmark_model_.AddURL(bookmark_model_.bookmark_bar_node(), 0, string16(),
    904                          url3);
    905   backend_->SetImportedFavicons(favicons);
    906   EXPECT_FALSE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
    907   EXPECT_TRUE(url_row3.visit_count() == 0);
    908 }
    909 
    910 TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
    911   ASSERT_TRUE(backend_.get());
    912 
    913   GURL url("http://anyuser:anypass@www.google.com");
    914   GURL stripped_url("http://www.google.com");
    915 
    916   // Clear all history.
    917   backend_->DeleteAllHistory();
    918 
    919   // Visit the url with username, password.
    920   backend_->AddPageVisit(url, base::Time::Now(), 0,
    921       content::PageTransitionFromInt(
    922           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
    923       history::SOURCE_BROWSED);
    924 
    925   // Fetch the row information about stripped url from history db.
    926   VisitVector visits;
    927   URLID row_id = backend_->db_->GetRowForURL(stripped_url, NULL);
    928   backend_->db_->GetVisitsForURL(row_id, &visits);
    929 
    930   // Check if stripped url is stored in database.
    931   ASSERT_EQ(1U, visits.size());
    932 }
    933 
    934 TEST_F(HistoryBackendTest, AddPageVisitSource) {
    935   ASSERT_TRUE(backend_.get());
    936 
    937   GURL url("http://www.google.com");
    938 
    939   // Clear all history.
    940   backend_->DeleteAllHistory();
    941 
    942   // Assume visiting the url from an externsion.
    943   backend_->AddPageVisit(
    944       url, base::Time::Now(), 0, content::PAGE_TRANSITION_TYPED,
    945       history::SOURCE_EXTENSION);
    946   // Assume the url is imported from Firefox.
    947   backend_->AddPageVisit(url, base::Time::Now(), 0,
    948                          content::PAGE_TRANSITION_TYPED,
    949                          history::SOURCE_FIREFOX_IMPORTED);
    950   // Assume this url is also synced.
    951   backend_->AddPageVisit(url, base::Time::Now(), 0,
    952                          content::PAGE_TRANSITION_TYPED,
    953                          history::SOURCE_SYNCED);
    954 
    955   // Fetch the row information about the url from history db.
    956   VisitVector visits;
    957   URLID row_id = backend_->db_->GetRowForURL(url, NULL);
    958   backend_->db_->GetVisitsForURL(row_id, &visits);
    959 
    960   // Check if all the visits to the url are stored in database.
    961   ASSERT_EQ(3U, visits.size());
    962   VisitSourceMap visit_sources;
    963   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
    964   ASSERT_EQ(3U, visit_sources.size());
    965   int sources = 0;
    966   for (int i = 0; i < 3; i++) {
    967     switch (visit_sources[visits[i].visit_id]) {
    968       case history::SOURCE_EXTENSION:
    969         sources |= 0x1;
    970         break;
    971       case history::SOURCE_FIREFOX_IMPORTED:
    972         sources |= 0x2;
    973         break;
    974       case history::SOURCE_SYNCED:
    975         sources |= 0x4;
    976       default:
    977         break;
    978     }
    979   }
    980   EXPECT_EQ(0x7, sources);
    981 }
    982 
    983 TEST_F(HistoryBackendTest, AddPageVisitNotLastVisit) {
    984   ASSERT_TRUE(backend_.get());
    985 
    986   GURL url("http://www.google.com");
    987 
    988   // Clear all history.
    989   backend_->DeleteAllHistory();
    990 
    991   // Create visit times
    992   base::Time recent_time = base::Time::Now();
    993   base::TimeDelta visit_age = base::TimeDelta::FromDays(3);
    994   base::Time older_time = recent_time - visit_age;
    995 
    996   // Visit the url with recent time.
    997   backend_->AddPageVisit(url, recent_time, 0,
    998       content::PageTransitionFromInt(
    999           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
   1000       history::SOURCE_BROWSED);
   1001 
   1002   // Add to the url a visit with older time (could be syncing from another
   1003   // client, etc.).
   1004   backend_->AddPageVisit(url, older_time, 0,
   1005       content::PageTransitionFromInt(
   1006           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
   1007       history::SOURCE_SYNCED);
   1008 
   1009   // Fetch the row information about url from history db.
   1010   VisitVector visits;
   1011   URLRow row;
   1012   URLID row_id = backend_->db_->GetRowForURL(url, &row);
   1013   backend_->db_->GetVisitsForURL(row_id, &visits);
   1014 
   1015   // Last visit time should be the most recent time, not the most recently added
   1016   // visit.
   1017   ASSERT_EQ(2U, visits.size());
   1018   ASSERT_EQ(recent_time, row.last_visit());
   1019 }
   1020 
   1021 TEST_F(HistoryBackendTest, AddPageArgsSource) {
   1022   ASSERT_TRUE(backend_.get());
   1023 
   1024   GURL url("http://testpageargs.com");
   1025 
   1026   // Assume this page is browsed by user.
   1027   HistoryAddPageArgs request1(url, base::Time::Now(), NULL, 0, GURL(),
   1028                              history::RedirectList(),
   1029                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
   1030                              history::SOURCE_BROWSED, false);
   1031   backend_->AddPage(request1);
   1032   // Assume this page is synced.
   1033   HistoryAddPageArgs request2(url, base::Time::Now(), NULL, 0, GURL(),
   1034                              history::RedirectList(),
   1035                              content::PAGE_TRANSITION_LINK,
   1036                              history::SOURCE_SYNCED, false);
   1037   backend_->AddPage(request2);
   1038   // Assume this page is browsed again.
   1039   HistoryAddPageArgs request3(url, base::Time::Now(), NULL, 0, GURL(),
   1040                              history::RedirectList(),
   1041                              content::PAGE_TRANSITION_TYPED,
   1042                              history::SOURCE_BROWSED, false);
   1043   backend_->AddPage(request3);
   1044 
   1045   // Three visits should be added with proper sources.
   1046   VisitVector visits;
   1047   URLRow row;
   1048   URLID id = backend_->db()->GetRowForURL(url, &row);
   1049   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1050   ASSERT_EQ(3U, visits.size());
   1051   VisitSourceMap visit_sources;
   1052   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1053   ASSERT_EQ(1U, visit_sources.size());
   1054   EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second);
   1055 }
   1056 
   1057 TEST_F(HistoryBackendTest, AddVisitsSource) {
   1058   ASSERT_TRUE(backend_.get());
   1059 
   1060   GURL url1("http://www.cnn.com");
   1061   std::vector<VisitInfo> visits1, visits2;
   1062   visits1.push_back(VisitInfo(
   1063       Time::Now() - base::TimeDelta::FromDays(5),
   1064       content::PAGE_TRANSITION_LINK));
   1065   visits1.push_back(VisitInfo(
   1066       Time::Now() - base::TimeDelta::FromDays(1),
   1067       content::PAGE_TRANSITION_LINK));
   1068   visits1.push_back(VisitInfo(
   1069       Time::Now(), content::PAGE_TRANSITION_LINK));
   1070 
   1071   GURL url2("http://www.example.com");
   1072   visits2.push_back(VisitInfo(
   1073       Time::Now() - base::TimeDelta::FromDays(10),
   1074       content::PAGE_TRANSITION_LINK));
   1075   visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK));
   1076 
   1077   // Clear all history.
   1078   backend_->DeleteAllHistory();
   1079 
   1080   // Add the visits.
   1081   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
   1082   backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
   1083 
   1084   // Verify the visits were added with their sources.
   1085   VisitVector visits;
   1086   URLRow row;
   1087   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1088   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1089   ASSERT_EQ(3U, visits.size());
   1090   VisitSourceMap visit_sources;
   1091   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1092   ASSERT_EQ(3U, visit_sources.size());
   1093   for (int i = 0; i < 3; i++)
   1094     EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]);
   1095   id = backend_->db()->GetRowForURL(url2, &row);
   1096   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1097   ASSERT_EQ(2U, visits.size());
   1098   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1099   ASSERT_EQ(2U, visit_sources.size());
   1100   for (int i = 0; i < 2; i++)
   1101     EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
   1102 }
   1103 
   1104 TEST_F(HistoryBackendTest, GetMostRecentVisits) {
   1105   ASSERT_TRUE(backend_.get());
   1106 
   1107   GURL url1("http://www.cnn.com");
   1108   std::vector<VisitInfo> visits1;
   1109   visits1.push_back(VisitInfo(
   1110       Time::Now() - base::TimeDelta::FromDays(5),
   1111       content::PAGE_TRANSITION_LINK));
   1112   visits1.push_back(VisitInfo(
   1113       Time::Now() - base::TimeDelta::FromDays(1),
   1114       content::PAGE_TRANSITION_LINK));
   1115   visits1.push_back(VisitInfo(
   1116       Time::Now(), content::PAGE_TRANSITION_LINK));
   1117 
   1118   // Clear all history.
   1119   backend_->DeleteAllHistory();
   1120 
   1121   // Add the visits.
   1122   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
   1123 
   1124   // Verify the visits were added with their sources.
   1125   VisitVector visits;
   1126   URLRow row;
   1127   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1128   ASSERT_TRUE(backend_->db()->GetMostRecentVisitsForURL(id, 1, &visits));
   1129   ASSERT_EQ(1U, visits.size());
   1130   EXPECT_EQ(visits1[2].first, visits[0].visit_time);
   1131 }
   1132 
   1133 TEST_F(HistoryBackendTest, RemoveVisitsTransitions) {
   1134   ASSERT_TRUE(backend_.get());
   1135 
   1136   // Clear all history.
   1137   backend_->DeleteAllHistory();
   1138 
   1139   GURL url1("http://www.cnn.com");
   1140   VisitInfo typed_visit(
   1141       Time::Now() - base::TimeDelta::FromDays(6),
   1142       content::PAGE_TRANSITION_TYPED);
   1143   VisitInfo reload_visit(
   1144       Time::Now() - base::TimeDelta::FromDays(5),
   1145       content::PAGE_TRANSITION_RELOAD);
   1146   VisitInfo link_visit(
   1147       Time::Now() - base::TimeDelta::FromDays(4),
   1148       content::PAGE_TRANSITION_LINK);
   1149   std::vector<VisitInfo> visits_to_add;
   1150   visits_to_add.push_back(typed_visit);
   1151   visits_to_add.push_back(reload_visit);
   1152   visits_to_add.push_back(link_visit);
   1153 
   1154   // Add the visits.
   1155   backend_->AddVisits(url1, visits_to_add, history::SOURCE_SYNCED);
   1156 
   1157   // Verify that the various counts are what we expect.
   1158   VisitVector visits;
   1159   URLRow row;
   1160   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1161   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1162   ASSERT_EQ(3U, visits.size());
   1163   ASSERT_EQ(1, row.typed_count());
   1164   ASSERT_EQ(2, row.visit_count());
   1165 
   1166   // Now, delete the typed visit and verify that typed_count is updated.
   1167   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
   1168   id = backend_->db()->GetRowForURL(url1, &row);
   1169   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1170   ASSERT_EQ(2U, visits.size());
   1171   ASSERT_EQ(0, row.typed_count());
   1172   ASSERT_EQ(1, row.visit_count());
   1173 
   1174   // Delete the reload visit now and verify that none of the counts have
   1175   // changed.
   1176   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
   1177   id = backend_->db()->GetRowForURL(url1, &row);
   1178   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1179   ASSERT_EQ(1U, visits.size());
   1180   ASSERT_EQ(0, row.typed_count());
   1181   ASSERT_EQ(1, row.visit_count());
   1182 
   1183   // Delete the last visit and verify that we delete the URL.
   1184   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
   1185   ASSERT_EQ(0, backend_->db()->GetRowForURL(url1, &row));
   1186 }
   1187 
   1188 TEST_F(HistoryBackendTest, RemoveVisitsSource) {
   1189   ASSERT_TRUE(backend_.get());
   1190 
   1191   GURL url1("http://www.cnn.com");
   1192   std::vector<VisitInfo> visits1, visits2;
   1193   visits1.push_back(VisitInfo(
   1194       Time::Now() - base::TimeDelta::FromDays(5),
   1195       content::PAGE_TRANSITION_LINK));
   1196   visits1.push_back(VisitInfo(Time::Now(),
   1197     content::PAGE_TRANSITION_LINK));
   1198 
   1199   GURL url2("http://www.example.com");
   1200   visits2.push_back(VisitInfo(
   1201       Time::Now() - base::TimeDelta::FromDays(10),
   1202       content::PAGE_TRANSITION_LINK));
   1203   visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK));
   1204 
   1205   // Clear all history.
   1206   backend_->DeleteAllHistory();
   1207 
   1208   // Add the visits.
   1209   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
   1210   backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
   1211 
   1212   // Verify the visits of url1 were added.
   1213   VisitVector visits;
   1214   URLRow row;
   1215   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1216   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1217   ASSERT_EQ(2U, visits.size());
   1218   // Remove these visits.
   1219   ASSERT_TRUE(backend_->RemoveVisits(visits));
   1220 
   1221   // Now check only url2's source in visit_source table.
   1222   VisitSourceMap visit_sources;
   1223   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1224   ASSERT_EQ(0U, visit_sources.size());
   1225   id = backend_->db()->GetRowForURL(url2, &row);
   1226   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1227   ASSERT_EQ(2U, visits.size());
   1228   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1229   ASSERT_EQ(2U, visit_sources.size());
   1230   for (int i = 0; i < 2; i++)
   1231     EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
   1232 }
   1233 
   1234 // Test for migration of adding visit_source table.
   1235 TEST_F(HistoryBackendTest, MigrationVisitSource) {
   1236   ASSERT_TRUE(backend_.get());
   1237   backend_->Closing();
   1238   backend_ = NULL;
   1239 
   1240   base::FilePath old_history_path;
   1241   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
   1242   old_history_path = old_history_path.AppendASCII("History");
   1243   old_history_path = old_history_path.AppendASCII("HistoryNoSource");
   1244 
   1245   // Copy history database file to current directory so that it will be deleted
   1246   // in Teardown.
   1247   base::FilePath new_history_path(getTestDir());
   1248   base::DeleteFile(new_history_path, true);
   1249   file_util::CreateDirectory(new_history_path);
   1250   base::FilePath new_history_file =
   1251       new_history_path.Append(chrome::kHistoryFilename);
   1252   ASSERT_TRUE(base::CopyFile(old_history_path, new_history_file));
   1253 
   1254   backend_ = new HistoryBackend(new_history_path,
   1255                                 0,
   1256                                 new HistoryBackendTestDelegate(this),
   1257                                 &bookmark_model_);
   1258   backend_->Init(std::string(), false);
   1259   backend_->Closing();
   1260   backend_ = NULL;
   1261 
   1262   // Now the database should already be migrated.
   1263   // Check version first.
   1264   int cur_version = HistoryDatabase::GetCurrentVersion();
   1265   sql::Connection db;
   1266   ASSERT_TRUE(db.Open(new_history_file));
   1267   sql::Statement s(db.GetUniqueStatement(
   1268       "SELECT value FROM meta WHERE key = 'version'"));
   1269   ASSERT_TRUE(s.Step());
   1270   int file_version = s.ColumnInt(0);
   1271   EXPECT_EQ(cur_version, file_version);
   1272 
   1273   // Check visit_source table is created and empty.
   1274   s.Assign(db.GetUniqueStatement(
   1275       "SELECT name FROM sqlite_master WHERE name=\"visit_source\""));
   1276   ASSERT_TRUE(s.Step());
   1277   s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10"));
   1278   EXPECT_FALSE(s.Step());
   1279 }
   1280 
   1281 // Test that SetFaviconMappingsForPageAndRedirects correctly updates icon
   1282 // mappings based on redirects, icon URLs and icon types.
   1283 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirects) {
   1284   // Init recent_redirects_
   1285   const GURL url1("http://www.google.com");
   1286   const GURL url2("http://www.google.com/m");
   1287   URLRow url_info1(url1);
   1288   url_info1.set_visit_count(0);
   1289   url_info1.set_typed_count(0);
   1290   url_info1.set_last_visit(base::Time());
   1291   url_info1.set_hidden(false);
   1292   backend_->db_->AddURL(url_info1);
   1293 
   1294   URLRow url_info2(url2);
   1295   url_info2.set_visit_count(0);
   1296   url_info2.set_typed_count(0);
   1297   url_info2.set_last_visit(base::Time());
   1298   url_info2.set_hidden(false);
   1299   backend_->db_->AddURL(url_info2);
   1300 
   1301   history::RedirectList redirects;
   1302   redirects.push_back(url2);
   1303   redirects.push_back(url1);
   1304   backend_->recent_redirects_.Put(url1, redirects);
   1305 
   1306   const GURL icon_url1("http://www.google.com/icon");
   1307   const GURL icon_url2("http://www.google.com/icon2");
   1308 
   1309   // Generate bitmap data for a page with two favicons.
   1310   std::vector<chrome::FaviconBitmapData> two_favicon_bitmap_data;
   1311   GenerateFaviconBitmapData(icon_url1, GetSizesSmallAndLarge(),
   1312       icon_url2, GetSizesSmallAndLarge(), &two_favicon_bitmap_data);
   1313 
   1314   // Generate bitmap data for a page with a single favicon.
   1315   std::vector<chrome::FaviconBitmapData> one_favicon_bitmap_data;
   1316   GenerateFaviconBitmapData(icon_url1, GetSizesSmallAndLarge(),
   1317                             &one_favicon_bitmap_data);
   1318 
   1319   // Add two favicons
   1320   backend_->SetFavicons(url1, chrome::FAVICON, two_favicon_bitmap_data);
   1321   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
   1322   EXPECT_EQ(2u, NumIconMappingsForPageURL(url2, chrome::FAVICON));
   1323 
   1324   // Add one touch_icon
   1325   backend_->SetFavicons(url1, chrome::TOUCH_ICON, one_favicon_bitmap_data);
   1326   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
   1327   EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, chrome::TOUCH_ICON));
   1328   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
   1329 
   1330   // Add one TOUCH_PRECOMPOSED_ICON
   1331   backend_->SetFavicons(
   1332       url1, chrome::TOUCH_PRECOMPOSED_ICON, one_favicon_bitmap_data);
   1333   // The touch_icon was replaced.
   1334   EXPECT_EQ(0u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
   1335   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
   1336   EXPECT_EQ(1u,
   1337             NumIconMappingsForPageURL(url1, chrome::TOUCH_PRECOMPOSED_ICON));
   1338   EXPECT_EQ(1u,
   1339             NumIconMappingsForPageURL(url2, chrome::TOUCH_PRECOMPOSED_ICON));
   1340 
   1341   // Add a touch_icon.
   1342   backend_->SetFavicons(url1, chrome::TOUCH_ICON, one_favicon_bitmap_data);
   1343   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
   1344   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
   1345   // The TOUCH_PRECOMPOSED_ICON was replaced.
   1346   EXPECT_EQ(0u,
   1347             NumIconMappingsForPageURL(url1, chrome::TOUCH_PRECOMPOSED_ICON));
   1348 
   1349   // Add a single favicon.
   1350   backend_->SetFavicons(url1, chrome::FAVICON, one_favicon_bitmap_data);
   1351   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
   1352   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
   1353   EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, chrome::FAVICON));
   1354 
   1355   // Add two favicons.
   1356   backend_->SetFavicons(url1, chrome::FAVICON, two_favicon_bitmap_data);
   1357   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
   1358   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
   1359 }
   1360 
   1361 // Test that there is no churn in icon mappings from calling
   1362 // SetFavicons() twice with the same |favicon_bitmap_data| parameter.
   1363 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageDuplicates) {
   1364   const GURL url("http://www.google.com/");
   1365   const GURL icon_url("http://www.google.com/icon");
   1366 
   1367   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1368   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
   1369                             &favicon_bitmap_data);
   1370 
   1371   backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data);
   1372 
   1373   std::vector<IconMapping> icon_mappings;
   1374   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1375       url, chrome::FAVICON, &icon_mappings));
   1376   EXPECT_EQ(1u, icon_mappings.size());
   1377   IconMappingID mapping_id = icon_mappings[0].mapping_id;
   1378 
   1379   backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data);
   1380 
   1381   icon_mappings.clear();
   1382   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1383       url, chrome::FAVICON, &icon_mappings));
   1384   EXPECT_EQ(1u, icon_mappings.size());
   1385 
   1386   // The same row in the icon_mapping table should be used for the mapping as
   1387   // before.
   1388   EXPECT_EQ(mapping_id, icon_mappings[0].mapping_id);
   1389 }
   1390 
   1391 // Test that calling SetFavicons() with FaviconBitmapData of different pixel
   1392 // sizes than the initially passed in FaviconBitmapData deletes the no longer
   1393 // used favicon bitmaps.
   1394 TEST_F(HistoryBackendTest, SetFaviconsDeleteBitmaps) {
   1395   const GURL page_url("http://www.google.com/");
   1396   const GURL icon_url("http://www.google.com/icon");
   1397 
   1398   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1399   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
   1400                             &favicon_bitmap_data);
   1401   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1402 
   1403   // Test initial state.
   1404   std::vector<IconMapping> icon_mappings;
   1405   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url, &icon_mappings));
   1406   EXPECT_EQ(1u, icon_mappings.size());
   1407   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1408   EXPECT_EQ(chrome::FAVICON, icon_mappings[0].icon_type);
   1409   chrome::FaviconID favicon_id = icon_mappings[0].icon_id;
   1410 
   1411   std::vector<FaviconBitmap> favicon_bitmaps;
   1412   EXPECT_TRUE(GetSortedFaviconBitmaps(favicon_id, &favicon_bitmaps));
   1413   EXPECT_EQ(2u, favicon_bitmaps.size());
   1414   FaviconBitmapID small_bitmap_id = favicon_bitmaps[0].bitmap_id;
   1415   EXPECT_NE(0, small_bitmap_id);
   1416   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmaps[0].bitmap_data));
   1417   EXPECT_EQ(kSmallSize, favicon_bitmaps[0].pixel_size);
   1418   FaviconBitmapID large_bitmap_id = favicon_bitmaps[1].bitmap_id;
   1419   EXPECT_NE(0, large_bitmap_id);
   1420   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data));
   1421   EXPECT_EQ(kLargeSize, favicon_bitmaps[1].pixel_size);
   1422 
   1423   // Call SetFavicons() with bitmap data for only the large bitmap. Check that
   1424   // the small bitmap is in fact deleted.
   1425   GenerateFaviconBitmapData(icon_url, GetSizesLarge(), &favicon_bitmap_data);
   1426   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1427 
   1428   scoped_refptr<base::RefCountedMemory> bitmap_data_out;
   1429   gfx::Size pixel_size_out;
   1430   EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(small_bitmap_id,
   1431       NULL, &bitmap_data_out, &pixel_size_out));
   1432   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id,
   1433       NULL, &bitmap_data_out, &pixel_size_out));
   1434   EXPECT_TRUE(BitmapDataEqual('a', bitmap_data_out));
   1435   EXPECT_EQ(kLargeSize, pixel_size_out);
   1436 
   1437   icon_mappings.clear();
   1438   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1439       &icon_mappings));
   1440   EXPECT_EQ(1u, icon_mappings.size());
   1441   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1442 
   1443   // Call SetFavicons() with no bitmap data. Check that the bitmaps and icon
   1444   // mappings are deleted.
   1445   favicon_bitmap_data.clear();
   1446   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1447 
   1448   EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id, NULL,
   1449       NULL, NULL));
   1450   icon_mappings.clear();
   1451   EXPECT_FALSE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1452       &icon_mappings));
   1453 
   1454   // Notifications should have been broadcast for each call to SetFavicons().
   1455   EXPECT_EQ(3, num_broadcasted_notifications());
   1456 }
   1457 
   1458 // Test updating a single favicon bitmap's data via SetFavicons.
   1459 TEST_F(HistoryBackendTest, SetFaviconsReplaceBitmapData) {
   1460   const GURL page_url("http://www.google.com/");
   1461   const GURL icon_url("http://www.google.com/icon");
   1462 
   1463   std::vector<unsigned char> data_initial;
   1464   data_initial.push_back('a');
   1465 
   1466   chrome::FaviconBitmapData bitmap_data_element;
   1467   bitmap_data_element.bitmap_data =
   1468       base::RefCountedBytes::TakeVector(&data_initial);
   1469   bitmap_data_element.pixel_size = kSmallSize;
   1470   bitmap_data_element.icon_url = icon_url;
   1471   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1472   favicon_bitmap_data.push_back(bitmap_data_element);
   1473 
   1474   // Add bitmap to the database.
   1475   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1476 
   1477   chrome::FaviconID original_favicon_id =
   1478       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1479           icon_url, chrome::FAVICON, NULL);
   1480   EXPECT_NE(0, original_favicon_id);
   1481   FaviconBitmap original_favicon_bitmap;
   1482   EXPECT_TRUE(
   1483       GetOnlyFaviconBitmap(original_favicon_id, &original_favicon_bitmap));
   1484   EXPECT_TRUE(BitmapDataEqual('a', original_favicon_bitmap.bitmap_data));
   1485 
   1486   EXPECT_EQ(1, num_broadcasted_notifications());
   1487 
   1488   // Call SetFavicons() with completely identical data.
   1489   std::vector<unsigned char> updated_data;
   1490   updated_data.push_back('a');
   1491   favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data);
   1492   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1493 
   1494   chrome::FaviconID updated_favicon_id =
   1495       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1496           icon_url, chrome::FAVICON, NULL);
   1497   EXPECT_NE(0, updated_favicon_id);
   1498   FaviconBitmap updated_favicon_bitmap;
   1499   EXPECT_TRUE(
   1500       GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
   1501   EXPECT_TRUE(BitmapDataEqual('a', updated_favicon_bitmap.bitmap_data));
   1502 
   1503   // Because the bitmap data is byte equivalent, no notifications should have
   1504   // been broadcasted.
   1505   EXPECT_EQ(1, num_broadcasted_notifications());
   1506 
   1507   // Call SetFavicons() with identical data but a different bitmap.
   1508   updated_data[0] = 'b';
   1509   favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data);
   1510   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1511 
   1512   updated_favicon_id =
   1513       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1514           icon_url, chrome::FAVICON, NULL);
   1515   EXPECT_NE(0, updated_favicon_id);
   1516   EXPECT_TRUE(
   1517       GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
   1518   EXPECT_TRUE(BitmapDataEqual('b', updated_favicon_bitmap.bitmap_data));
   1519 
   1520   // There should be no churn in FaviconIDs or FaviconBitmapIds even though
   1521   // the bitmap data changed.
   1522   EXPECT_EQ(original_favicon_bitmap.icon_id, updated_favicon_bitmap.icon_id);
   1523   EXPECT_EQ(original_favicon_bitmap.bitmap_id,
   1524             updated_favicon_bitmap.bitmap_id);
   1525 
   1526   // A notification should have been broadcasted as the favicon bitmap data has
   1527   // changed.
   1528   EXPECT_EQ(2, num_broadcasted_notifications());
   1529 }
   1530 
   1531 // Test that if two pages share the same FaviconID, changing the favicon for
   1532 // one page does not affect the other.
   1533 TEST_F(HistoryBackendTest, SetFaviconsSameFaviconURLForTwoPages) {
   1534   GURL icon_url("http://www.google.com/favicon.ico");
   1535   GURL icon_url_new("http://www.google.com/favicon2.ico");
   1536   GURL page_url1("http://www.google.com");
   1537   GURL page_url2("http://www.google.ca");
   1538 
   1539   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1540   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
   1541                             &favicon_bitmap_data);
   1542 
   1543   backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data);
   1544 
   1545   std::vector<GURL> icon_urls;
   1546   icon_urls.push_back(icon_url);
   1547 
   1548   std::vector<chrome::FaviconBitmapResult> bitmap_results;
   1549   backend_->UpdateFaviconMappingsAndFetch(
   1550       page_url2, icon_urls, chrome::FAVICON, kSmallSize.width(),
   1551       GetScaleFactors1x2x(), &bitmap_results);
   1552 
   1553   // Check that the same FaviconID is mapped to both page URLs.
   1554   std::vector<IconMapping> icon_mappings;
   1555   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1556       page_url1, &icon_mappings));
   1557   EXPECT_EQ(1u, icon_mappings.size());
   1558   chrome::FaviconID favicon_id = icon_mappings[0].icon_id;
   1559   EXPECT_NE(0, favicon_id);
   1560 
   1561   icon_mappings.clear();
   1562   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1563       page_url2, &icon_mappings));
   1564   EXPECT_EQ(1u, icon_mappings.size());
   1565   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1566 
   1567   // Change the icon URL that |page_url1| is mapped to.
   1568   GenerateFaviconBitmapData(icon_url_new, GetSizesSmall(),
   1569                             &favicon_bitmap_data);
   1570   backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data);
   1571 
   1572   // |page_url1| should map to a new FaviconID and have valid bitmap data.
   1573   icon_mappings.clear();
   1574   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1575       page_url1, &icon_mappings));
   1576   EXPECT_EQ(1u, icon_mappings.size());
   1577   EXPECT_EQ(icon_url_new, icon_mappings[0].icon_url);
   1578   EXPECT_NE(favicon_id, icon_mappings[0].icon_id);
   1579 
   1580   std::vector<FaviconBitmap> favicon_bitmaps;
   1581   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
   1582       icon_mappings[0].icon_id, &favicon_bitmaps));
   1583   EXPECT_EQ(1u, favicon_bitmaps.size());
   1584 
   1585   // |page_url2| should still map to the same FaviconID and have valid bitmap
   1586   // data.
   1587   icon_mappings.clear();
   1588   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1589       page_url2, &icon_mappings));
   1590   EXPECT_EQ(1u, icon_mappings.size());
   1591   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1592 
   1593   favicon_bitmaps.clear();
   1594   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(favicon_id,
   1595                                                          &favicon_bitmaps));
   1596   EXPECT_EQ(2u, favicon_bitmaps.size());
   1597 
   1598   // A notification should have been broadcast for each call to SetFavicons()
   1599   // and each call to UpdateFaviconMappingsAndFetch().
   1600   EXPECT_EQ(3, num_broadcasted_notifications());
   1601 }
   1602 
   1603 // Test that no notifications are broadcast as a result of calling
   1604 // UpdateFaviconMappingsAndFetch() for an icon URL which is already
   1605 // mapped to the passed in page URL.
   1606 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoChange) {
   1607   GURL page_url("http://www.google.com");
   1608   GURL icon_url("http://www.google.com/favicon.ico");
   1609   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1610   GenerateFaviconBitmapData(icon_url, GetSizesSmall(), &favicon_bitmap_data);
   1611 
   1612   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1613 
   1614   chrome::FaviconID icon_id =
   1615     backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1616         icon_url, chrome::FAVICON, NULL);
   1617   EXPECT_NE(0, icon_id);
   1618   EXPECT_EQ(1, num_broadcasted_notifications());
   1619 
   1620   std::vector<GURL> icon_urls;
   1621   icon_urls.push_back(icon_url);
   1622 
   1623   std::vector<chrome::FaviconBitmapResult> bitmap_results;
   1624   backend_->UpdateFaviconMappingsAndFetch(
   1625       page_url, icon_urls, chrome::FAVICON, kSmallSize.width(),
   1626       GetScaleFactors1x2x(), &bitmap_results);
   1627 
   1628   EXPECT_EQ(icon_id, backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1629       icon_url, chrome::FAVICON, NULL));
   1630 
   1631   // No notification should have been broadcast as no icon mapping, favicon,
   1632   // or favicon bitmap was updated, added or removed.
   1633   EXPECT_EQ(1, num_broadcasted_notifications());
   1634 }
   1635 
   1636 // Test repeatedly calling MergeFavicon(). |page_url| is initially not known
   1637 // to the database.
   1638 TEST_F(HistoryBackendTest, MergeFaviconPageURLNotInDB) {
   1639   GURL page_url("http://www.google.com");
   1640   GURL icon_url("http:/www.google.com/favicon.ico");
   1641 
   1642   std::vector<unsigned char> data;
   1643   data.push_back('a');
   1644   scoped_refptr<base::RefCountedBytes> bitmap_data(
   1645       new base::RefCountedBytes(data));
   1646 
   1647   backend_->MergeFavicon(
   1648       page_url, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
   1649 
   1650   // |page_url| should now be mapped to |icon_url| and the favicon bitmap should
   1651   // not be expired.
   1652   std::vector<IconMapping> icon_mappings;
   1653   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1654       &icon_mappings));
   1655   EXPECT_EQ(1u, icon_mappings.size());
   1656   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1657 
   1658   FaviconBitmap favicon_bitmap;
   1659   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1660   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1661   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1662   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1663 
   1664   data[0] = 'b';
   1665   bitmap_data = new base::RefCountedBytes(data);
   1666   backend_->MergeFavicon(
   1667       page_url, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
   1668 
   1669   // |page_url| should still have a single favicon bitmap. The bitmap data
   1670   // should be updated.
   1671   icon_mappings.clear();
   1672   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1673       &icon_mappings));
   1674   EXPECT_EQ(1u, icon_mappings.size());
   1675   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1676 
   1677   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1678   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1679   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
   1680   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1681 }
   1682 
   1683 // Test calling MergeFavicon() when |page_url| is known to the database.
   1684 TEST_F(HistoryBackendTest, MergeFaviconPageURLInDB) {
   1685   GURL page_url("http://www.google.com");
   1686   GURL icon_url1("http:/www.google.com/favicon.ico");
   1687   GURL icon_url2("http://www.google.com/favicon2.ico");
   1688 
   1689   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1690   GenerateFaviconBitmapData(icon_url1, GetSizesSmall(),
   1691                             &favicon_bitmap_data);
   1692 
   1693   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1694 
   1695   // Test initial state.
   1696   std::vector<IconMapping> icon_mappings;
   1697   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1698       &icon_mappings));
   1699   EXPECT_EQ(1u, icon_mappings.size());
   1700   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1701 
   1702   FaviconBitmap favicon_bitmap;
   1703   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1704   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1705   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1706   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1707 
   1708   EXPECT_EQ(1, num_broadcasted_notifications());
   1709 
   1710   // 1) Merge identical favicon bitmap.
   1711   std::vector<unsigned char> data;
   1712   data.push_back('a');
   1713   scoped_refptr<base::RefCountedBytes> bitmap_data(
   1714       new base::RefCountedBytes(data));
   1715   backend_->MergeFavicon(
   1716       page_url, icon_url1, chrome::FAVICON, bitmap_data, kSmallSize);
   1717 
   1718   // All the data should stay the same and no notifications should have been
   1719   // sent.
   1720   icon_mappings.clear();
   1721   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1722       &icon_mappings));
   1723   EXPECT_EQ(1u, icon_mappings.size());
   1724   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1725 
   1726   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1727   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1728   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1729   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1730 
   1731   EXPECT_EQ(1, num_broadcasted_notifications());
   1732 
   1733   // 2) Merge favicon bitmap of the same size.
   1734   data[0] = 'b';
   1735   bitmap_data = new base::RefCountedBytes(data);
   1736   backend_->MergeFavicon(
   1737       page_url, icon_url1, chrome::FAVICON, bitmap_data, kSmallSize);
   1738 
   1739   // The small favicon bitmap at |icon_url1| should be overwritten.
   1740   icon_mappings.clear();
   1741   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1742       &icon_mappings));
   1743   EXPECT_EQ(1u, icon_mappings.size());
   1744   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1745 
   1746   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1747   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1748   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
   1749   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1750 
   1751   // 3) Merge favicon for the same icon URL, but a pixel size for which there is
   1752   // no favicon bitmap.
   1753   data[0] = 'c';
   1754   bitmap_data = new base::RefCountedBytes(data);
   1755   backend_->MergeFavicon(
   1756       page_url, icon_url1, chrome::FAVICON, bitmap_data, kTinySize);
   1757 
   1758   // A new favicon bitmap should be created and the preexisting favicon bitmap
   1759   // ('b') should be expired.
   1760   icon_mappings.clear();
   1761   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1762       &icon_mappings));
   1763   EXPECT_EQ(1u, icon_mappings.size());
   1764   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1765 
   1766   std::vector<FaviconBitmap> favicon_bitmaps;
   1767   EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id,
   1768                                       &favicon_bitmaps));
   1769   EXPECT_NE(base::Time(), favicon_bitmaps[0].last_updated);
   1770   EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data));
   1771   EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size);
   1772   EXPECT_EQ(base::Time(), favicon_bitmaps[1].last_updated);
   1773   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data));
   1774   EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size);
   1775 
   1776   // 4) Merge favicon for an icon URL different from the icon URLs already
   1777   // mapped to page URL.
   1778   data[0] = 'd';
   1779   bitmap_data = new base::RefCountedBytes(data);
   1780   backend_->MergeFavicon(
   1781       page_url, icon_url2, chrome::FAVICON, bitmap_data, kSmallSize);
   1782 
   1783   // The existing favicon bitmaps should be copied over to the newly created
   1784   // favicon at |icon_url2|. |page_url| should solely be mapped to |icon_url2|.
   1785   icon_mappings.clear();
   1786   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1787       &icon_mappings));
   1788   EXPECT_EQ(1u, icon_mappings.size());
   1789   EXPECT_EQ(icon_url2, icon_mappings[0].icon_url);
   1790 
   1791   favicon_bitmaps.clear();
   1792   EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id,
   1793                                       &favicon_bitmaps));
   1794   EXPECT_EQ(base::Time(), favicon_bitmaps[0].last_updated);
   1795   EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data));
   1796   EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size);
   1797   // The favicon being merged should take precedence over the preexisting
   1798   // favicon bitmaps.
   1799   EXPECT_NE(base::Time(), favicon_bitmaps[1].last_updated);
   1800   EXPECT_TRUE(BitmapDataEqual('d', favicon_bitmaps[1].bitmap_data));
   1801   EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size);
   1802 
   1803   // A notification should have been broadcast for each call to SetFavicons()
   1804   // and MergeFavicon().
   1805   EXPECT_EQ(4, num_broadcasted_notifications());
   1806 }
   1807 
   1808 // Test calling MergeFavicon() when |icon_url| is known to the database but not
   1809 // mapped to |page_url|.
   1810 TEST_F(HistoryBackendTest, MergeFaviconIconURLMappedToDifferentPageURL) {
   1811   GURL page_url1("http://www.google.com");
   1812   GURL page_url2("http://news.google.com");
   1813   GURL page_url3("http://maps.google.com");
   1814   GURL icon_url("http:/www.google.com/favicon.ico");
   1815 
   1816   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1817   GenerateFaviconBitmapData(icon_url, GetSizesSmall(),
   1818                             &favicon_bitmap_data);
   1819 
   1820   backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data);
   1821 
   1822   // Test initial state.
   1823   std::vector<IconMapping> icon_mappings;
   1824   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
   1825       &icon_mappings));
   1826   EXPECT_EQ(1u, icon_mappings.size());
   1827   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1828 
   1829   FaviconBitmap favicon_bitmap;
   1830   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1831   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1832   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1833   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1834 
   1835   // 1) Merge in an identical favicon bitmap data but for a different page URL.
   1836   std::vector<unsigned char> data;
   1837   data.push_back('a');
   1838   scoped_refptr<base::RefCountedBytes> bitmap_data(
   1839       new base::RefCountedBytes(data));
   1840 
   1841   backend_->MergeFavicon(
   1842       page_url2, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
   1843 
   1844   chrome::FaviconID favicon_id =
   1845     backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1846         icon_url, chrome::FAVICON, NULL);
   1847   EXPECT_NE(0, favicon_id);
   1848 
   1849   EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
   1850   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1851   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1852   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1853 
   1854   // 2) Merging a favicon bitmap with different bitmap data for the same icon
   1855   // URL should overwrite the small favicon bitmap at |icon_url|.
   1856   bitmap_data->data()[0] = 'b';
   1857   backend_->MergeFavicon(
   1858       page_url3, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
   1859 
   1860   favicon_id = backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1861       icon_url, chrome::FAVICON, NULL);
   1862   EXPECT_NE(0, favicon_id);
   1863 
   1864   EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
   1865   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1866   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
   1867   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1868 
   1869   // |icon_url| should be mapped to all three page URLs.
   1870   icon_mappings.clear();
   1871   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
   1872       &icon_mappings));
   1873   EXPECT_EQ(1u, icon_mappings.size());
   1874   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1875 
   1876   icon_mappings.clear();
   1877   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url2,
   1878       &icon_mappings));
   1879   EXPECT_EQ(1u, icon_mappings.size());
   1880   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1881 
   1882   icon_mappings.clear();
   1883   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url3,
   1884       &icon_mappings));
   1885   EXPECT_EQ(1u, icon_mappings.size());
   1886   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1887 
   1888   // A notification should have been broadcast for each call to SetFavicons()
   1889   // and MergeFavicon().
   1890   EXPECT_EQ(3, num_broadcasted_notifications());
   1891 }
   1892 
   1893 // Test that MergeFavicon() does not add more than
   1894 // |kMaxFaviconBitmapsPerIconURL| to a favicon.
   1895 TEST_F(HistoryBackendTest, MergeFaviconMaxFaviconBitmapsPerIconURL) {
   1896   GURL page_url("http://www.google.com");
   1897   std::string icon_url_string("http://www.google.com/favicon.ico");
   1898   size_t replace_index = icon_url_string.size() - 1;
   1899 
   1900   std::vector<unsigned char> data;
   1901   data.push_back('a');
   1902   scoped_refptr<base::RefCountedMemory> bitmap_data =
   1903       base::RefCountedBytes::TakeVector(&data);
   1904 
   1905   int pixel_size = 1;
   1906   for (size_t i = 0; i < kMaxFaviconBitmapsPerIconURL + 1; ++i) {
   1907     icon_url_string[replace_index] = '0' + i;
   1908     GURL icon_url(icon_url_string);
   1909 
   1910     backend_->MergeFavicon(page_url, icon_url, chrome::FAVICON, bitmap_data,
   1911                            gfx::Size(pixel_size, pixel_size));
   1912     ++pixel_size;
   1913   }
   1914 
   1915   // There should be a single favicon mapped to |page_url| with exactly
   1916   // kMaxFaviconBitmapsPerIconURL favicon bitmaps.
   1917   std::vector<IconMapping> icon_mappings;
   1918   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1919       &icon_mappings));
   1920   EXPECT_EQ(1u, icon_mappings.size());
   1921   std::vector<FaviconBitmap> favicon_bitmaps;
   1922   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
   1923       icon_mappings[0].icon_id, &favicon_bitmaps));
   1924   EXPECT_EQ(kMaxFaviconBitmapsPerIconURL, favicon_bitmaps.size());
   1925 }
   1926 
   1927 // Tests that the favicon set by MergeFavicon() shows up in the result of
   1928 // GetFaviconsForURL().
   1929 TEST_F(HistoryBackendTest, MergeFaviconShowsUpInGetFaviconsForURLResult) {
   1930   GURL page_url("http://www.google.com");
   1931   GURL icon_url("http://www.google.com/favicon.ico");
   1932   GURL merged_icon_url("http://wwww.google.com/favicon2.ico");
   1933 
   1934   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1935   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
   1936                             &favicon_bitmap_data);
   1937 
   1938   // Set some preexisting favicons for |page_url|.
   1939   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   1940 
   1941   // Merge small favicon.
   1942   std::vector<unsigned char> data;
   1943   data.push_back('c');
   1944   scoped_refptr<base::RefCountedBytes> bitmap_data(
   1945       new base::RefCountedBytes(data));
   1946   backend_->MergeFavicon(
   1947       page_url, merged_icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
   1948 
   1949   // Request favicon bitmaps for both 1x and 2x to simulate request done by
   1950   // BookmarkModel::GetFavicon().
   1951   std::vector<chrome::FaviconBitmapResult> bitmap_results;
   1952   backend_->GetFaviconsForURL(page_url, chrome::FAVICON, kSmallSize.width(),
   1953                               GetScaleFactors1x2x(), &bitmap_results);
   1954 
   1955   EXPECT_EQ(2u, bitmap_results.size());
   1956   const chrome::FaviconBitmapResult& first_result = bitmap_results[0];
   1957   const chrome::FaviconBitmapResult& result =
   1958       (first_result.pixel_size == kSmallSize) ? first_result
   1959                                               : bitmap_results[1];
   1960   EXPECT_TRUE(BitmapDataEqual('c', result.bitmap_data));
   1961 }
   1962 
   1963 // Test UpdateFaviconMapingsAndFetch() when multiple icon types are passed in.
   1964 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchMultipleIconTypes) {
   1965   GURL page_url1("http://www.google.com");
   1966   GURL page_url2("http://news.google.com");
   1967   GURL page_url3("http://mail.google.com");
   1968   GURL icon_urla("http://www.google.com/favicon1.ico");
   1969   GURL icon_urlb("http://www.google.com/favicon2.ico");
   1970   GURL icon_urlc("http://www.google.com/favicon3.ico");
   1971 
   1972   // |page_url1| is mapped to |icon_urla| which if of type TOUCH_ICON.
   1973   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   1974   GenerateFaviconBitmapData(icon_urla, GetSizesSmall(), &favicon_bitmap_data);
   1975   backend_->SetFavicons(page_url1, chrome::TOUCH_ICON, favicon_bitmap_data);
   1976 
   1977   // |page_url2| is mapped to |icon_urlb| and |icon_urlc| which are of type
   1978   // TOUCH_PRECOMPOSED_ICON.
   1979   GenerateFaviconBitmapData(icon_urlb, GetSizesSmall(), icon_urlc,
   1980                             GetSizesSmall(), &favicon_bitmap_data);
   1981   backend_->SetFavicons(
   1982       page_url2, chrome::TOUCH_PRECOMPOSED_ICON, favicon_bitmap_data);
   1983 
   1984   std::vector<GURL> icon_urls;
   1985   icon_urls.push_back(icon_urla);
   1986   icon_urls.push_back(icon_urlb);
   1987   icon_urls.push_back(icon_urlc);
   1988 
   1989   std::vector<chrome::FaviconBitmapResult> bitmap_results;
   1990   backend_->UpdateFaviconMappingsAndFetch(
   1991       page_url3,
   1992       icon_urls,
   1993       (chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON),
   1994       kSmallSize.width(),
   1995       GetScaleFactors1x2x(),
   1996       &bitmap_results);
   1997 
   1998   // |page_url1| and |page_url2| should still be mapped to the same icon URLs.
   1999   std::vector<IconMapping> icon_mappings;
   2000   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
   2001       &icon_mappings));
   2002   EXPECT_EQ(1u, icon_mappings.size());
   2003   EXPECT_EQ(icon_urla, icon_mappings[0].icon_url);
   2004   EXPECT_EQ(chrome::TOUCH_ICON, icon_mappings[0].icon_type);
   2005 
   2006   icon_mappings.clear();
   2007   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url2, &icon_mappings));
   2008   EXPECT_EQ(2u, icon_mappings.size());
   2009   EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url);
   2010   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type);
   2011   EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url);
   2012   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type);
   2013 
   2014   // |page_url3| should be mapped only to |icon_urlb| and |icon_urlc| as
   2015   // TOUCH_PRECOMPOSED_ICON is the largest IconType.
   2016   icon_mappings.clear();
   2017   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url3, &icon_mappings));
   2018   EXPECT_EQ(2u, icon_mappings.size());
   2019   EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url);
   2020   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type);
   2021   EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url);
   2022   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type);
   2023 }
   2024 
   2025 // Test the results of GetFaviconsFromDB() when there are no found
   2026 // favicons.
   2027 TEST_F(HistoryBackendTest, GetFaviconsFromDBEmpty) {
   2028   const GURL page_url("http://www.google.com/");
   2029 
   2030   std::vector<chrome::FaviconBitmapResult> bitmap_results;
   2031   EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
   2032       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results));
   2033   EXPECT_TRUE(bitmap_results.empty());
   2034 }
   2035 
   2036 // Test the results of GetFaviconsFromDB() when there are matching favicons
   2037 // but there are no associated favicon bitmaps.
   2038 TEST_F(HistoryBackendTest, GetFaviconsFromDBNoFaviconBitmaps) {
   2039   const GURL page_url("http://www.google.com/");
   2040   const GURL icon_url("http://www.google.com/icon1");
   2041 
   2042   chrome::FaviconID icon_id = backend_->thumbnail_db_->AddFavicon(
   2043       icon_url, chrome::FAVICON);
   2044   EXPECT_NE(0, icon_id);
   2045   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
   2046 
   2047   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
   2048   EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
   2049       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2050   EXPECT_TRUE(bitmap_results_out.empty());
   2051 }
   2052 
   2053 // Test that GetFaviconsFromDB() returns results for the bitmaps which most
   2054 // closely match the passed in desired size and scale factors.
   2055 TEST_F(HistoryBackendTest, GetFaviconsFromDBSelectClosestMatch) {
   2056   const GURL page_url("http://www.google.com/");
   2057   const GURL icon_url("http://www.google.com/icon1");
   2058 
   2059   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   2060   GenerateFaviconBitmapData(icon_url, GetSizesTinySmallAndLarge(),
   2061                             &favicon_bitmap_data);
   2062 
   2063   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   2064 
   2065   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
   2066   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2067                                           chrome::FAVICON,
   2068                                           kSmallSize.width(),
   2069                                           GetScaleFactors1x2x(),
   2070                                           &bitmap_results_out));
   2071 
   2072   // The bitmap data for the small and large bitmaps should be returned as their
   2073   // sizes match exactly.
   2074   EXPECT_EQ(2u, bitmap_results_out.size());
   2075   // No required order for results.
   2076   if (bitmap_results_out[0].pixel_size == kLargeSize) {
   2077     chrome::FaviconBitmapResult tmp_result = bitmap_results_out[0];
   2078     bitmap_results_out[0] = bitmap_results_out[1];
   2079     bitmap_results_out[1] = tmp_result;
   2080   }
   2081 
   2082   EXPECT_FALSE(bitmap_results_out[0].expired);
   2083   EXPECT_TRUE(BitmapDataEqual('b', bitmap_results_out[0].bitmap_data));
   2084   EXPECT_EQ(kSmallSize, bitmap_results_out[0].pixel_size);
   2085   EXPECT_EQ(icon_url, bitmap_results_out[0].icon_url);
   2086   EXPECT_EQ(chrome::FAVICON, bitmap_results_out[0].icon_type);
   2087 
   2088   EXPECT_FALSE(bitmap_results_out[1].expired);
   2089   EXPECT_TRUE(BitmapDataEqual('c', bitmap_results_out[1].bitmap_data));
   2090   EXPECT_EQ(kLargeSize, bitmap_results_out[1].pixel_size);
   2091   EXPECT_EQ(icon_url, bitmap_results_out[1].icon_url);
   2092   EXPECT_EQ(chrome::FAVICON, bitmap_results_out[1].icon_type);
   2093 }
   2094 
   2095 // Test that GetFaviconsFromDB() returns results from the icon URL whose
   2096 // bitmaps most closely match the passed in desired size and scale factors.
   2097 TEST_F(HistoryBackendTest, GetFaviconsFromDBSingleIconURL) {
   2098   const GURL page_url("http://www.google.com/");
   2099 
   2100   const GURL icon_url1("http://www.google.com/icon1");
   2101   const GURL icon_url2("http://www.google.com/icon2");
   2102 
   2103   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   2104   GenerateFaviconBitmapData(icon_url1, GetSizesSmall(), icon_url2,
   2105                             GetSizesLarge(), &favicon_bitmap_data);
   2106 
   2107   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   2108 
   2109   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
   2110   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2111                                           chrome::FAVICON,
   2112                                           kSmallSize.width(),
   2113                                           GetScaleFactors1x2x(),
   2114                                           &bitmap_results_out));
   2115 
   2116   // The results should have results for the icon URL with the large bitmap as
   2117   // downscaling is preferred to upscaling.
   2118   EXPECT_EQ(1u, bitmap_results_out.size());
   2119   EXPECT_EQ(kLargeSize, bitmap_results_out[0].pixel_size);
   2120   EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url);
   2121 }
   2122 
   2123 // Test the results of GetFaviconsFromDB() when called with different
   2124 // |icon_types|.
   2125 TEST_F(HistoryBackendTest, GetFaviconsFromDBIconType) {
   2126   const GURL page_url("http://www.google.com/");
   2127   const GURL icon_url1("http://www.google.com/icon1.png");
   2128   const GURL icon_url2("http://www.google.com/icon2.png");
   2129 
   2130   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   2131   GenerateFaviconBitmapData(icon_url1, GetSizesSmall(),  &favicon_bitmap_data);
   2132   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
   2133 
   2134   GenerateFaviconBitmapData(icon_url2, GetSizesSmall(), &favicon_bitmap_data);
   2135   backend_->SetFavicons(page_url, chrome::TOUCH_ICON, favicon_bitmap_data);
   2136 
   2137   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
   2138   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
   2139       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2140 
   2141   EXPECT_EQ(1u, bitmap_results_out.size());
   2142   EXPECT_EQ(chrome::FAVICON, bitmap_results_out[0].icon_type);
   2143   EXPECT_EQ(icon_url1, bitmap_results_out[0].icon_url);
   2144 
   2145   bitmap_results_out.clear();
   2146   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::TOUCH_ICON,
   2147       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2148 
   2149   EXPECT_EQ(1u, bitmap_results_out.size());
   2150   EXPECT_EQ(chrome::TOUCH_ICON, bitmap_results_out[0].icon_type);
   2151   EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url);
   2152 }
   2153 
   2154 // Test that GetFaviconsFromDB() correctly sets the expired flag for bitmap
   2155 // reults.
   2156 TEST_F(HistoryBackendTest, GetFaviconsFromDBExpired) {
   2157   const GURL page_url("http://www.google.com/");
   2158   const GURL icon_url("http://www.google.com/icon.png");
   2159 
   2160   std::vector<unsigned char> data;
   2161   data.push_back('a');
   2162   scoped_refptr<base::RefCountedBytes> bitmap_data(
   2163       base::RefCountedBytes::TakeVector(&data));
   2164   base::Time last_updated = base::Time::FromTimeT(0);
   2165   chrome::FaviconID icon_id =
   2166       backend_->thumbnail_db_->AddFavicon(icon_url,
   2167                                           chrome::FAVICON,
   2168                                           bitmap_data,
   2169                                           last_updated,
   2170                                           kSmallSize);
   2171   EXPECT_NE(0, icon_id);
   2172   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
   2173 
   2174   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
   2175   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
   2176       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2177 
   2178   EXPECT_EQ(1u, bitmap_results_out.size());
   2179   EXPECT_TRUE(bitmap_results_out[0].expired);
   2180 }
   2181 
   2182 // Check that UpdateFaviconMappingsAndFetch() call back to the UI when there is
   2183 // no valid thumbnail database.
   2184 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoDB) {
   2185   // Make the thumbnail database invalid.
   2186   backend_->thumbnail_db_.reset();
   2187 
   2188   std::vector<chrome::FaviconBitmapResult> bitmap_results;
   2189 
   2190   backend_->UpdateFaviconMappingsAndFetch(
   2191       GURL(), std::vector<GURL>(), chrome::FAVICON, kSmallSize.width(),
   2192       GetScaleFactors1x2x(), &bitmap_results);
   2193 
   2194   EXPECT_TRUE(bitmap_results.empty());
   2195 }
   2196 
   2197 TEST_F(HistoryBackendTest, CloneFaviconIsRestrictedToSameDomain) {
   2198   const GURL url("http://www.google.com/");
   2199   const GURL same_domain_url("http://www.google.com/subdir/index.html");
   2200   const GURL foreign_domain_url("http://www.not-google.com/");
   2201   const GURL icon_url("http://www.google.com/icon.png");
   2202 
   2203   // Add a favicon
   2204   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
   2205   GenerateFaviconBitmapData(icon_url, GetSizesSmall(),  &favicon_bitmap_data);
   2206   backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data);
   2207   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   2208       url, chrome::FAVICON, NULL));
   2209 
   2210   // Validate starting state.
   2211   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
   2212   EXPECT_TRUE(backend_->GetFaviconsFromDB(url, chrome::FAVICON,
   2213       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2214   EXPECT_FALSE(backend_->GetFaviconsFromDB(same_domain_url, chrome::FAVICON,
   2215       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2216   EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url, chrome::FAVICON,
   2217       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2218 
   2219   // Same-domain cloning should work.
   2220   backend_->CloneFavicons(url, same_domain_url);
   2221   EXPECT_TRUE(backend_->GetFaviconsFromDB(same_domain_url, chrome::FAVICON,
   2222       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2223 
   2224   // Foreign-domain cloning is forbidden.
   2225   backend_->CloneFavicons(url, foreign_domain_url);
   2226   EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url, chrome::FAVICON,
   2227       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
   2228 }
   2229 
   2230 TEST_F(HistoryBackendTest, QueryFilteredURLs) {
   2231   const char* google = "http://www.google.com/";
   2232   const char* yahoo = "http://www.yahoo.com/";
   2233   const char* yahoo_sports = "http://sports.yahoo.com/";
   2234   const char* yahoo_sports_with_article1 =
   2235       "http://sports.yahoo.com/article1.htm";
   2236   const char* yahoo_sports_with_article2 =
   2237       "http://sports.yahoo.com/article2.htm";
   2238   const char* yahoo_sports_soccer = "http://sports.yahoo.com/soccer";
   2239   const char* apple = "http://www.apple.com/";
   2240 
   2241   // Clear all history.
   2242   backend_->DeleteAllHistory();
   2243 
   2244   Time tested_time = Time::Now().LocalMidnight() +
   2245                      base::TimeDelta::FromHours(4);
   2246   base::TimeDelta half_an_hour = base::TimeDelta::FromMinutes(30);
   2247   base::TimeDelta one_hour = base::TimeDelta::FromHours(1);
   2248   base::TimeDelta one_day = base::TimeDelta::FromDays(1);
   2249 
   2250   const content::PageTransition kTypedTransition =
   2251       content::PAGE_TRANSITION_TYPED;
   2252   const content::PageTransition kKeywordGeneratedTransition =
   2253       content::PAGE_TRANSITION_KEYWORD_GENERATED;
   2254 
   2255   const char* redirect_sequence[2];
   2256   redirect_sequence[1] = NULL;
   2257 
   2258   redirect_sequence[0] = google;
   2259   AddRedirectChainWithTransitionAndTime(
   2260       redirect_sequence, 0, kTypedTransition,
   2261       tested_time - one_day - half_an_hour * 2);
   2262   AddRedirectChainWithTransitionAndTime(
   2263       redirect_sequence, 0,
   2264       kTypedTransition, tested_time - one_day);
   2265   AddRedirectChainWithTransitionAndTime(
   2266       redirect_sequence, 0,
   2267       kTypedTransition, tested_time - half_an_hour / 2);
   2268   AddRedirectChainWithTransitionAndTime(
   2269       redirect_sequence, 0,
   2270       kTypedTransition, tested_time);
   2271 
   2272   // Add a visit with a transition that will make sure that no segment gets
   2273   // created for this page (so the subsequent entries will have different URLIDs
   2274   // and SegmentIDs).
   2275   redirect_sequence[0] = apple;
   2276   AddRedirectChainWithTransitionAndTime(
   2277       redirect_sequence, 0, kKeywordGeneratedTransition,
   2278       tested_time - one_day + one_hour * 6);
   2279 
   2280   redirect_sequence[0] = yahoo;
   2281   AddRedirectChainWithTransitionAndTime(
   2282       redirect_sequence, 0, kTypedTransition,
   2283       tested_time - one_day + half_an_hour);
   2284   AddRedirectChainWithTransitionAndTime(
   2285       redirect_sequence, 0, kTypedTransition,
   2286       tested_time - one_day + half_an_hour * 2);
   2287 
   2288   redirect_sequence[0] = yahoo_sports;
   2289   AddRedirectChainWithTransitionAndTime(
   2290       redirect_sequence, 0, kTypedTransition,
   2291       tested_time - one_day - half_an_hour * 2);
   2292   AddRedirectChainWithTransitionAndTime(
   2293       redirect_sequence, 0, kTypedTransition,
   2294       tested_time - one_day);
   2295   int transition1, transition2;
   2296   AddClientRedirect(GURL(yahoo_sports), GURL(yahoo_sports_with_article1), false,
   2297                     tested_time - one_day + half_an_hour,
   2298                     &transition1, &transition2);
   2299   AddClientRedirect(GURL(yahoo_sports_with_article1),
   2300                     GURL(yahoo_sports_with_article2),
   2301                     false,
   2302                     tested_time - one_day + half_an_hour * 2,
   2303                     &transition1, &transition2);
   2304 
   2305   redirect_sequence[0] = yahoo_sports_soccer;
   2306   AddRedirectChainWithTransitionAndTime(redirect_sequence, 0,
   2307                                         kTypedTransition,
   2308                                         tested_time - half_an_hour);
   2309   backend_->Commit();
   2310 
   2311   scoped_refptr<QueryFilteredURLsRequest> request1 =
   2312       new history::QueryFilteredURLsRequest(
   2313           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2314                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2315   HistoryBackendCancelableRequest cancellable_request;
   2316   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2317       request1.get());
   2318 
   2319   VisitFilter filter;
   2320   // Time limit is |tested_time| +/- 45 min.
   2321   base::TimeDelta three_quarters_of_an_hour = base::TimeDelta::FromMinutes(45);
   2322   filter.SetFilterTime(tested_time);
   2323   filter.SetFilterWidth(three_quarters_of_an_hour);
   2324   backend_->QueryFilteredURLs(request1, 100, filter, false);
   2325 
   2326   ASSERT_EQ(4U, get_filtered_list().size());
   2327   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2328   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2329             get_filtered_list()[1].url.spec());
   2330   EXPECT_EQ(std::string(yahoo), get_filtered_list()[2].url.spec());
   2331   EXPECT_EQ(std::string(yahoo_sports),
   2332             get_filtered_list()[3].url.spec());
   2333 
   2334   // Time limit is between |tested_time| and |tested_time| + 2 hours.
   2335   scoped_refptr<QueryFilteredURLsRequest> request2 =
   2336       new history::QueryFilteredURLsRequest(
   2337           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2338                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2339   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2340       request2.get());
   2341   filter.SetFilterTime(tested_time + one_hour);
   2342   filter.SetFilterWidth(one_hour);
   2343   backend_->QueryFilteredURLs(request2, 100, filter, false);
   2344 
   2345   ASSERT_EQ(3U, get_filtered_list().size());
   2346   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2347   EXPECT_EQ(std::string(yahoo), get_filtered_list()[1].url.spec());
   2348   EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec());
   2349 
   2350   // Time limit is between |tested_time| - 2 hours and |tested_time|.
   2351   scoped_refptr<QueryFilteredURLsRequest> request3 =
   2352       new history::QueryFilteredURLsRequest(
   2353           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2354                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2355   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2356       request3.get());
   2357   filter.SetFilterTime(tested_time - one_hour);
   2358   filter.SetFilterWidth(one_hour);
   2359   backend_->QueryFilteredURLs(request3, 100, filter, false);
   2360 
   2361   ASSERT_EQ(3U, get_filtered_list().size());
   2362   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2363   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2364             get_filtered_list()[1].url.spec());
   2365   EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec());
   2366 
   2367   filter.ClearFilters();
   2368   base::Time::Exploded exploded_time;
   2369   tested_time.LocalExplode(&exploded_time);
   2370 
   2371   // Today.
   2372   scoped_refptr<QueryFilteredURLsRequest> request4 =
   2373       new history::QueryFilteredURLsRequest(
   2374           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2375                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2376   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2377       request4.get());
   2378   filter.SetFilterTime(tested_time);
   2379   filter.SetDayOfTheWeekFilter(static_cast<int>(exploded_time.day_of_week));
   2380   backend_->QueryFilteredURLs(request4, 100, filter, false);
   2381 
   2382   ASSERT_EQ(2U, get_filtered_list().size());
   2383   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2384   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2385             get_filtered_list()[1].url.spec());
   2386 
   2387   // Today + time limit - only yahoo_sports_soccer should fit.
   2388   scoped_refptr<QueryFilteredURLsRequest> request5 =
   2389       new history::QueryFilteredURLsRequest(
   2390           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2391                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2392   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2393       request5.get());
   2394   filter.SetFilterTime(tested_time - base::TimeDelta::FromMinutes(40));
   2395   filter.SetFilterWidth(base::TimeDelta::FromMinutes(20));
   2396   backend_->QueryFilteredURLs(request5, 100, filter, false);
   2397 
   2398   ASSERT_EQ(1U, get_filtered_list().size());
   2399   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2400             get_filtered_list()[0].url.spec());
   2401 
   2402   // Make sure we get debug data if we request it.
   2403   scoped_refptr<QueryFilteredURLsRequest> request6 =
   2404       new history::QueryFilteredURLsRequest(
   2405           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2406                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2407   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2408       request6.get());
   2409   filter.SetFilterTime(tested_time);
   2410   filter.SetFilterWidth(one_hour * 2);
   2411   backend_->QueryFilteredURLs(request6, 100, filter, true);
   2412 
   2413   // If the SegmentID is used by QueryFilteredURLs when generating the debug
   2414   // data instead of the URLID, the |total_visits| for the |yahoo_sports_soccer|
   2415   // entry will be zero instead of 1.
   2416   ASSERT_GE(get_filtered_list().size(), 2U);
   2417   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2418   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2419       get_filtered_list()[1].url.spec());
   2420   EXPECT_EQ(4U, get_filtered_list()[0].extended_info.total_visits);
   2421   EXPECT_EQ(1U, get_filtered_list()[1].extended_info.total_visits);
   2422 }
   2423 
   2424 TEST_F(HistoryBackendTest, UpdateVisitDuration) {
   2425   // This unit test will test adding and deleting visit details information.
   2426   ASSERT_TRUE(backend_.get());
   2427 
   2428   GURL url1("http://www.cnn.com");
   2429   std::vector<VisitInfo> visit_info1, visit_info2;
   2430   Time start_ts = Time::Now() - base::TimeDelta::FromDays(5);
   2431   Time end_ts = start_ts + base::TimeDelta::FromDays(2);
   2432   visit_info1.push_back(VisitInfo(start_ts, content::PAGE_TRANSITION_LINK));
   2433 
   2434   GURL url2("http://www.example.com");
   2435   visit_info2.push_back(VisitInfo(Time::Now() - base::TimeDelta::FromDays(10),
   2436                                   content::PAGE_TRANSITION_LINK));
   2437 
   2438   // Clear all history.
   2439   backend_->DeleteAllHistory();
   2440 
   2441   // Add the visits.
   2442   backend_->AddVisits(url1, visit_info1, history::SOURCE_BROWSED);
   2443   backend_->AddVisits(url2, visit_info2, history::SOURCE_BROWSED);
   2444 
   2445   // Verify the entries for both visits were added in visit_details.
   2446   VisitVector visits1, visits2;
   2447   URLRow row;
   2448   URLID url_id1 = backend_->db()->GetRowForURL(url1, &row);
   2449   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1));
   2450   ASSERT_EQ(1U, visits1.size());
   2451   EXPECT_EQ(0, visits1[0].visit_duration.ToInternalValue());
   2452 
   2453   URLID url_id2 = backend_->db()->GetRowForURL(url2, &row);
   2454   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id2, &visits2));
   2455   ASSERT_EQ(1U, visits2.size());
   2456   EXPECT_EQ(0, visits2[0].visit_duration.ToInternalValue());
   2457 
   2458   // Update the visit to cnn.com.
   2459   backend_->UpdateVisitDuration(visits1[0].visit_id, end_ts);
   2460 
   2461   // Check the duration for visiting cnn.com was correctly updated.
   2462   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1));
   2463   ASSERT_EQ(1U, visits1.size());
   2464   base::TimeDelta expected_duration = end_ts - start_ts;
   2465   EXPECT_EQ(expected_duration.ToInternalValue(),
   2466             visits1[0].visit_duration.ToInternalValue());
   2467 
   2468   // Remove the visit to cnn.com.
   2469   ASSERT_TRUE(backend_->RemoveVisits(visits1));
   2470 }
   2471 
   2472 // Test for migration of adding visit_duration column.
   2473 TEST_F(HistoryBackendTest, MigrationVisitDuration) {
   2474   ASSERT_TRUE(backend_.get());
   2475   backend_->Closing();
   2476   backend_ = NULL;
   2477 
   2478   base::FilePath old_history_path, old_history, old_archived;
   2479   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
   2480   old_history_path = old_history_path.AppendASCII("History");
   2481   old_history = old_history_path.AppendASCII("HistoryNoDuration");
   2482   old_archived = old_history_path.AppendASCII("ArchivedNoDuration");
   2483 
   2484   // Copy history database file to current directory so that it will be deleted
   2485   // in Teardown.
   2486   base::FilePath new_history_path(getTestDir());
   2487   base::DeleteFile(new_history_path, true);
   2488   file_util::CreateDirectory(new_history_path);
   2489   base::FilePath new_history_file =
   2490       new_history_path.Append(chrome::kHistoryFilename);
   2491   base::FilePath new_archived_file =
   2492       new_history_path.Append(chrome::kArchivedHistoryFilename);
   2493   ASSERT_TRUE(base::CopyFile(old_history, new_history_file));
   2494   ASSERT_TRUE(base::CopyFile(old_archived, new_archived_file));
   2495 
   2496   backend_ = new HistoryBackend(new_history_path,
   2497                                 0,
   2498                                 new HistoryBackendTestDelegate(this),
   2499                                 &bookmark_model_);
   2500   backend_->Init(std::string(), false);
   2501   backend_->Closing();
   2502   backend_ = NULL;
   2503 
   2504   // Now both history and archived_history databases should already be migrated.
   2505 
   2506   // Check version in history database first.
   2507   int cur_version = HistoryDatabase::GetCurrentVersion();
   2508   sql::Connection db;
   2509   ASSERT_TRUE(db.Open(new_history_file));
   2510   sql::Statement s(db.GetUniqueStatement(
   2511       "SELECT value FROM meta WHERE key = 'version'"));
   2512   ASSERT_TRUE(s.Step());
   2513   int file_version = s.ColumnInt(0);
   2514   EXPECT_EQ(cur_version, file_version);
   2515 
   2516   // Check visit_duration column in visits table is created and set to 0.
   2517   s.Assign(db.GetUniqueStatement(
   2518       "SELECT visit_duration FROM visits LIMIT 1"));
   2519   ASSERT_TRUE(s.Step());
   2520   EXPECT_EQ(0, s.ColumnInt(0));
   2521 
   2522   // Repeat version and visit_duration checks in archived history database
   2523   // also.
   2524   cur_version = ArchivedDatabase::GetCurrentVersion();
   2525   sql::Connection archived_db;
   2526   ASSERT_TRUE(archived_db.Open(new_archived_file));
   2527   sql::Statement s1(archived_db.GetUniqueStatement(
   2528       "SELECT value FROM meta WHERE key = 'version'"));
   2529   ASSERT_TRUE(s1.Step());
   2530   file_version = s1.ColumnInt(0);
   2531   EXPECT_EQ(cur_version, file_version);
   2532 
   2533   // Check visit_duration column in visits table is created and set to 0.
   2534   s1.Assign(archived_db.GetUniqueStatement(
   2535       "SELECT visit_duration FROM visits LIMIT 1"));
   2536   ASSERT_TRUE(s1.Step());
   2537   EXPECT_EQ(0, s1.ColumnInt(0));
   2538 }
   2539 
   2540 TEST_F(HistoryBackendTest, AddPageNoVisitForBookmark) {
   2541   ASSERT_TRUE(backend_.get());
   2542 
   2543   GURL url("http://www.google.com");
   2544   string16 title(UTF8ToUTF16("Bookmark title"));
   2545   backend_->AddPageNoVisitForBookmark(url, title);
   2546 
   2547   URLRow row;
   2548   backend_->GetURL(url, &row);
   2549   EXPECT_EQ(url, row.url());
   2550   EXPECT_EQ(title, row.title());
   2551   EXPECT_EQ(0, row.visit_count());
   2552 
   2553   backend_->DeleteURL(url);
   2554   backend_->AddPageNoVisitForBookmark(url, string16());
   2555   backend_->GetURL(url, &row);
   2556   EXPECT_EQ(url, row.url());
   2557   EXPECT_EQ(UTF8ToUTF16(url.spec()), row.title());
   2558   EXPECT_EQ(0, row.visit_count());
   2559 }
   2560 
   2561 TEST_F(HistoryBackendTest, ExpireHistoryForTimes) {
   2562   ASSERT_TRUE(backend_.get());
   2563 
   2564   HistoryAddPageArgs args[10];
   2565   for (size_t i = 0; i < arraysize(args); ++i) {
   2566     args[i].url = GURL("http://example" +
   2567                        std::string((i % 2 == 0 ? ".com" : ".net")));
   2568     args[i].time = base::Time::FromInternalValue(i);
   2569     backend_->AddPage(args[i]);
   2570   }
   2571   EXPECT_EQ(base::Time(), backend_->GetFirstRecordedTimeForTest());
   2572 
   2573   URLRow row;
   2574   for (size_t i = 0; i < arraysize(args); ++i) {
   2575     EXPECT_TRUE(backend_->GetURL(args[i].url, &row));
   2576   }
   2577 
   2578   std::set<base::Time> times;
   2579   times.insert(args[5].time);
   2580   backend_->ExpireHistoryForTimes(times,
   2581                                   base::Time::FromInternalValue(2),
   2582                                   base::Time::FromInternalValue(8));
   2583 
   2584   EXPECT_EQ(base::Time::FromInternalValue(0),
   2585             backend_->GetFirstRecordedTimeForTest());
   2586 
   2587   // Visits to http://example.com are untouched.
   2588   VisitVector visit_vector;
   2589   EXPECT_TRUE(backend_->GetVisitsForURL(
   2590       backend_->db_->GetRowForURL(GURL("http://example.com"), NULL),
   2591       &visit_vector));
   2592   ASSERT_EQ(5u, visit_vector.size());
   2593   EXPECT_EQ(base::Time::FromInternalValue(0), visit_vector[0].visit_time);
   2594   EXPECT_EQ(base::Time::FromInternalValue(2), visit_vector[1].visit_time);
   2595   EXPECT_EQ(base::Time::FromInternalValue(4), visit_vector[2].visit_time);
   2596   EXPECT_EQ(base::Time::FromInternalValue(6), visit_vector[3].visit_time);
   2597   EXPECT_EQ(base::Time::FromInternalValue(8), visit_vector[4].visit_time);
   2598 
   2599   // Visits to http://example.net between [2,8] are removed.
   2600   visit_vector.clear();
   2601   EXPECT_TRUE(backend_->GetVisitsForURL(
   2602       backend_->db_->GetRowForURL(GURL("http://example.net"), NULL),
   2603       &visit_vector));
   2604   ASSERT_EQ(2u, visit_vector.size());
   2605   EXPECT_EQ(base::Time::FromInternalValue(1), visit_vector[0].visit_time);
   2606   EXPECT_EQ(base::Time::FromInternalValue(9), visit_vector[1].visit_time);
   2607 
   2608   EXPECT_EQ(base::Time::FromInternalValue(0),
   2609             backend_->GetFirstRecordedTimeForTest());
   2610 }
   2611 
   2612 TEST_F(HistoryBackendTest, ExpireHistory) {
   2613   ASSERT_TRUE(backend_.get());
   2614   // Since history operations are dependent on the local timezone, make all
   2615   // entries relative to a fixed, local reference time.
   2616   base::Time reference_time = base::Time::UnixEpoch().LocalMidnight() +
   2617                               base::TimeDelta::FromHours(12);
   2618 
   2619   // Insert 4 entries into the database.
   2620   HistoryAddPageArgs args[4];
   2621   for (size_t i = 0; i < arraysize(args); ++i) {
   2622     args[i].url = GURL("http://example" + base::IntToString(i) + ".com");
   2623     args[i].time = reference_time + base::TimeDelta::FromDays(i);
   2624     backend_->AddPage(args[i]);
   2625   }
   2626 
   2627   URLRow url_rows[4];
   2628   for (unsigned int i = 0; i < arraysize(args); ++i)
   2629     ASSERT_TRUE(backend_->GetURL(args[i].url, &url_rows[i]));
   2630 
   2631   std::vector<ExpireHistoryArgs> expire_list;
   2632   VisitVector visits;
   2633 
   2634   // Passing an empty map should be a no-op.
   2635   backend_->ExpireHistory(expire_list);
   2636   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   2637   EXPECT_EQ(4U, visits.size());
   2638 
   2639   // Trying to delete an unknown URL with the time of the first visit should
   2640   // also be a no-op.
   2641   expire_list.resize(expire_list.size() + 1);
   2642   expire_list[0].SetTimeRangeForOneDay(args[0].time);
   2643   expire_list[0].urls.insert(GURL("http://google.does-not-exist"));
   2644   backend_->ExpireHistory(expire_list);
   2645   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   2646   EXPECT_EQ(4U, visits.size());
   2647 
   2648   // Now add the first URL with the same time -- it should get deleted.
   2649   expire_list.back().urls.insert(url_rows[0].url());
   2650   backend_->ExpireHistory(expire_list);
   2651 
   2652   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   2653   ASSERT_EQ(3U, visits.size());
   2654   EXPECT_EQ(visits[0].url_id, url_rows[1].id());
   2655   EXPECT_EQ(visits[1].url_id, url_rows[2].id());
   2656   EXPECT_EQ(visits[2].url_id, url_rows[3].id());
   2657 
   2658   // The first recorded time should also get updated.
   2659   EXPECT_EQ(backend_->GetFirstRecordedTimeForTest(), args[1].time);
   2660 
   2661   // Now delete the rest of the visits in one call.
   2662   for (unsigned int i = 1; i < arraysize(args); ++i) {
   2663     expire_list.resize(expire_list.size() + 1);
   2664     expire_list[i].SetTimeRangeForOneDay(args[i].time);
   2665     expire_list[i].urls.insert(args[i].url);
   2666   }
   2667   backend_->ExpireHistory(expire_list);
   2668 
   2669   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   2670   ASSERT_EQ(0U, visits.size());
   2671 }
   2672 
   2673 class HistoryBackendSegmentDurationTest : public HistoryBackendTest {
   2674  public:
   2675   HistoryBackendSegmentDurationTest() {}
   2676 
   2677   virtual void SetUp() {
   2678     CommandLine::ForCurrentProcess()->AppendSwitch(
   2679         switches::kTrackActiveVisitTime);
   2680     HistoryBackendTest::SetUp();
   2681   }
   2682 
   2683  private:
   2684   DISALLOW_COPY_AND_ASSIGN(HistoryBackendSegmentDurationTest);
   2685 };
   2686 
   2687 // Assertions around segment durations.
   2688 TEST_F(HistoryBackendSegmentDurationTest, SegmentDuration) {
   2689   const GURL url1("http://www.google.com");
   2690   const GURL url2("http://www.foo.com/m");
   2691   const std::string segment1(VisitSegmentDatabase::ComputeSegmentName(url1));
   2692   const std::string segment2(VisitSegmentDatabase::ComputeSegmentName(url2));
   2693 
   2694   Time segment_time(VisitSegmentDatabase::SegmentTime(Time::Now()));
   2695   URLRow url_info1(url1);
   2696   url_info1.set_visit_count(0);
   2697   url_info1.set_typed_count(0);
   2698   url_info1.set_last_visit(segment_time);
   2699   url_info1.set_hidden(false);
   2700   const URLID url1_id = backend_->db()->AddURL(url_info1);
   2701   EXPECT_NE(0, url1_id);
   2702 
   2703   URLRow url_info2(url2);
   2704   url_info2.set_visit_count(0);
   2705   url_info2.set_typed_count(0);
   2706   url_info2.set_last_visit(Time());
   2707   url_info2.set_hidden(false);
   2708   const URLID url2_id = backend_->db()->AddURL(url_info2);
   2709   EXPECT_NE(0, url2_id);
   2710   EXPECT_NE(url1_id, url2_id);
   2711 
   2712   // Should not have any segments for the urls.
   2713   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment1));
   2714   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment2));
   2715 
   2716   // Update the duration, which should implicitly create the segments.
   2717   const TimeDelta segment1_time_delta(TimeDelta::FromHours(1));
   2718   const TimeDelta segment2_time_delta(TimeDelta::FromHours(2));
   2719   backend_->IncreaseSegmentDuration(url1, segment_time, segment1_time_delta);
   2720   backend_->IncreaseSegmentDuration(url2, segment_time, segment2_time_delta);
   2721 
   2722   // Get the ids of the segments that were created.
   2723   const SegmentID segment1_id = backend_->db()->GetSegmentNamed(segment1);
   2724   EXPECT_NE(0, segment1_id);
   2725   const SegmentID segment2_id = backend_->db()->GetSegmentNamed(segment2);
   2726   EXPECT_NE(0, segment2_id);
   2727   EXPECT_NE(segment1_id, segment2_id);
   2728 
   2729   // Make sure the values made it to the db.
   2730   SegmentDurationID segment1_duration_id;
   2731   TimeDelta fetched_delta;
   2732   EXPECT_TRUE(backend_->db()->GetSegmentDuration(
   2733                   segment1_id, segment_time, &segment1_duration_id,
   2734                   &fetched_delta));
   2735   EXPECT_NE(0, segment1_duration_id);
   2736   EXPECT_EQ(segment1_time_delta.InHours(), fetched_delta.InHours());
   2737 
   2738   SegmentDurationID segment2_duration_id;
   2739   EXPECT_TRUE(backend_->db()->GetSegmentDuration(
   2740                   segment2_id, segment_time, &segment2_duration_id,
   2741                   &fetched_delta));
   2742   EXPECT_NE(0, segment2_duration_id);
   2743   EXPECT_NE(segment1_duration_id, segment2_duration_id);
   2744   EXPECT_EQ(segment2_time_delta.InHours(), fetched_delta.InHours());
   2745 
   2746   // Query by duration. |url2| should be first as it has a longer view time.
   2747   ScopedVector<PageUsageData> data;
   2748   backend_->db()->QuerySegmentDuration(segment_time, 10, &data.get());
   2749   ASSERT_EQ(2u, data.size());
   2750   EXPECT_EQ(url2.spec(), data[0]->GetURL().spec());
   2751   EXPECT_EQ(url2_id, data[0]->GetID());
   2752   EXPECT_EQ(segment2_time_delta.InHours(), data[0]->duration().InHours());
   2753 
   2754   EXPECT_EQ(url1.spec(), data[1]->GetURL().spec());
   2755   EXPECT_EQ(url1_id, data[1]->GetID());
   2756   EXPECT_EQ(segment1_time_delta.InHours(), data[1]->duration().InHours());
   2757 }
   2758 
   2759 // Simple test that removes a bookmark. This test exercises the code paths in
   2760 // History that block till bookmark bar model is loaded.
   2761 TEST_F(HistoryBackendTest, RemoveNotification) {
   2762   scoped_ptr<TestingProfile> profile(new TestingProfile());
   2763 
   2764   ASSERT_TRUE(profile->CreateHistoryService(false, false));
   2765   profile->CreateBookmarkModel(true);
   2766   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile.get());
   2767   ui_test_utils::WaitForBookmarkModelToLoad(model);
   2768 
   2769   // Add a URL.
   2770   GURL url("http://www.google.com");
   2771   bookmark_utils::AddIfNotBookmarked(model, url, base::string16());
   2772 
   2773   HistoryService* service = HistoryServiceFactory::GetForProfile(
   2774       profile.get(), Profile::EXPLICIT_ACCESS);
   2775 
   2776   service->AddPage(
   2777       url, base::Time::Now(), NULL, 1, GURL(), RedirectList(),
   2778       content::PAGE_TRANSITION_TYPED, SOURCE_BROWSED, false);
   2779 
   2780   // This won't actually delete the URL, rather it'll empty out the visits.
   2781   // This triggers blocking on the BookmarkModel.
   2782   service->DeleteURL(url);
   2783 }
   2784 
   2785 // Test DeleteFTSIndexDatabases deletes expected files.
   2786 TEST_F(HistoryBackendTest, DeleteFTSIndexDatabases) {
   2787   ASSERT_TRUE(backend_.get());
   2788 
   2789   base::FilePath history_path(getTestDir());
   2790   base::FilePath db1(history_path.AppendASCII("History Index 2013-05"));
   2791   base::FilePath db1_journal(db1.InsertBeforeExtensionASCII("-journal"));
   2792   base::FilePath db1_wal(db1.InsertBeforeExtensionASCII("-wal"));
   2793   base::FilePath db2_symlink(history_path.AppendASCII("History Index 2013-06"));
   2794   base::FilePath db2_actual(history_path.AppendASCII("Underlying DB"));
   2795 
   2796   // Setup dummy index database files.
   2797   const char* data = "Dummy";
   2798   const size_t data_len = 5;
   2799   ASSERT_TRUE(file_util::WriteFile(db1, data, data_len));
   2800   ASSERT_TRUE(file_util::WriteFile(db1_journal, data, data_len));
   2801   ASSERT_TRUE(file_util::WriteFile(db1_wal, data, data_len));
   2802   ASSERT_TRUE(file_util::WriteFile(db2_actual, data, data_len));
   2803 #if defined(OS_POSIX)
   2804   EXPECT_TRUE(file_util::CreateSymbolicLink(db2_actual, db2_symlink));
   2805 #endif
   2806 
   2807   // Delete all DTS index databases.
   2808   backend_->DeleteFTSIndexDatabases();
   2809   EXPECT_FALSE(base::PathExists(db1));
   2810   EXPECT_FALSE(base::PathExists(db1_wal));
   2811   EXPECT_FALSE(base::PathExists(db1_journal));
   2812   EXPECT_FALSE(base::PathExists(db2_symlink));
   2813   EXPECT_TRUE(base::PathExists(db2_actual));  // Symlinks shouldn't be followed.
   2814 }
   2815 
   2816 }  // namespace history
   2817