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