- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / history_backend_unittest.cc
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 (!file_util::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, 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(), string16());
658   bookmark_utils::AddIfNotBookmarked(&bookmark_model_, row2.url(), string16());
659
660   // Delete url 2. Because url 2 is starred this won't delete the URL, only
661   // the visits.
662   backend_->expirer_.DeleteURL(row2.url());
663
664   // Make sure url 2 is still valid, but has no visits.
665   URLRow tmp_url_row;
666   EXPECT_EQ(row2_id, backend_->db_->GetRowForURL(row2.url(), NULL));
667   VisitVector visits;
668   backend_->db_->GetVisitsForURL(row2_id, &visits);
669   EXPECT_EQ(0U, visits.size());
670   // The favicon should still be valid.
671   EXPECT_EQ(favicon2,
672       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url2,
673                                                          chrome::FAVICON,
674                                                          NULL));
675
676   // Unstar row2.
677   bookmark_utils::RemoveAllBookmarks(&bookmark_model_, row2.url());
678
679   // Tell the backend it was unstarred. We have to explicitly do this as
680   // BookmarkModel isn't wired up to the backend during testing.
681   std::set<GURL> unstarred_urls;
682   unstarred_urls.insert(row2.url());
683   backend_->URLsNoLongerBookmarked(unstarred_urls);
684
685   // The URL should no longer exist.
686   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row));
687   // And the favicon should be deleted.
688   EXPECT_EQ(0,
689       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url2,
690                                                          chrome::FAVICON,
691                                                          NULL));
692
693   // Unstar row 1.
694   bookmark_utils::RemoveAllBookmarks(&bookmark_model_, row1.url());
695   // Tell the backend it was unstarred. We have to explicitly do this as
696   // BookmarkModel isn't wired up to the backend during testing.
697   unstarred_urls.clear();
698   unstarred_urls.insert(row1.url());
699   backend_->URLsNoLongerBookmarked(unstarred_urls);
700
701   // The URL should still exist (because there were visits).
702   EXPECT_EQ(row1_id, backend_->db_->GetRowForURL(row1.url(), NULL));
703
704   // There should still be visits.
705   visits.clear();
706   backend_->db_->GetVisitsForURL(row1_id, &visits);
707   EXPECT_EQ(1U, visits.size());
708
709   // The favicon should still be valid.
710   EXPECT_EQ(favicon1,
711       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url1,
712                                                          chrome::FAVICON,
713                                                          NULL));
714 }
715
716 // Tests a handful of assertions for a navigation with a type of
717 // KEYWORD_GENERATED.
718 TEST_F(HistoryBackendTest, KeywordGenerated) {
719   ASSERT_TRUE(backend_.get());
720
721   GURL url("http://google.com");
722
723   Time visit_time = Time::Now() - base::TimeDelta::FromDays(1);
724   HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
725                              history::RedirectList(),
726                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
727                              history::SOURCE_BROWSED, false);
728   backend_->AddPage(request);
729
730   // A row should have been added for the url.
731   URLRow row;
732   URLID url_id = backend_->db()->GetRowForURL(url, &row);
733   ASSERT_NE(0, url_id);
734
735   // The typed count should be 1.
736   ASSERT_EQ(1, row.typed_count());
737
738   // KEYWORD_GENERATED urls should not be added to the segment db.
739   std::string segment_name = VisitSegmentDatabase::ComputeSegmentName(url);
740   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment_name));
741
742   // One visit should be added.
743   VisitVector visits;
744   EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
745   EXPECT_EQ(1U, visits.size());
746
747   // But no visible visits.
748   visits.clear();
749   QueryOptions query_options;
750   query_options.max_count = 1;
751   backend_->db()->GetVisibleVisitsInRange(query_options, &visits);
752   EXPECT_TRUE(visits.empty());
753
754   // Expire the visits.
755   std::set<GURL> restrict_urls;
756   backend_->expire_backend()->ExpireHistoryBetween(restrict_urls,
757                                                    visit_time, Time::Now());
758
759   // The visit should have been nuked.
760   visits.clear();
761   EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
762   EXPECT_TRUE(visits.empty());
763
764   // As well as the url.
765   ASSERT_EQ(0, backend_->db()->GetRowForURL(url, &row));
766 }
767
768 TEST_F(HistoryBackendTest, ClientRedirect) {
769   ASSERT_TRUE(backend_.get());
770
771   int transition1;
772   int transition2;
773
774   // Initial transition to page A.
775   GURL url_a("http://google.com/a");
776   AddClientRedirect(GURL(), url_a, false, base::Time(),
777                     &transition1, &transition2);
778   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
779
780   // User initiated redirect to page B.
781   GURL url_b("http://google.com/b");
782   AddClientRedirect(url_a, url_b, false, base::Time(),
783                     &transition1, &transition2);
784   EXPECT_TRUE(transition1 & content::PAGE_TRANSITION_CHAIN_END);
785   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
786
787   // Non-user initiated redirect to page C.
788   GURL url_c("http://google.com/c");
789   AddClientRedirect(url_b, url_c, true, base::Time(),
790                     &transition1, &transition2);
791   EXPECT_FALSE(transition1 & content::PAGE_TRANSITION_CHAIN_END);
792   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
793 }
794
795 TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
796   // Setup test data - two Urls in the history, one with favicon assigned and
797   // one without.
798   GURL favicon_url1("http://www.google.com/favicon.ico");
799   std::vector<unsigned char> data;
800   data.push_back('1');
801   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
802       favicon_url1,
803       chrome::FAVICON,
804       base::RefCountedBytes::TakeVector(&data),
805       Time::Now(),
806       gfx::Size());
807   URLRow row1(GURL("http://www.google.com/"));
808   row1.set_visit_count(1);
809   row1.set_last_visit(Time::Now());
810   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
811
812   URLRow row2(GURL("http://news.google.com/"));
813   row2.set_visit_count(1);
814   row2.set_last_visit(Time::Now());
815   URLRows rows;
816   rows.push_back(row1);
817   rows.push_back(row2);
818   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
819   URLRow url_row1, url_row2;
820   EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
821   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
822   EXPECT_EQ(1u, NumIconMappingsForPageURL(row1.url(), chrome::FAVICON));
823   EXPECT_EQ(0u, NumIconMappingsForPageURL(row2.url(), chrome::FAVICON));
824
825   // Now provide one imported favicon for both URLs already in the registry.
826   // The new favicon should only be used with the URL that doesn't already have
827   // a favicon.
828   std::vector<ImportedFaviconUsage> favicons;
829   ImportedFaviconUsage favicon;
830   favicon.favicon_url = GURL("http://news.google.com/favicon.ico");
831   favicon.png_data.push_back('2');
832   favicon.urls.insert(row1.url());
833   favicon.urls.insert(row2.url());
834   favicons.push_back(favicon);
835   backend_->SetImportedFavicons(favicons);
836   EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
837   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
838
839   std::vector<IconMapping> mappings;
840   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
841       row1.url(), chrome::FAVICON, &mappings));
842   EXPECT_EQ(1u, mappings.size());
843   EXPECT_EQ(favicon1, mappings[0].icon_id);
844   EXPECT_EQ(favicon_url1, mappings[0].icon_url);
845
846   mappings.clear();
847   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
848     row2.url(), chrome::FAVICON, &mappings));
849   EXPECT_EQ(1u, mappings.size());
850   EXPECT_EQ(favicon.favicon_url, mappings[0].icon_url);
851
852   // A URL should not be added to history (to store favicon), if
853   // the URL is not bookmarked.
854   GURL url3("http://mail.google.com");
855   favicons.clear();
856   favicon.favicon_url = GURL("http://mail.google.com/favicon.ico");
857   favicon.png_data.push_back('3');
858   favicon.urls.insert(url3);
859   favicons.push_back(favicon);
860   backend_->SetImportedFavicons(favicons);
861   URLRow url_row3;
862   EXPECT_TRUE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
863
864   // If the URL is bookmarked, it should get added to history with 0 visits.
865   bookmark_model_.AddURL(bookmark_model_.bookmark_bar_node(), 0, string16(),
866                          url3);
867   backend_->SetImportedFavicons(favicons);
868   EXPECT_FALSE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
869   EXPECT_TRUE(url_row3.visit_count() == 0);
870 }
871
872 TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
873   ASSERT_TRUE(backend_.get());
874
875   GURL url("http://anyuser:anypass@www.google.com");
876   GURL stripped_url("http://www.google.com");
877
878   // Clear all history.
879   backend_->DeleteAllHistory();
880
881   // Visit the url with username, password.
882   backend_->AddPageVisit(url, base::Time::Now(), 0,
883       content::PageTransitionFromInt(
884           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
885       history::SOURCE_BROWSED);
886
887   // Fetch the row information about stripped url from history db.
888   VisitVector visits;
889   URLID row_id = backend_->db_->GetRowForURL(stripped_url, NULL);
890   backend_->db_->GetVisitsForURL(row_id, &visits);
891
892   // Check if stripped url is stored in database.
893   ASSERT_EQ(1U, visits.size());
894 }
895
896 TEST_F(HistoryBackendTest, AddPageVisitSource) {
897   ASSERT_TRUE(backend_.get());
898
899   GURL url("http://www.google.com");
900
901   // Clear all history.
902   backend_->DeleteAllHistory();
903
904   // Assume visiting the url from an externsion.
905   backend_->AddPageVisit(
906       url, base::Time::Now(), 0, content::PAGE_TRANSITION_TYPED,
907       history::SOURCE_EXTENSION);
908   // Assume the url is imported from Firefox.
909   backend_->AddPageVisit(url, base::Time::Now(), 0,
910                          content::PAGE_TRANSITION_TYPED,
911                          history::SOURCE_FIREFOX_IMPORTED);
912   // Assume this url is also synced.
913   backend_->AddPageVisit(url, base::Time::Now(), 0,
914                          content::PAGE_TRANSITION_TYPED,
915                          history::SOURCE_SYNCED);
916
917   // Fetch the row information about the url from history db.
918   VisitVector visits;
919   URLID row_id = backend_->db_->GetRowForURL(url, NULL);
920   backend_->db_->GetVisitsForURL(row_id, &visits);
921
922   // Check if all the visits to the url are stored in database.
923   ASSERT_EQ(3U, visits.size());
924   VisitSourceMap visit_sources;
925   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
926   ASSERT_EQ(3U, visit_sources.size());
927   int sources = 0;
928   for (int i = 0; i < 3; i++) {
929     switch (visit_sources[visits[i].visit_id]) {
930       case history::SOURCE_EXTENSION:
931         sources |= 0x1;
932         break;
933       case history::SOURCE_FIREFOX_IMPORTED:
934         sources |= 0x2;
935         break;
936       case history::SOURCE_SYNCED:
937         sources |= 0x4;
938       default:
939         break;
940     }
941   }
942   EXPECT_EQ(0x7, sources);
943 }
944
945 TEST_F(HistoryBackendTest, AddPageVisitNotLastVisit) {
946   ASSERT_TRUE(backend_.get());
947
948   GURL url("http://www.google.com");
949
950   // Clear all history.
951   backend_->DeleteAllHistory();
952
953   // Create visit times
954   base::Time recent_time = base::Time::Now();
955   base::TimeDelta visit_age = base::TimeDelta::FromDays(3);
956   base::Time older_time = recent_time - visit_age;
957
958   // Visit the url with recent time.
959   backend_->AddPageVisit(url, recent_time, 0,
960       content::PageTransitionFromInt(
961           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
962       history::SOURCE_BROWSED);
963
964   // Add to the url a visit with older time (could be syncing from another
965   // client, etc.).
966   backend_->AddPageVisit(url, older_time, 0,
967       content::PageTransitionFromInt(
968           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
969       history::SOURCE_SYNCED);
970
971   // Fetch the row information about url from history db.
972   VisitVector visits;
973   URLRow row;
974   URLID row_id = backend_->db_->GetRowForURL(url, &row);
975   backend_->db_->GetVisitsForURL(row_id, &visits);
976
977   // Last visit time should be the most recent time, not the most recently added
978   // visit.
979   ASSERT_EQ(2U, visits.size());
980   ASSERT_EQ(recent_time, row.last_visit());
981 }
982
983 TEST_F(HistoryBackendTest, AddPageArgsSource) {
984   ASSERT_TRUE(backend_.get());
985
986   GURL url("http://testpageargs.com");
987
988   // Assume this page is browsed by user.
989   HistoryAddPageArgs request1(url, base::Time::Now(), NULL, 0, GURL(),
990                              history::RedirectList(),
991                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
992                              history::SOURCE_BROWSED, false);
993   backend_->AddPage(request1);
994   // Assume this page is synced.
995   HistoryAddPageArgs request2(url, base::Time::Now(), NULL, 0, GURL(),
996                              history::RedirectList(),
997                              content::PAGE_TRANSITION_LINK,
998                              history::SOURCE_SYNCED, false);
999   backend_->AddPage(request2);
1000   // Assume this page is browsed again.
1001   HistoryAddPageArgs request3(url, base::Time::Now(), NULL, 0, GURL(),
1002                              history::RedirectList(),
1003                              content::PAGE_TRANSITION_TYPED,
1004                              history::SOURCE_BROWSED, false);
1005   backend_->AddPage(request3);
1006
1007   // Three visits should be added with proper sources.
1008   VisitVector visits;
1009   URLRow row;
1010   URLID id = backend_->db()->GetRowForURL(url, &row);
1011   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1012   ASSERT_EQ(3U, visits.size());
1013   VisitSourceMap visit_sources;
1014   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
1015   ASSERT_EQ(1U, visit_sources.size());
1016   EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second);
1017 }
1018
1019 TEST_F(HistoryBackendTest, AddVisitsSource) {
1020   ASSERT_TRUE(backend_.get());
1021
1022   GURL url1("http://www.cnn.com");
1023   std::vector<VisitInfo> visits1, visits2;
1024   visits1.push_back(VisitInfo(
1025       Time::Now() - base::TimeDelta::FromDays(5),
1026       content::PAGE_TRANSITION_LINK));
1027   visits1.push_back(VisitInfo(
1028       Time::Now() - base::TimeDelta::FromDays(1),
1029       content::PAGE_TRANSITION_LINK));
1030   visits1.push_back(VisitInfo(
1031       Time::Now(), content::PAGE_TRANSITION_LINK));
1032
1033   GURL url2("http://www.example.com");
1034   visits2.push_back(VisitInfo(
1035       Time::Now() - base::TimeDelta::FromDays(10),
1036       content::PAGE_TRANSITION_LINK));
1037   visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK));
1038
1039   // Clear all history.
1040   backend_->DeleteAllHistory();
1041
1042   // Add the visits.
1043   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
1044   backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
1045
1046   // Verify the visits were added with their sources.
1047   VisitVector visits;
1048   URLRow row;
1049   URLID id = backend_->db()->GetRowForURL(url1, &row);
1050   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1051   ASSERT_EQ(3U, visits.size());
1052   VisitSourceMap visit_sources;
1053   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
1054   ASSERT_EQ(3U, visit_sources.size());
1055   for (int i = 0; i < 3; i++)
1056     EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]);
1057   id = backend_->db()->GetRowForURL(url2, &row);
1058   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1059   ASSERT_EQ(2U, visits.size());
1060   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
1061   ASSERT_EQ(2U, visit_sources.size());
1062   for (int i = 0; i < 2; i++)
1063     EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
1064 }
1065
1066 TEST_F(HistoryBackendTest, GetMostRecentVisits) {
1067   ASSERT_TRUE(backend_.get());
1068
1069   GURL url1("http://www.cnn.com");
1070   std::vector<VisitInfo> visits1;
1071   visits1.push_back(VisitInfo(
1072       Time::Now() - base::TimeDelta::FromDays(5),
1073       content::PAGE_TRANSITION_LINK));
1074   visits1.push_back(VisitInfo(
1075       Time::Now() - base::TimeDelta::FromDays(1),
1076       content::PAGE_TRANSITION_LINK));
1077   visits1.push_back(VisitInfo(
1078       Time::Now(), content::PAGE_TRANSITION_LINK));
1079
1080   // Clear all history.
1081   backend_->DeleteAllHistory();
1082
1083   // Add the visits.
1084   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
1085
1086   // Verify the visits were added with their sources.
1087   VisitVector visits;
1088   URLRow row;
1089   URLID id = backend_->db()->GetRowForURL(url1, &row);
1090   ASSERT_TRUE(backend_->db()->GetMostRecentVisitsForURL(id, 1, &visits));
1091   ASSERT_EQ(1U, visits.size());
1092   EXPECT_EQ(visits1[2].first, visits[0].visit_time);
1093 }
1094
1095 TEST_F(HistoryBackendTest, RemoveVisitsTransitions) {
1096   ASSERT_TRUE(backend_.get());
1097
1098   // Clear all history.
1099   backend_->DeleteAllHistory();
1100
1101   GURL url1("http://www.cnn.com");
1102   VisitInfo typed_visit(
1103       Time::Now() - base::TimeDelta::FromDays(6),
1104       content::PAGE_TRANSITION_TYPED);
1105   VisitInfo reload_visit(
1106       Time::Now() - base::TimeDelta::FromDays(5),
1107       content::PAGE_TRANSITION_RELOAD);
1108   VisitInfo link_visit(
1109       Time::Now() - base::TimeDelta::FromDays(4),
1110       content::PAGE_TRANSITION_LINK);
1111   std::vector<VisitInfo> visits_to_add;
1112   visits_to_add.push_back(typed_visit);
1113   visits_to_add.push_back(reload_visit);
1114   visits_to_add.push_back(link_visit);
1115
1116   // Add the visits.
1117   backend_->AddVisits(url1, visits_to_add, history::SOURCE_SYNCED);
1118
1119   // Verify that the various counts are what we expect.
1120   VisitVector visits;
1121   URLRow row;
1122   URLID id = backend_->db()->GetRowForURL(url1, &row);
1123   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1124   ASSERT_EQ(3U, visits.size());
1125   ASSERT_EQ(1, row.typed_count());
1126   ASSERT_EQ(2, row.visit_count());
1127
1128   // Now, delete the typed visit and verify that typed_count is updated.
1129   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
1130   id = backend_->db()->GetRowForURL(url1, &row);
1131   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1132   ASSERT_EQ(2U, visits.size());
1133   ASSERT_EQ(0, row.typed_count());
1134   ASSERT_EQ(1, row.visit_count());
1135
1136   // Delete the reload visit now and verify that none of the counts have
1137   // changed.
1138   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
1139   id = backend_->db()->GetRowForURL(url1, &row);
1140   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1141   ASSERT_EQ(1U, visits.size());
1142   ASSERT_EQ(0, row.typed_count());
1143   ASSERT_EQ(1, row.visit_count());
1144
1145   // Delete the last visit and verify that we delete the URL.
1146   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
1147   ASSERT_EQ(0, backend_->db()->GetRowForURL(url1, &row));
1148 }
1149
1150 TEST_F(HistoryBackendTest, RemoveVisitsSource) {
1151   ASSERT_TRUE(backend_.get());
1152
1153   GURL url1("http://www.cnn.com");
1154   std::vector<VisitInfo> visits1, visits2;
1155   visits1.push_back(VisitInfo(
1156       Time::Now() - base::TimeDelta::FromDays(5),
1157       content::PAGE_TRANSITION_LINK));
1158   visits1.push_back(VisitInfo(Time::Now(),
1159     content::PAGE_TRANSITION_LINK));
1160
1161   GURL url2("http://www.example.com");
1162   visits2.push_back(VisitInfo(
1163       Time::Now() - base::TimeDelta::FromDays(10),
1164       content::PAGE_TRANSITION_LINK));
1165   visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK));
1166
1167   // Clear all history.
1168   backend_->DeleteAllHistory();
1169
1170   // Add the visits.
1171   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
1172   backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
1173
1174   // Verify the visits of url1 were added.
1175   VisitVector visits;
1176   URLRow row;
1177   URLID id = backend_->db()->GetRowForURL(url1, &row);
1178   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1179   ASSERT_EQ(2U, visits.size());
1180   // Remove these visits.
1181   ASSERT_TRUE(backend_->RemoveVisits(visits));
1182
1183   // Now check only url2's source in visit_source table.
1184   VisitSourceMap visit_sources;
1185   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
1186   ASSERT_EQ(0U, visit_sources.size());
1187   id = backend_->db()->GetRowForURL(url2, &row);
1188   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
1189   ASSERT_EQ(2U, visits.size());
1190   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
1191   ASSERT_EQ(2U, visit_sources.size());
1192   for (int i = 0; i < 2; i++)
1193     EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
1194 }
1195
1196 // Test for migration of adding visit_source table.
1197 TEST_F(HistoryBackendTest, MigrationVisitSource) {
1198   ASSERT_TRUE(backend_.get());
1199   backend_->Closing();
1200   backend_ = NULL;
1201
1202   base::FilePath old_history_path;
1203   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
1204   old_history_path = old_history_path.AppendASCII("History");
1205   old_history_path = old_history_path.AppendASCII("HistoryNoSource");
1206
1207   // Copy history database file to current directory so that it will be deleted
1208   // in Teardown.
1209   base::FilePath new_history_path(getTestDir());
1210   base::DeleteFile(new_history_path, true);
1211   file_util::CreateDirectory(new_history_path);
1212   base::FilePath new_history_file =
1213       new_history_path.Append(chrome::kHistoryFilename);
1214   ASSERT_TRUE(base::CopyFile(old_history_path, new_history_file));
1215
1216   backend_ = new HistoryBackend(new_history_path,
1217                                 0,
1218                                 new HistoryBackendTestDelegate(this),
1219                                 &bookmark_model_);
1220   backend_->Init(std::string(), false);
1221   backend_->Closing();
1222   backend_ = NULL;
1223
1224   // Now the database should already be migrated.
1225   // Check version first.
1226   int cur_version = HistoryDatabase::GetCurrentVersion();
1227   sql::Connection db;
1228   ASSERT_TRUE(db.Open(new_history_file));
1229   sql::Statement s(db.GetUniqueStatement(
1230       "SELECT value FROM meta WHERE key = 'version'"));
1231   ASSERT_TRUE(s.Step());
1232   int file_version = s.ColumnInt(0);
1233   EXPECT_EQ(cur_version, file_version);
1234
1235   // Check visit_source table is created and empty.
1236   s.Assign(db.GetUniqueStatement(
1237       "SELECT name FROM sqlite_master WHERE name=\"visit_source\""));
1238   ASSERT_TRUE(s.Step());
1239   s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10"));
1240   EXPECT_FALSE(s.Step());
1241 }
1242
1243 // Test that SetFaviconMappingsForPageAndRedirects correctly updates icon
1244 // mappings based on redirects, icon URLs and icon types.
1245 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirects) {
1246   // Init recent_redirects_
1247   const GURL url1("http://www.google.com");
1248   const GURL url2("http://www.google.com/m");
1249   URLRow url_info1(url1);
1250   url_info1.set_visit_count(0);
1251   url_info1.set_typed_count(0);
1252   url_info1.set_last_visit(base::Time());
1253   url_info1.set_hidden(false);
1254   backend_->db_->AddURL(url_info1);
1255
1256   URLRow url_info2(url2);
1257   url_info2.set_visit_count(0);
1258   url_info2.set_typed_count(0);
1259   url_info2.set_last_visit(base::Time());
1260   url_info2.set_hidden(false);
1261   backend_->db_->AddURL(url_info2);
1262
1263   history::RedirectList redirects;
1264   redirects.push_back(url2);
1265   redirects.push_back(url1);
1266   backend_->recent_redirects_.Put(url1, redirects);
1267
1268   const GURL icon_url1("http://www.google.com/icon");
1269   const GURL icon_url2("http://www.google.com/icon2");
1270
1271   // Generate bitmap data for a page with two favicons.
1272   std::vector<chrome::FaviconBitmapData> two_favicon_bitmap_data;
1273   GenerateFaviconBitmapData(icon_url1, GetSizesSmallAndLarge(),
1274       icon_url2, GetSizesSmallAndLarge(), &two_favicon_bitmap_data);
1275
1276   // Generate bitmap data for a page with a single favicon.
1277   std::vector<chrome::FaviconBitmapData> one_favicon_bitmap_data;
1278   GenerateFaviconBitmapData(icon_url1, GetSizesSmallAndLarge(),
1279                             &one_favicon_bitmap_data);
1280
1281   // Add two favicons
1282   backend_->SetFavicons(url1, chrome::FAVICON, two_favicon_bitmap_data);
1283   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
1284   EXPECT_EQ(2u, NumIconMappingsForPageURL(url2, chrome::FAVICON));
1285
1286   // Add one touch_icon
1287   backend_->SetFavicons(url1, chrome::TOUCH_ICON, one_favicon_bitmap_data);
1288   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
1289   EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, chrome::TOUCH_ICON));
1290   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
1291
1292   // Add one TOUCH_PRECOMPOSED_ICON
1293   backend_->SetFavicons(
1294       url1, chrome::TOUCH_PRECOMPOSED_ICON, one_favicon_bitmap_data);
1295   // The touch_icon was replaced.
1296   EXPECT_EQ(0u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
1297   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
1298   EXPECT_EQ(1u,
1299             NumIconMappingsForPageURL(url1, chrome::TOUCH_PRECOMPOSED_ICON));
1300   EXPECT_EQ(1u,
1301             NumIconMappingsForPageURL(url2, chrome::TOUCH_PRECOMPOSED_ICON));
1302
1303   // Add a touch_icon.
1304   backend_->SetFavicons(url1, chrome::TOUCH_ICON, one_favicon_bitmap_data);
1305   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
1306   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
1307   // The TOUCH_PRECOMPOSED_ICON was replaced.
1308   EXPECT_EQ(0u,
1309             NumIconMappingsForPageURL(url1, chrome::TOUCH_PRECOMPOSED_ICON));
1310
1311   // Add a single favicon.
1312   backend_->SetFavicons(url1, chrome::FAVICON, one_favicon_bitmap_data);
1313   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
1314   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
1315   EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, chrome::FAVICON));
1316
1317   // Add two favicons.
1318   backend_->SetFavicons(url1, chrome::FAVICON, two_favicon_bitmap_data);
1319   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON));
1320   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON));
1321 }
1322
1323 // Test that there is no churn in icon mappings from calling
1324 // SetFavicons() twice with the same |favicon_bitmap_data| parameter.
1325 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageDuplicates) {
1326   const GURL url("http://www.google.com/");
1327   const GURL icon_url("http://www.google.com/icon");
1328
1329   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1330   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
1331                             &favicon_bitmap_data);
1332
1333   backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data);
1334
1335   std::vector<IconMapping> icon_mappings;
1336   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
1337       url, chrome::FAVICON, &icon_mappings));
1338   EXPECT_EQ(1u, icon_mappings.size());
1339   IconMappingID mapping_id = icon_mappings[0].mapping_id;
1340
1341   backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data);
1342
1343   icon_mappings.clear();
1344   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
1345       url, chrome::FAVICON, &icon_mappings));
1346   EXPECT_EQ(1u, icon_mappings.size());
1347
1348   // The same row in the icon_mapping table should be used for the mapping as
1349   // before.
1350   EXPECT_EQ(mapping_id, icon_mappings[0].mapping_id);
1351 }
1352
1353 // Test that calling SetFavicons() with FaviconBitmapData of different pixel
1354 // sizes than the initially passed in FaviconBitmapData deletes the no longer
1355 // used favicon bitmaps.
1356 TEST_F(HistoryBackendTest, SetFaviconsDeleteBitmaps) {
1357   const GURL page_url("http://www.google.com/");
1358   const GURL icon_url("http://www.google.com/icon");
1359
1360   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1361   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
1362                             &favicon_bitmap_data);
1363   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1364
1365   // Test initial state.
1366   std::vector<IconMapping> icon_mappings;
1367   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url, &icon_mappings));
1368   EXPECT_EQ(1u, icon_mappings.size());
1369   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
1370   EXPECT_EQ(chrome::FAVICON, icon_mappings[0].icon_type);
1371   chrome::FaviconID favicon_id = icon_mappings[0].icon_id;
1372
1373   std::vector<FaviconBitmap> favicon_bitmaps;
1374   EXPECT_TRUE(GetSortedFaviconBitmaps(favicon_id, &favicon_bitmaps));
1375   EXPECT_EQ(2u, favicon_bitmaps.size());
1376   FaviconBitmapID small_bitmap_id = favicon_bitmaps[0].bitmap_id;
1377   EXPECT_NE(0, small_bitmap_id);
1378   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmaps[0].bitmap_data));
1379   EXPECT_EQ(kSmallSize, favicon_bitmaps[0].pixel_size);
1380   FaviconBitmapID large_bitmap_id = favicon_bitmaps[1].bitmap_id;
1381   EXPECT_NE(0, large_bitmap_id);
1382   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data));
1383   EXPECT_EQ(kLargeSize, favicon_bitmaps[1].pixel_size);
1384
1385   // Call SetFavicons() with bitmap data for only the large bitmap. Check that
1386   // the small bitmap is in fact deleted.
1387   GenerateFaviconBitmapData(icon_url, GetSizesLarge(), &favicon_bitmap_data);
1388   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1389
1390   scoped_refptr<base::RefCountedMemory> bitmap_data_out;
1391   gfx::Size pixel_size_out;
1392   EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(small_bitmap_id,
1393       NULL, &bitmap_data_out, &pixel_size_out));
1394   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id,
1395       NULL, &bitmap_data_out, &pixel_size_out));
1396   EXPECT_TRUE(BitmapDataEqual('a', bitmap_data_out));
1397   EXPECT_EQ(kLargeSize, pixel_size_out);
1398
1399   icon_mappings.clear();
1400   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1401       &icon_mappings));
1402   EXPECT_EQ(1u, icon_mappings.size());
1403   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
1404
1405   // Call SetFavicons() with no bitmap data. Check that the bitmaps and icon
1406   // mappings are deleted.
1407   favicon_bitmap_data.clear();
1408   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1409
1410   EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id, NULL,
1411       NULL, NULL));
1412   icon_mappings.clear();
1413   EXPECT_FALSE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1414       &icon_mappings));
1415
1416   // Notifications should have been broadcast for each call to SetFavicons().
1417   EXPECT_EQ(3, num_broadcasted_notifications());
1418 }
1419
1420 // Test updating a single favicon bitmap's data via SetFavicons.
1421 TEST_F(HistoryBackendTest, SetFaviconsReplaceBitmapData) {
1422   const GURL page_url("http://www.google.com/");
1423   const GURL icon_url("http://www.google.com/icon");
1424
1425   std::vector<unsigned char> data_initial;
1426   data_initial.push_back('a');
1427
1428   chrome::FaviconBitmapData bitmap_data_element;
1429   bitmap_data_element.bitmap_data =
1430       base::RefCountedBytes::TakeVector(&data_initial);
1431   bitmap_data_element.pixel_size = kSmallSize;
1432   bitmap_data_element.icon_url = icon_url;
1433   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1434   favicon_bitmap_data.push_back(bitmap_data_element);
1435
1436   // Add bitmap to the database.
1437   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1438
1439   chrome::FaviconID original_favicon_id =
1440       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1441           icon_url, chrome::FAVICON, NULL);
1442   EXPECT_NE(0, original_favicon_id);
1443   FaviconBitmap original_favicon_bitmap;
1444   EXPECT_TRUE(
1445       GetOnlyFaviconBitmap(original_favicon_id, &original_favicon_bitmap));
1446   EXPECT_TRUE(BitmapDataEqual('a', original_favicon_bitmap.bitmap_data));
1447
1448   EXPECT_EQ(1, num_broadcasted_notifications());
1449
1450   // Call SetFavicons() with completely identical data.
1451   std::vector<unsigned char> updated_data;
1452   updated_data.push_back('a');
1453   favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data);
1454   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1455
1456   chrome::FaviconID updated_favicon_id =
1457       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1458           icon_url, chrome::FAVICON, NULL);
1459   EXPECT_NE(0, updated_favicon_id);
1460   FaviconBitmap updated_favicon_bitmap;
1461   EXPECT_TRUE(
1462       GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
1463   EXPECT_TRUE(BitmapDataEqual('a', updated_favicon_bitmap.bitmap_data));
1464
1465   // Because the bitmap data is byte equivalent, no notifications should have
1466   // been broadcasted.
1467   EXPECT_EQ(1, num_broadcasted_notifications());
1468
1469   // Call SetFavicons() with identical data but a different bitmap.
1470   updated_data[0] = 'b';
1471   favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data);
1472   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1473
1474   updated_favicon_id =
1475       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1476           icon_url, chrome::FAVICON, NULL);
1477   EXPECT_NE(0, updated_favicon_id);
1478   EXPECT_TRUE(
1479       GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
1480   EXPECT_TRUE(BitmapDataEqual('b', updated_favicon_bitmap.bitmap_data));
1481
1482   // There should be no churn in FaviconIDs or FaviconBitmapIds even though
1483   // the bitmap data changed.
1484   EXPECT_EQ(original_favicon_bitmap.icon_id, updated_favicon_bitmap.icon_id);
1485   EXPECT_EQ(original_favicon_bitmap.bitmap_id,
1486             updated_favicon_bitmap.bitmap_id);
1487
1488   // A notification should have been broadcasted as the favicon bitmap data has
1489   // changed.
1490   EXPECT_EQ(2, num_broadcasted_notifications());
1491 }
1492
1493 // Test that if two pages share the same FaviconID, changing the favicon for
1494 // one page does not affect the other.
1495 TEST_F(HistoryBackendTest, SetFaviconsSameFaviconURLForTwoPages) {
1496   GURL icon_url("http://www.google.com/favicon.ico");
1497   GURL icon_url_new("http://www.google.com/favicon2.ico");
1498   GURL page_url1("http://www.google.com");
1499   GURL page_url2("http://www.google.ca");
1500
1501   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1502   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
1503                             &favicon_bitmap_data);
1504
1505   backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data);
1506
1507   std::vector<GURL> icon_urls;
1508   icon_urls.push_back(icon_url);
1509
1510   std::vector<chrome::FaviconBitmapResult> bitmap_results;
1511   backend_->UpdateFaviconMappingsAndFetch(
1512       page_url2, icon_urls, chrome::FAVICON, kSmallSize.width(),
1513       GetScaleFactors1x2x(), &bitmap_results);
1514
1515   // Check that the same FaviconID is mapped to both page URLs.
1516   std::vector<IconMapping> icon_mappings;
1517   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
1518       page_url1, &icon_mappings));
1519   EXPECT_EQ(1u, icon_mappings.size());
1520   chrome::FaviconID favicon_id = icon_mappings[0].icon_id;
1521   EXPECT_NE(0, favicon_id);
1522
1523   icon_mappings.clear();
1524   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
1525       page_url2, &icon_mappings));
1526   EXPECT_EQ(1u, icon_mappings.size());
1527   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
1528
1529   // Change the icon URL that |page_url1| is mapped to.
1530   GenerateFaviconBitmapData(icon_url_new, GetSizesSmall(),
1531                             &favicon_bitmap_data);
1532   backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data);
1533
1534   // |page_url1| should map to a new FaviconID and have valid bitmap data.
1535   icon_mappings.clear();
1536   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
1537       page_url1, &icon_mappings));
1538   EXPECT_EQ(1u, icon_mappings.size());
1539   EXPECT_EQ(icon_url_new, icon_mappings[0].icon_url);
1540   EXPECT_NE(favicon_id, icon_mappings[0].icon_id);
1541
1542   std::vector<FaviconBitmap> favicon_bitmaps;
1543   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
1544       icon_mappings[0].icon_id, &favicon_bitmaps));
1545   EXPECT_EQ(1u, favicon_bitmaps.size());
1546
1547   // |page_url2| should still map to the same FaviconID and have valid bitmap
1548   // data.
1549   icon_mappings.clear();
1550   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
1551       page_url2, &icon_mappings));
1552   EXPECT_EQ(1u, icon_mappings.size());
1553   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
1554
1555   favicon_bitmaps.clear();
1556   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(favicon_id,
1557                                                          &favicon_bitmaps));
1558   EXPECT_EQ(2u, favicon_bitmaps.size());
1559
1560   // A notification should have been broadcast for each call to SetFavicons()
1561   // and each call to UpdateFaviconMappingsAndFetch().
1562   EXPECT_EQ(3, num_broadcasted_notifications());
1563 }
1564
1565 // Test that no notifications are broadcast as a result of calling
1566 // UpdateFaviconMappingsAndFetch() for an icon URL which is already
1567 // mapped to the passed in page URL.
1568 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoChange) {
1569   GURL page_url("http://www.google.com");
1570   GURL icon_url("http://www.google.com/favicon.ico");
1571   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1572   GenerateFaviconBitmapData(icon_url, GetSizesSmall(), &favicon_bitmap_data);
1573
1574   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1575
1576   chrome::FaviconID icon_id =
1577     backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1578         icon_url, chrome::FAVICON, NULL);
1579   EXPECT_NE(0, icon_id);
1580   EXPECT_EQ(1, num_broadcasted_notifications());
1581
1582   std::vector<GURL> icon_urls;
1583   icon_urls.push_back(icon_url);
1584
1585   std::vector<chrome::FaviconBitmapResult> bitmap_results;
1586   backend_->UpdateFaviconMappingsAndFetch(
1587       page_url, icon_urls, chrome::FAVICON, kSmallSize.width(),
1588       GetScaleFactors1x2x(), &bitmap_results);
1589
1590   EXPECT_EQ(icon_id, backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1591       icon_url, chrome::FAVICON, NULL));
1592
1593   // No notification should have been broadcast as no icon mapping, favicon,
1594   // or favicon bitmap was updated, added or removed.
1595   EXPECT_EQ(1, num_broadcasted_notifications());
1596 }
1597
1598 // Test repeatedly calling MergeFavicon(). |page_url| is initially not known
1599 // to the database.
1600 TEST_F(HistoryBackendTest, MergeFaviconPageURLNotInDB) {
1601   GURL page_url("http://www.google.com");
1602   GURL icon_url("http:/www.google.com/favicon.ico");
1603
1604   std::vector<unsigned char> data;
1605   data.push_back('a');
1606   scoped_refptr<base::RefCountedBytes> bitmap_data(
1607       new base::RefCountedBytes(data));
1608
1609   backend_->MergeFavicon(
1610       page_url, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
1611
1612   // |page_url| should now be mapped to |icon_url| and the favicon bitmap should
1613   // not be expired.
1614   std::vector<IconMapping> icon_mappings;
1615   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1616       &icon_mappings));
1617   EXPECT_EQ(1u, icon_mappings.size());
1618   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
1619
1620   FaviconBitmap favicon_bitmap;
1621   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
1622   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1623   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
1624   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1625
1626   data[0] = 'b';
1627   bitmap_data = new base::RefCountedBytes(data);
1628   backend_->MergeFavicon(
1629       page_url, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
1630
1631   // |page_url| should still have a single favicon bitmap. The bitmap data
1632   // should be updated.
1633   icon_mappings.clear();
1634   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1635       &icon_mappings));
1636   EXPECT_EQ(1u, icon_mappings.size());
1637   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
1638
1639   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
1640   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1641   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
1642   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1643 }
1644
1645 // Test calling MergeFavicon() when |page_url| is known to the database.
1646 TEST_F(HistoryBackendTest, MergeFaviconPageURLInDB) {
1647   GURL page_url("http://www.google.com");
1648   GURL icon_url1("http:/www.google.com/favicon.ico");
1649   GURL icon_url2("http://www.google.com/favicon2.ico");
1650
1651   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1652   GenerateFaviconBitmapData(icon_url1, GetSizesSmall(),
1653                             &favicon_bitmap_data);
1654
1655   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1656
1657   // Test initial state.
1658   std::vector<IconMapping> icon_mappings;
1659   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1660       &icon_mappings));
1661   EXPECT_EQ(1u, icon_mappings.size());
1662   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
1663
1664   FaviconBitmap favicon_bitmap;
1665   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
1666   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1667   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
1668   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1669
1670   EXPECT_EQ(1, num_broadcasted_notifications());
1671
1672   // 1) Merge identical favicon bitmap.
1673   std::vector<unsigned char> data;
1674   data.push_back('a');
1675   scoped_refptr<base::RefCountedBytes> bitmap_data(
1676       new base::RefCountedBytes(data));
1677   backend_->MergeFavicon(
1678       page_url, icon_url1, chrome::FAVICON, bitmap_data, kSmallSize);
1679
1680   // All the data should stay the same and no notifications should have been
1681   // sent.
1682   icon_mappings.clear();
1683   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1684       &icon_mappings));
1685   EXPECT_EQ(1u, icon_mappings.size());
1686   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
1687
1688   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
1689   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1690   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
1691   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1692
1693   EXPECT_EQ(1, num_broadcasted_notifications());
1694
1695   // 2) Merge favicon bitmap of the same size.
1696   data[0] = 'b';
1697   bitmap_data = new base::RefCountedBytes(data);
1698   backend_->MergeFavicon(
1699       page_url, icon_url1, chrome::FAVICON, bitmap_data, kSmallSize);
1700
1701   // The small favicon bitmap at |icon_url1| should be overwritten.
1702   icon_mappings.clear();
1703   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1704       &icon_mappings));
1705   EXPECT_EQ(1u, icon_mappings.size());
1706   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
1707
1708   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
1709   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1710   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
1711   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1712
1713   // 3) Merge favicon for the same icon URL, but a pixel size for which there is
1714   // no favicon bitmap.
1715   data[0] = 'c';
1716   bitmap_data = new base::RefCountedBytes(data);
1717   backend_->MergeFavicon(
1718       page_url, icon_url1, chrome::FAVICON, bitmap_data, kTinySize);
1719
1720   // A new favicon bitmap should be created and the preexisting favicon bitmap
1721   // ('b') should be expired.
1722   icon_mappings.clear();
1723   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1724       &icon_mappings));
1725   EXPECT_EQ(1u, icon_mappings.size());
1726   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
1727
1728   std::vector<FaviconBitmap> favicon_bitmaps;
1729   EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id,
1730                                       &favicon_bitmaps));
1731   EXPECT_NE(base::Time(), favicon_bitmaps[0].last_updated);
1732   EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data));
1733   EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size);
1734   EXPECT_EQ(base::Time(), favicon_bitmaps[1].last_updated);
1735   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data));
1736   EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size);
1737
1738   // 4) Merge favicon for an icon URL different from the icon URLs already
1739   // mapped to page URL.
1740   data[0] = 'd';
1741   bitmap_data = new base::RefCountedBytes(data);
1742   backend_->MergeFavicon(
1743       page_url, icon_url2, chrome::FAVICON, bitmap_data, kSmallSize);
1744
1745   // The existing favicon bitmaps should be copied over to the newly created
1746   // favicon at |icon_url2|. |page_url| should solely be mapped to |icon_url2|.
1747   icon_mappings.clear();
1748   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1749       &icon_mappings));
1750   EXPECT_EQ(1u, icon_mappings.size());
1751   EXPECT_EQ(icon_url2, icon_mappings[0].icon_url);
1752
1753   favicon_bitmaps.clear();
1754   EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id,
1755                                       &favicon_bitmaps));
1756   EXPECT_EQ(base::Time(), favicon_bitmaps[0].last_updated);
1757   EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data));
1758   EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size);
1759   // The favicon being merged should take precedence over the preexisting
1760   // favicon bitmaps.
1761   EXPECT_NE(base::Time(), favicon_bitmaps[1].last_updated);
1762   EXPECT_TRUE(BitmapDataEqual('d', favicon_bitmaps[1].bitmap_data));
1763   EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size);
1764
1765   // A notification should have been broadcast for each call to SetFavicons()
1766   // and MergeFavicon().
1767   EXPECT_EQ(4, num_broadcasted_notifications());
1768 }
1769
1770 // Test calling MergeFavicon() when |icon_url| is known to the database but not
1771 // mapped to |page_url|.
1772 TEST_F(HistoryBackendTest, MergeFaviconIconURLMappedToDifferentPageURL) {
1773   GURL page_url1("http://www.google.com");
1774   GURL page_url2("http://news.google.com");
1775   GURL page_url3("http://maps.google.com");
1776   GURL icon_url("http:/www.google.com/favicon.ico");
1777
1778   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1779   GenerateFaviconBitmapData(icon_url, GetSizesSmall(),
1780                             &favicon_bitmap_data);
1781
1782   backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data);
1783
1784   // Test initial state.
1785   std::vector<IconMapping> icon_mappings;
1786   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
1787       &icon_mappings));
1788   EXPECT_EQ(1u, icon_mappings.size());
1789   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
1790
1791   FaviconBitmap favicon_bitmap;
1792   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
1793   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1794   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
1795   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1796
1797   // 1) Merge in an identical favicon bitmap data but for a different page URL.
1798   std::vector<unsigned char> data;
1799   data.push_back('a');
1800   scoped_refptr<base::RefCountedBytes> bitmap_data(
1801       new base::RefCountedBytes(data));
1802
1803   backend_->MergeFavicon(
1804       page_url2, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
1805
1806   chrome::FaviconID favicon_id =
1807     backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1808         icon_url, chrome::FAVICON, NULL);
1809   EXPECT_NE(0, favicon_id);
1810
1811   EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
1812   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1813   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
1814   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1815
1816   // 2) Merging a favicon bitmap with different bitmap data for the same icon
1817   // URL should overwrite the small favicon bitmap at |icon_url|.
1818   bitmap_data->data()[0] = 'b';
1819   backend_->MergeFavicon(
1820       page_url3, icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
1821
1822   favicon_id = backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
1823       icon_url, chrome::FAVICON, NULL);
1824   EXPECT_NE(0, favicon_id);
1825
1826   EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
1827   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
1828   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
1829   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
1830
1831   // |icon_url| should be mapped to all three page URLs.
1832   icon_mappings.clear();
1833   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
1834       &icon_mappings));
1835   EXPECT_EQ(1u, icon_mappings.size());
1836   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
1837
1838   icon_mappings.clear();
1839   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url2,
1840       &icon_mappings));
1841   EXPECT_EQ(1u, icon_mappings.size());
1842   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
1843
1844   icon_mappings.clear();
1845   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url3,
1846       &icon_mappings));
1847   EXPECT_EQ(1u, icon_mappings.size());
1848   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
1849
1850   // A notification should have been broadcast for each call to SetFavicons()
1851   // and MergeFavicon().
1852   EXPECT_EQ(3, num_broadcasted_notifications());
1853 }
1854
1855 // Test that MergeFavicon() does not add more than
1856 // |kMaxFaviconBitmapsPerIconURL| to a favicon.
1857 TEST_F(HistoryBackendTest, MergeFaviconMaxFaviconBitmapsPerIconURL) {
1858   GURL page_url("http://www.google.com");
1859   std::string icon_url_string("http://www.google.com/favicon.ico");
1860   size_t replace_index = icon_url_string.size() - 1;
1861
1862   std::vector<unsigned char> data;
1863   data.push_back('a');
1864   scoped_refptr<base::RefCountedMemory> bitmap_data =
1865       base::RefCountedBytes::TakeVector(&data);
1866
1867   int pixel_size = 1;
1868   for (size_t i = 0; i < kMaxFaviconBitmapsPerIconURL + 1; ++i) {
1869     icon_url_string[replace_index] = '0' + i;
1870     GURL icon_url(icon_url_string);
1871
1872     backend_->MergeFavicon(page_url, icon_url, chrome::FAVICON, bitmap_data,
1873                            gfx::Size(pixel_size, pixel_size));
1874     ++pixel_size;
1875   }
1876
1877   // There should be a single favicon mapped to |page_url| with exactly
1878   // kMaxFaviconBitmapsPerIconURL favicon bitmaps.
1879   std::vector<IconMapping> icon_mappings;
1880   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
1881       &icon_mappings));
1882   EXPECT_EQ(1u, icon_mappings.size());
1883   std::vector<FaviconBitmap> favicon_bitmaps;
1884   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
1885       icon_mappings[0].icon_id, &favicon_bitmaps));
1886   EXPECT_EQ(kMaxFaviconBitmapsPerIconURL, favicon_bitmaps.size());
1887 }
1888
1889 // Tests that the favicon set by MergeFavicon() shows up in the result of
1890 // GetFaviconsForURL().
1891 TEST_F(HistoryBackendTest, MergeFaviconShowsUpInGetFaviconsForURLResult) {
1892   GURL page_url("http://www.google.com");
1893   GURL icon_url("http://www.google.com/favicon.ico");
1894   GURL merged_icon_url("http://wwww.google.com/favicon2.ico");
1895
1896   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1897   GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(),
1898                             &favicon_bitmap_data);
1899
1900   // Set some preexisting favicons for |page_url|.
1901   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1902
1903   // Merge small favicon.
1904   std::vector<unsigned char> data;
1905   data.push_back('c');
1906   scoped_refptr<base::RefCountedBytes> bitmap_data(
1907       new base::RefCountedBytes(data));
1908   backend_->MergeFavicon(
1909       page_url, merged_icon_url, chrome::FAVICON, bitmap_data, kSmallSize);
1910
1911   // Request favicon bitmaps for both 1x and 2x to simulate request done by
1912   // BookmarkModel::GetFavicon().
1913   std::vector<chrome::FaviconBitmapResult> bitmap_results;
1914   backend_->GetFaviconsForURL(page_url, chrome::FAVICON, kSmallSize.width(),
1915                               GetScaleFactors1x2x(), &bitmap_results);
1916
1917   EXPECT_EQ(2u, bitmap_results.size());
1918   const chrome::FaviconBitmapResult& first_result = bitmap_results[0];
1919   const chrome::FaviconBitmapResult& result =
1920       (first_result.pixel_size == kSmallSize) ? first_result
1921                                               : bitmap_results[1];
1922   EXPECT_TRUE(BitmapDataEqual('c', result.bitmap_data));
1923 }
1924
1925 // Tests GetFaviconsForURL with icon_types priority,
1926 TEST_F(HistoryBackendTest, TestGetFaviconsForURLWithIconTypesPriority) {
1927   GURL page_url("http://www.google.com");
1928   GURL icon_url("http://www.google.com/favicon.ico");
1929   GURL touch_icon_url("http://wwww.google.com/touch_icon.ico");
1930
1931   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1932   std::vector<gfx::Size> favicon_size;
1933   favicon_size.push_back(gfx::Size(16, 16));
1934   favicon_size.push_back(gfx::Size(32, 32));
1935   GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
1936   ASSERT_EQ(2u, favicon_bitmap_data.size());
1937
1938   std::vector<chrome::FaviconBitmapData> touch_icon_bitmap_data;
1939   std::vector<gfx::Size> touch_icon_size;
1940   touch_icon_size.push_back(gfx::Size(64, 64));
1941   GenerateFaviconBitmapData(icon_url, touch_icon_size, &touch_icon_bitmap_data);
1942   ASSERT_EQ(1u, touch_icon_bitmap_data.size());
1943
1944   // Set some preexisting favicons for |page_url|.
1945   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1946   backend_->SetFavicons(page_url, chrome::TOUCH_ICON, touch_icon_bitmap_data);
1947
1948   chrome::FaviconBitmapResult result;
1949   std::vector<int> icon_types;
1950   icon_types.push_back(chrome::FAVICON);
1951   icon_types.push_back(chrome::TOUCH_ICON);
1952
1953   backend_->GetLargestFaviconForURL(page_url, icon_types, 16, &result);
1954
1955   // Verify the result icon is 32x32 favicon.
1956   EXPECT_EQ(gfx::Size(32, 32), result.pixel_size);
1957   EXPECT_EQ(chrome::FAVICON, result.icon_type);
1958
1959   // Change Minimal size to 32x32 and verify the 64x64 touch icon returned.
1960   backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result);
1961   EXPECT_EQ(gfx::Size(64, 64), result.pixel_size);
1962   EXPECT_EQ(chrome::TOUCH_ICON, result.icon_type);
1963 }
1964
1965 // Test the the first types of icon is returned if its size equal to the
1966 // second types icon.
1967 TEST_F(HistoryBackendTest, TestGetFaviconsForURLReturnFavicon) {
1968   GURL page_url("http://www.google.com");
1969   GURL icon_url("http://www.google.com/favicon.ico");
1970   GURL touch_icon_url("http://wwww.google.com/touch_icon.ico");
1971
1972   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1973   std::vector<gfx::Size> favicon_size;
1974   favicon_size.push_back(gfx::Size(16, 16));
1975   favicon_size.push_back(gfx::Size(32, 32));
1976   GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
1977   ASSERT_EQ(2u, favicon_bitmap_data.size());
1978
1979   std::vector<chrome::FaviconBitmapData> touch_icon_bitmap_data;
1980   std::vector<gfx::Size> touch_icon_size;
1981   touch_icon_size.push_back(gfx::Size(32, 32));
1982   GenerateFaviconBitmapData(icon_url, touch_icon_size, &touch_icon_bitmap_data);
1983   ASSERT_EQ(1u, touch_icon_bitmap_data.size());
1984
1985   // Set some preexisting favicons for |page_url|.
1986   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
1987   backend_->SetFavicons(page_url, chrome::TOUCH_ICON, touch_icon_bitmap_data);
1988
1989   chrome::FaviconBitmapResult result;
1990   std::vector<int> icon_types;
1991   icon_types.push_back(chrome::FAVICON);
1992   icon_types.push_back(chrome::TOUCH_ICON);
1993
1994   backend_->GetLargestFaviconForURL(page_url, icon_types, 16, &result);
1995
1996   // Verify the result icon is 32x32 favicon.
1997   EXPECT_EQ(gfx::Size(32, 32), result.pixel_size);
1998   EXPECT_EQ(chrome::FAVICON, result.icon_type);
1999
2000   // Change minimal size to 32x32 and verify the 32x32 favicon returned.
2001   chrome::FaviconBitmapResult result1;
2002   backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result1);
2003   EXPECT_EQ(gfx::Size(32, 32), result1.pixel_size);
2004   EXPECT_EQ(chrome::FAVICON, result1.icon_type);
2005 }
2006
2007 // Test the favicon is returned if its size is smaller than minimal size,
2008 // because it is only one available.
2009 TEST_F(HistoryBackendTest, TestGetFaviconsForURLReturnFaviconEvenItSmaller) {
2010   GURL page_url("http://www.google.com");
2011   GURL icon_url("http://www.google.com/favicon.ico");
2012
2013   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
2014   std::vector<gfx::Size> favicon_size;
2015   favicon_size.push_back(gfx::Size(16, 16));
2016   GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
2017   ASSERT_EQ(1u, favicon_bitmap_data.size());
2018
2019   // Set preexisting favicons for |page_url|.
2020   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
2021
2022   chrome::FaviconBitmapResult result;
2023   std::vector<int> icon_types;
2024   icon_types.push_back(chrome::FAVICON);
2025   icon_types.push_back(chrome::TOUCH_ICON);
2026
2027   backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result);
2028
2029   // Verify 16x16 icon is returned, even it small than minimal_size.
2030   EXPECT_EQ(gfx::Size(16, 16), result.pixel_size);
2031   EXPECT_EQ(chrome::FAVICON, result.icon_type);
2032 }
2033
2034 // Test UpdateFaviconMapingsAndFetch() when multiple icon types are passed in.
2035 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchMultipleIconTypes) {
2036   GURL page_url1("http://www.google.com");
2037   GURL page_url2("http://news.google.com");
2038   GURL page_url3("http://mail.google.com");
2039   GURL icon_urla("http://www.google.com/favicon1.ico");
2040   GURL icon_urlb("http://www.google.com/favicon2.ico");
2041   GURL icon_urlc("http://www.google.com/favicon3.ico");
2042
2043   // |page_url1| is mapped to |icon_urla| which if of type TOUCH_ICON.
2044   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
2045   GenerateFaviconBitmapData(icon_urla, GetSizesSmall(), &favicon_bitmap_data);
2046   backend_->SetFavicons(page_url1, chrome::TOUCH_ICON, favicon_bitmap_data);
2047
2048   // |page_url2| is mapped to |icon_urlb| and |icon_urlc| which are of type
2049   // TOUCH_PRECOMPOSED_ICON.
2050   GenerateFaviconBitmapData(icon_urlb, GetSizesSmall(), icon_urlc,
2051                             GetSizesSmall(), &favicon_bitmap_data);
2052   backend_->SetFavicons(
2053       page_url2, chrome::TOUCH_PRECOMPOSED_ICON, favicon_bitmap_data);
2054
2055   std::vector<GURL> icon_urls;
2056   icon_urls.push_back(icon_urla);
2057   icon_urls.push_back(icon_urlb);
2058   icon_urls.push_back(icon_urlc);
2059
2060   std::vector<chrome::FaviconBitmapResult> bitmap_results;
2061   backend_->UpdateFaviconMappingsAndFetch(
2062       page_url3,
2063       icon_urls,
2064       (chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON),
2065       kSmallSize.width(),
2066       GetScaleFactors1x2x(),
2067       &bitmap_results);
2068
2069   // |page_url1| and |page_url2| should still be mapped to the same icon URLs.
2070   std::vector<IconMapping> icon_mappings;
2071   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
2072       &icon_mappings));
2073   EXPECT_EQ(1u, icon_mappings.size());
2074   EXPECT_EQ(icon_urla, icon_mappings[0].icon_url);
2075   EXPECT_EQ(chrome::TOUCH_ICON, icon_mappings[0].icon_type);
2076
2077   icon_mappings.clear();
2078   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url2, &icon_mappings));
2079   EXPECT_EQ(2u, icon_mappings.size());
2080   EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url);
2081   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type);
2082   EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url);
2083   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type);
2084
2085   // |page_url3| should be mapped only to |icon_urlb| and |icon_urlc| as
2086   // TOUCH_PRECOMPOSED_ICON is the largest IconType.
2087   icon_mappings.clear();
2088   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url3, &icon_mappings));
2089   EXPECT_EQ(2u, icon_mappings.size());
2090   EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url);
2091   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type);
2092   EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url);
2093   EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type);
2094 }
2095
2096 // Test the results of GetFaviconsFromDB() when there are no found
2097 // favicons.
2098 TEST_F(HistoryBackendTest, GetFaviconsFromDBEmpty) {
2099   const GURL page_url("http://www.google.com/");
2100
2101   std::vector<chrome::FaviconBitmapResult> bitmap_results;
2102   EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
2103       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results));
2104   EXPECT_TRUE(bitmap_results.empty());
2105 }
2106
2107 // Test the results of GetFaviconsFromDB() when there are matching favicons
2108 // but there are no associated favicon bitmaps.
2109 TEST_F(HistoryBackendTest, GetFaviconsFromDBNoFaviconBitmaps) {
2110   const GURL page_url("http://www.google.com/");
2111   const GURL icon_url("http://www.google.com/icon1");
2112
2113   chrome::FaviconID icon_id = backend_->thumbnail_db_->AddFavicon(
2114       icon_url, chrome::FAVICON);
2115   EXPECT_NE(0, icon_id);
2116   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
2117
2118   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
2119   EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
2120       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2121   EXPECT_TRUE(bitmap_results_out.empty());
2122 }
2123
2124 // Test that GetFaviconsFromDB() returns results for the bitmaps which most
2125 // closely match the passed in desired size and scale factors.
2126 TEST_F(HistoryBackendTest, GetFaviconsFromDBSelectClosestMatch) {
2127   const GURL page_url("http://www.google.com/");
2128   const GURL icon_url("http://www.google.com/icon1");
2129
2130   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
2131   GenerateFaviconBitmapData(icon_url, GetSizesTinySmallAndLarge(),
2132                             &favicon_bitmap_data);
2133
2134   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
2135
2136   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
2137   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
2138                                           chrome::FAVICON,
2139                                           kSmallSize.width(),
2140                                           GetScaleFactors1x2x(),
2141                                           &bitmap_results_out));
2142
2143   // The bitmap data for the small and large bitmaps should be returned as their
2144   // sizes match exactly.
2145   EXPECT_EQ(2u, bitmap_results_out.size());
2146   // No required order for results.
2147   if (bitmap_results_out[0].pixel_size == kLargeSize) {
2148     chrome::FaviconBitmapResult tmp_result = bitmap_results_out[0];
2149     bitmap_results_out[0] = bitmap_results_out[1];
2150     bitmap_results_out[1] = tmp_result;
2151   }
2152
2153   EXPECT_FALSE(bitmap_results_out[0].expired);
2154   EXPECT_TRUE(BitmapDataEqual('b', bitmap_results_out[0].bitmap_data));
2155   EXPECT_EQ(kSmallSize, bitmap_results_out[0].pixel_size);
2156   EXPECT_EQ(icon_url, bitmap_results_out[0].icon_url);
2157   EXPECT_EQ(chrome::FAVICON, bitmap_results_out[0].icon_type);
2158
2159   EXPECT_FALSE(bitmap_results_out[1].expired);
2160   EXPECT_TRUE(BitmapDataEqual('c', bitmap_results_out[1].bitmap_data));
2161   EXPECT_EQ(kLargeSize, bitmap_results_out[1].pixel_size);
2162   EXPECT_EQ(icon_url, bitmap_results_out[1].icon_url);
2163   EXPECT_EQ(chrome::FAVICON, bitmap_results_out[1].icon_type);
2164 }
2165
2166 // Test that GetFaviconsFromDB() returns results from the icon URL whose
2167 // bitmaps most closely match the passed in desired size and scale factors.
2168 TEST_F(HistoryBackendTest, GetFaviconsFromDBSingleIconURL) {
2169   const GURL page_url("http://www.google.com/");
2170
2171   const GURL icon_url1("http://www.google.com/icon1");
2172   const GURL icon_url2("http://www.google.com/icon2");
2173
2174   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
2175   GenerateFaviconBitmapData(icon_url1, GetSizesSmall(), icon_url2,
2176                             GetSizesLarge(), &favicon_bitmap_data);
2177
2178   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
2179
2180   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
2181   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
2182                                           chrome::FAVICON,
2183                                           kSmallSize.width(),
2184                                           GetScaleFactors1x2x(),
2185                                           &bitmap_results_out));
2186
2187   // The results should have results for the icon URL with the large bitmap as
2188   // downscaling is preferred to upscaling.
2189   EXPECT_EQ(1u, bitmap_results_out.size());
2190   EXPECT_EQ(kLargeSize, bitmap_results_out[0].pixel_size);
2191   EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url);
2192 }
2193
2194 // Test the results of GetFaviconsFromDB() when called with different
2195 // |icon_types|.
2196 TEST_F(HistoryBackendTest, GetFaviconsFromDBIconType) {
2197   const GURL page_url("http://www.google.com/");
2198   const GURL icon_url1("http://www.google.com/icon1.png");
2199   const GURL icon_url2("http://www.google.com/icon2.png");
2200
2201   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
2202   GenerateFaviconBitmapData(icon_url1, GetSizesSmall(),  &favicon_bitmap_data);
2203   backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
2204
2205   GenerateFaviconBitmapData(icon_url2, GetSizesSmall(), &favicon_bitmap_data);
2206   backend_->SetFavicons(page_url, chrome::TOUCH_ICON, favicon_bitmap_data);
2207
2208   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
2209   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
2210       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2211
2212   EXPECT_EQ(1u, bitmap_results_out.size());
2213   EXPECT_EQ(chrome::FAVICON, bitmap_results_out[0].icon_type);
2214   EXPECT_EQ(icon_url1, bitmap_results_out[0].icon_url);
2215
2216   bitmap_results_out.clear();
2217   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::TOUCH_ICON,
2218       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2219
2220   EXPECT_EQ(1u, bitmap_results_out.size());
2221   EXPECT_EQ(chrome::TOUCH_ICON, bitmap_results_out[0].icon_type);
2222   EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url);
2223 }
2224
2225 // Test that GetFaviconsFromDB() correctly sets the expired flag for bitmap
2226 // reults.
2227 TEST_F(HistoryBackendTest, GetFaviconsFromDBExpired) {
2228   const GURL page_url("http://www.google.com/");
2229   const GURL icon_url("http://www.google.com/icon.png");
2230
2231   std::vector<unsigned char> data;
2232   data.push_back('a');
2233   scoped_refptr<base::RefCountedBytes> bitmap_data(
2234       base::RefCountedBytes::TakeVector(&data));
2235   base::Time last_updated = base::Time::FromTimeT(0);
2236   chrome::FaviconID icon_id =
2237       backend_->thumbnail_db_->AddFavicon(icon_url,
2238                                           chrome::FAVICON,
2239                                           bitmap_data,
2240                                           last_updated,
2241                                           kSmallSize);
2242   EXPECT_NE(0, icon_id);
2243   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
2244
2245   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
2246   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON,
2247       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2248
2249   EXPECT_EQ(1u, bitmap_results_out.size());
2250   EXPECT_TRUE(bitmap_results_out[0].expired);
2251 }
2252
2253 // Check that UpdateFaviconMappingsAndFetch() call back to the UI when there is
2254 // no valid thumbnail database.
2255 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoDB) {
2256   // Make the thumbnail database invalid.
2257   backend_->thumbnail_db_.reset();
2258
2259   std::vector<chrome::FaviconBitmapResult> bitmap_results;
2260
2261   backend_->UpdateFaviconMappingsAndFetch(
2262       GURL(), std::vector<GURL>(), chrome::FAVICON, kSmallSize.width(),
2263       GetScaleFactors1x2x(), &bitmap_results);
2264
2265   EXPECT_TRUE(bitmap_results.empty());
2266 }
2267
2268 TEST_F(HistoryBackendTest, CloneFaviconIsRestrictedToSameDomain) {
2269   const GURL url("http://www.google.com/");
2270   const GURL same_domain_url("http://www.google.com/subdir/index.html");
2271   const GURL foreign_domain_url("http://www.not-google.com/");
2272   const GURL icon_url("http://www.google.com/icon.png");
2273
2274   // Add a favicon
2275   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
2276   GenerateFaviconBitmapData(icon_url, GetSizesSmall(),  &favicon_bitmap_data);
2277   backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data);
2278   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
2279       url, chrome::FAVICON, NULL));
2280
2281   // Validate starting state.
2282   std::vector<chrome::FaviconBitmapResult> bitmap_results_out;
2283   EXPECT_TRUE(backend_->GetFaviconsFromDB(url, chrome::FAVICON,
2284       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2285   EXPECT_FALSE(backend_->GetFaviconsFromDB(same_domain_url, chrome::FAVICON,
2286       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2287   EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url, chrome::FAVICON,
2288       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2289
2290   // Same-domain cloning should work.
2291   backend_->CloneFavicons(url, same_domain_url);
2292   EXPECT_TRUE(backend_->GetFaviconsFromDB(same_domain_url, chrome::FAVICON,
2293       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2294
2295   // Foreign-domain cloning is forbidden.
2296   backend_->CloneFavicons(url, foreign_domain_url);
2297   EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url, chrome::FAVICON,
2298       kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out));
2299 }
2300
2301 TEST_F(HistoryBackendTest, QueryFilteredURLs) {
2302   const char* google = "http://www.google.com/";
2303   const char* yahoo = "http://www.yahoo.com/";
2304   const char* yahoo_sports = "http://sports.yahoo.com/";
2305   const char* yahoo_sports_with_article1 =
2306       "http://sports.yahoo.com/article1.htm";
2307   const char* yahoo_sports_with_article2 =
2308       "http://sports.yahoo.com/article2.htm";
2309   const char* yahoo_sports_soccer = "http://sports.yahoo.com/soccer";
2310   const char* apple = "http://www.apple.com/";
2311
2312   // Clear all history.
2313   backend_->DeleteAllHistory();
2314
2315   Time tested_time = Time::Now().LocalMidnight() +
2316                      base::TimeDelta::FromHours(4);
2317   base::TimeDelta half_an_hour = base::TimeDelta::FromMinutes(30);
2318   base::TimeDelta one_hour = base::TimeDelta::FromHours(1);
2319   base::TimeDelta one_day = base::TimeDelta::FromDays(1);
2320
2321   const content::PageTransition kTypedTransition =
2322       content::PAGE_TRANSITION_TYPED;
2323   const content::PageTransition kKeywordGeneratedTransition =
2324       content::PAGE_TRANSITION_KEYWORD_GENERATED;
2325
2326   const char* redirect_sequence[2];
2327   redirect_sequence[1] = NULL;
2328
2329   redirect_sequence[0] = google;
2330   AddRedirectChainWithTransitionAndTime(
2331       redirect_sequence, 0, kTypedTransition,
2332       tested_time - one_day - half_an_hour * 2);
2333   AddRedirectChainWithTransitionAndTime(
2334       redirect_sequence, 0,
2335       kTypedTransition, tested_time - one_day);
2336   AddRedirectChainWithTransitionAndTime(
2337       redirect_sequence, 0,
2338       kTypedTransition, tested_time - half_an_hour / 2);
2339   AddRedirectChainWithTransitionAndTime(
2340       redirect_sequence, 0,
2341       kTypedTransition, tested_time);
2342
2343   // Add a visit with a transition that will make sure that no segment gets
2344   // created for this page (so the subsequent entries will have different URLIDs
2345   // and SegmentIDs).
2346   redirect_sequence[0] = apple;
2347   AddRedirectChainWithTransitionAndTime(
2348       redirect_sequence, 0, kKeywordGeneratedTransition,
2349       tested_time - one_day + one_hour * 6);
2350
2351   redirect_sequence[0] = yahoo;
2352   AddRedirectChainWithTransitionAndTime(
2353       redirect_sequence, 0, kTypedTransition,
2354       tested_time - one_day + half_an_hour);
2355   AddRedirectChainWithTransitionAndTime(
2356       redirect_sequence, 0, kTypedTransition,
2357       tested_time - one_day + half_an_hour * 2);
2358
2359   redirect_sequence[0] = yahoo_sports;
2360   AddRedirectChainWithTransitionAndTime(
2361       redirect_sequence, 0, kTypedTransition,
2362       tested_time - one_day - half_an_hour * 2);
2363   AddRedirectChainWithTransitionAndTime(
2364       redirect_sequence, 0, kTypedTransition,
2365       tested_time - one_day);
2366   int transition1, transition2;
2367   AddClientRedirect(GURL(yahoo_sports), GURL(yahoo_sports_with_article1), false,
2368                     tested_time - one_day + half_an_hour,
2369                     &transition1, &transition2);
2370   AddClientRedirect(GURL(yahoo_sports_with_article1),
2371                     GURL(yahoo_sports_with_article2),
2372                     false,
2373                     tested_time - one_day + half_an_hour * 2,
2374                     &transition1, &transition2);
2375
2376   redirect_sequence[0] = yahoo_sports_soccer;
2377   AddRedirectChainWithTransitionAndTime(redirect_sequence, 0,
2378                                         kTypedTransition,
2379                                         tested_time - half_an_hour);
2380   backend_->Commit();
2381
2382   scoped_refptr<QueryFilteredURLsRequest> request1 =
2383       new history::QueryFilteredURLsRequest(
2384           base::Bind(&HistoryBackendTest::OnQueryFiltered,
2385                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
2386   HistoryBackendCancelableRequest cancellable_request;
2387   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
2388       request1.get());
2389
2390   VisitFilter filter;
2391   // Time limit is |tested_time| +/- 45 min.
2392   base::TimeDelta three_quarters_of_an_hour = base::TimeDelta::FromMinutes(45);
2393   filter.SetFilterTime(tested_time);
2394   filter.SetFilterWidth(three_quarters_of_an_hour);
2395   backend_->QueryFilteredURLs(request1, 100, filter, false);
2396
2397   ASSERT_EQ(4U, get_filtered_list().size());
2398   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
2399   EXPECT_EQ(std::string(yahoo_sports_soccer),
2400             get_filtered_list()[1].url.spec());
2401   EXPECT_EQ(std::string(yahoo), get_filtered_list()[2].url.spec());
2402   EXPECT_EQ(std::string(yahoo_sports),
2403             get_filtered_list()[3].url.spec());
2404
2405   // Time limit is between |tested_time| and |tested_time| + 2 hours.
2406   scoped_refptr<QueryFilteredURLsRequest> request2 =
2407       new history::QueryFilteredURLsRequest(
2408           base::Bind(&HistoryBackendTest::OnQueryFiltered,
2409                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
2410   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
2411       request2.get());
2412   filter.SetFilterTime(tested_time + one_hour);
2413   filter.SetFilterWidth(one_hour);
2414   backend_->QueryFilteredURLs(request2, 100, filter, false);
2415
2416   ASSERT_EQ(3U, get_filtered_list().size());
2417   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
2418   EXPECT_EQ(std::string(yahoo), get_filtered_list()[1].url.spec());
2419   EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec());
2420
2421   // Time limit is between |tested_time| - 2 hours and |tested_time|.
2422   scoped_refptr<QueryFilteredURLsRequest> request3 =
2423       new history::QueryFilteredURLsRequest(
2424           base::Bind(&HistoryBackendTest::OnQueryFiltered,
2425                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
2426   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
2427       request3.get());
2428   filter.SetFilterTime(tested_time - one_hour);
2429   filter.SetFilterWidth(one_hour);
2430   backend_->QueryFilteredURLs(request3, 100, filter, false);
2431
2432   ASSERT_EQ(3U, get_filtered_list().size());
2433   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
2434   EXPECT_EQ(std::string(yahoo_sports_soccer),
2435             get_filtered_list()[1].url.spec());
2436   EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec());
2437
2438   filter.ClearFilters();
2439   base::Time::Exploded exploded_time;
2440   tested_time.LocalExplode(&exploded_time);
2441
2442   // Today.
2443   scoped_refptr<QueryFilteredURLsRequest> request4 =
2444       new history::QueryFilteredURLsRequest(
2445           base::Bind(&HistoryBackendTest::OnQueryFiltered,
2446                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
2447   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
2448       request4.get());
2449   filter.SetFilterTime(tested_time);
2450   filter.SetDayOfTheWeekFilter(static_cast<int>(exploded_time.day_of_week));
2451   backend_->QueryFilteredURLs(request4, 100, filter, false);
2452
2453   ASSERT_EQ(2U, get_filtered_list().size());
2454   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
2455   EXPECT_EQ(std::string(yahoo_sports_soccer),
2456             get_filtered_list()[1].url.spec());
2457
2458   // Today + time limit - only yahoo_sports_soccer should fit.
2459   scoped_refptr<QueryFilteredURLsRequest> request5 =
2460       new history::QueryFilteredURLsRequest(
2461           base::Bind(&HistoryBackendTest::OnQueryFiltered,
2462                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
2463   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
2464       request5.get());
2465   filter.SetFilterTime(tested_time - base::TimeDelta::FromMinutes(40));
2466   filter.SetFilterWidth(base::TimeDelta::FromMinutes(20));
2467   backend_->QueryFilteredURLs(request5, 100, filter, false);
2468
2469   ASSERT_EQ(1U, get_filtered_list().size());
2470   EXPECT_EQ(std::string(yahoo_sports_soccer),
2471             get_filtered_list()[0].url.spec());
2472
2473   // Make sure we get debug data if we request it.
2474   scoped_refptr<QueryFilteredURLsRequest> request6 =
2475       new history::QueryFilteredURLsRequest(
2476           base::Bind(&HistoryBackendTest::OnQueryFiltered,
2477                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
2478   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
2479       request6.get());
2480   filter.SetFilterTime(tested_time);
2481   filter.SetFilterWidth(one_hour * 2);
2482   backend_->QueryFilteredURLs(request6, 100, filter, true);
2483
2484   // If the SegmentID is used by QueryFilteredURLs when generating the debug
2485   // data instead of the URLID, the |total_visits| for the |yahoo_sports_soccer|
2486   // entry will be zero instead of 1.
2487   ASSERT_GE(get_filtered_list().size(), 2U);
2488   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
2489   EXPECT_EQ(std::string(yahoo_sports_soccer),
2490       get_filtered_list()[1].url.spec());
2491   EXPECT_EQ(4U, get_filtered_list()[0].extended_info.total_visits);
2492   EXPECT_EQ(1U, get_filtered_list()[1].extended_info.total_visits);
2493 }
2494
2495 TEST_F(HistoryBackendTest, UpdateVisitDuration) {
2496   // This unit test will test adding and deleting visit details information.
2497   ASSERT_TRUE(backend_.get());
2498
2499   GURL url1("http://www.cnn.com");
2500   std::vector<VisitInfo> visit_info1, visit_info2;
2501   Time start_ts = Time::Now() - base::TimeDelta::FromDays(5);
2502   Time end_ts = start_ts + base::TimeDelta::FromDays(2);
2503   visit_info1.push_back(VisitInfo(start_ts, content::PAGE_TRANSITION_LINK));
2504
2505   GURL url2("http://www.example.com");
2506   visit_info2.push_back(VisitInfo(Time::Now() - base::TimeDelta::FromDays(10),
2507                                   content::PAGE_TRANSITION_LINK));
2508
2509   // Clear all history.
2510   backend_->DeleteAllHistory();
2511
2512   // Add the visits.
2513   backend_->AddVisits(url1, visit_info1, history::SOURCE_BROWSED);
2514   backend_->AddVisits(url2, visit_info2, history::SOURCE_BROWSED);
2515
2516   // Verify the entries for both visits were added in visit_details.
2517   VisitVector visits1, visits2;
2518   URLRow row;
2519   URLID url_id1 = backend_->db()->GetRowForURL(url1, &row);
2520   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1));
2521   ASSERT_EQ(1U, visits1.size());
2522   EXPECT_EQ(0, visits1[0].visit_duration.ToInternalValue());
2523
2524   URLID url_id2 = backend_->db()->GetRowForURL(url2, &row);
2525   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id2, &visits2));
2526   ASSERT_EQ(1U, visits2.size());
2527   EXPECT_EQ(0, visits2[0].visit_duration.ToInternalValue());
2528
2529   // Update the visit to cnn.com.
2530   backend_->UpdateVisitDuration(visits1[0].visit_id, end_ts);
2531
2532   // Check the duration for visiting cnn.com was correctly updated.
2533   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1));
2534   ASSERT_EQ(1U, visits1.size());
2535   base::TimeDelta expected_duration = end_ts - start_ts;
2536   EXPECT_EQ(expected_duration.ToInternalValue(),
2537             visits1[0].visit_duration.ToInternalValue());
2538
2539   // Remove the visit to cnn.com.
2540   ASSERT_TRUE(backend_->RemoveVisits(visits1));
2541 }
2542
2543 // Test for migration of adding visit_duration column.
2544 TEST_F(HistoryBackendTest, MigrationVisitDuration) {
2545   ASSERT_TRUE(backend_.get());
2546   backend_->Closing();
2547   backend_ = NULL;
2548
2549   base::FilePath old_history_path, old_history, old_archived;
2550   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
2551   old_history_path = old_history_path.AppendASCII("History");
2552   old_history = old_history_path.AppendASCII("HistoryNoDuration");
2553   old_archived = old_history_path.AppendASCII("ArchivedNoDuration");
2554
2555   // Copy history database file to current directory so that it will be deleted
2556   // in Teardown.
2557   base::FilePath new_history_path(getTestDir());
2558   base::DeleteFile(new_history_path, true);
2559   file_util::CreateDirectory(new_history_path);
2560   base::FilePath new_history_file =
2561       new_history_path.Append(chrome::kHistoryFilename);
2562   base::FilePath new_archived_file =
2563       new_history_path.Append(chrome::kArchivedHistoryFilename);
2564   ASSERT_TRUE(base::CopyFile(old_history, new_history_file));
2565   ASSERT_TRUE(base::CopyFile(old_archived, new_archived_file));
2566
2567   backend_ = new HistoryBackend(new_history_path,
2568                                 0,
2569                                 new HistoryBackendTestDelegate(this),
2570                                 &bookmark_model_);
2571   backend_->Init(std::string(), false);
2572   backend_->Closing();
2573   backend_ = NULL;
2574
2575   // Now both history and archived_history databases should already be migrated.
2576
2577   // Check version in history database first.
2578   int cur_version = HistoryDatabase::GetCurrentVersion();
2579   sql::Connection db;
2580   ASSERT_TRUE(db.Open(new_history_file));
2581   sql::Statement s(db.GetUniqueStatement(
2582       "SELECT value FROM meta WHERE key = 'version'"));
2583   ASSERT_TRUE(s.Step());
2584   int file_version = s.ColumnInt(0);
2585   EXPECT_EQ(cur_version, file_version);
2586
2587   // Check visit_duration column in visits table is created and set to 0.
2588   s.Assign(db.GetUniqueStatement(
2589       "SELECT visit_duration FROM visits LIMIT 1"));
2590   ASSERT_TRUE(s.Step());
2591   EXPECT_EQ(0, s.ColumnInt(0));
2592
2593   // Repeat version and visit_duration checks in archived history database
2594   // also.
2595   cur_version = ArchivedDatabase::GetCurrentVersion();
2596   sql::Connection archived_db;
2597   ASSERT_TRUE(archived_db.Open(new_archived_file));
2598   sql::Statement s1(archived_db.GetUniqueStatement(
2599       "SELECT value FROM meta WHERE key = 'version'"));
2600   ASSERT_TRUE(s1.Step());
2601   file_version = s1.ColumnInt(0);
2602   EXPECT_EQ(cur_version, file_version);
2603
2604   // Check visit_duration column in visits table is created and set to 0.
2605   s1.Assign(archived_db.GetUniqueStatement(
2606       "SELECT visit_duration FROM visits LIMIT 1"));
2607   ASSERT_TRUE(s1.Step());
2608   EXPECT_EQ(0, s1.ColumnInt(0));
2609 }
2610
2611 TEST_F(HistoryBackendTest, AddPageNoVisitForBookmark) {
2612   ASSERT_TRUE(backend_.get());
2613
2614   GURL url("http://www.google.com");
2615   string16 title(UTF8ToUTF16("Bookmark title"));
2616   backend_->AddPageNoVisitForBookmark(url, title);
2617
2618   URLRow row;
2619   backend_->GetURL(url, &row);
2620   EXPECT_EQ(url, row.url());
2621   EXPECT_EQ(title, row.title());
2622   EXPECT_EQ(0, row.visit_count());
2623
2624   backend_->DeleteURL(url);
2625   backend_->AddPageNoVisitForBookmark(url, string16());
2626   backend_->GetURL(url, &row);
2627   EXPECT_EQ(url, row.url());
2628   EXPECT_EQ(UTF8ToUTF16(url.spec()), row.title());
2629   EXPECT_EQ(0, row.visit_count());
2630 }
2631
2632 TEST_F(HistoryBackendTest, ExpireHistoryForTimes) {
2633   ASSERT_TRUE(backend_.get());
2634
2635   HistoryAddPageArgs args[10];
2636   for (size_t i = 0; i < arraysize(args); ++i) {
2637     args[i].url = GURL("http://example" +
2638                        std::string((i % 2 == 0 ? ".com" : ".net")));
2639     args[i].time = base::Time::FromInternalValue(i);
2640     backend_->AddPage(args[i]);
2641   }
2642   EXPECT_EQ(base::Time(), backend_->GetFirstRecordedTimeForTest());
2643
2644   URLRow row;
2645   for (size_t i = 0; i < arraysize(args); ++i) {
2646     EXPECT_TRUE(backend_->GetURL(args[i].url, &row));
2647   }
2648
2649   std::set<base::Time> times;
2650   times.insert(args[5].time);
2651   backend_->ExpireHistoryForTimes(times,
2652                                   base::Time::FromInternalValue(2),
2653                                   base::Time::FromInternalValue(8));
2654
2655   EXPECT_EQ(base::Time::FromInternalValue(0),
2656             backend_->GetFirstRecordedTimeForTest());
2657
2658   // Visits to http://example.com are untouched.
2659   VisitVector visit_vector;
2660   EXPECT_TRUE(backend_->GetVisitsForURL(
2661       backend_->db_->GetRowForURL(GURL("http://example.com"), NULL),
2662       &visit_vector));
2663   ASSERT_EQ(5u, visit_vector.size());
2664   EXPECT_EQ(base::Time::FromInternalValue(0), visit_vector[0].visit_time);
2665   EXPECT_EQ(base::Time::FromInternalValue(2), visit_vector[1].visit_time);
2666   EXPECT_EQ(base::Time::FromInternalValue(4), visit_vector[2].visit_time);
2667   EXPECT_EQ(base::Time::FromInternalValue(6), visit_vector[3].visit_time);
2668   EXPECT_EQ(base::Time::FromInternalValue(8), visit_vector[4].visit_time);
2669
2670   // Visits to http://example.net between [2,8] are removed.
2671   visit_vector.clear();
2672   EXPECT_TRUE(backend_->GetVisitsForURL(
2673       backend_->db_->GetRowForURL(GURL("http://example.net"), NULL),
2674       &visit_vector));
2675   ASSERT_EQ(2u, visit_vector.size());
2676   EXPECT_EQ(base::Time::FromInternalValue(1), visit_vector[0].visit_time);
2677   EXPECT_EQ(base::Time::FromInternalValue(9), visit_vector[1].visit_time);
2678
2679   EXPECT_EQ(base::Time::FromInternalValue(0),
2680             backend_->GetFirstRecordedTimeForTest());
2681 }
2682
2683 TEST_F(HistoryBackendTest, ExpireHistory) {
2684   ASSERT_TRUE(backend_.get());
2685   // Since history operations are dependent on the local timezone, make all
2686   // entries relative to a fixed, local reference time.
2687   base::Time reference_time = base::Time::UnixEpoch().LocalMidnight() +
2688                               base::TimeDelta::FromHours(12);
2689
2690   // Insert 4 entries into the database.
2691   HistoryAddPageArgs args[4];
2692   for (size_t i = 0; i < arraysize(args); ++i) {
2693     args[i].url = GURL("http://example" + base::IntToString(i) + ".com");
2694     args[i].time = reference_time + base::TimeDelta::FromDays(i);
2695     backend_->AddPage(args[i]);
2696   }
2697
2698   URLRow url_rows[4];
2699   for (unsigned int i = 0; i < arraysize(args); ++i)
2700     ASSERT_TRUE(backend_->GetURL(args[i].url, &url_rows[i]));
2701
2702   std::vector<ExpireHistoryArgs> expire_list;
2703   VisitVector visits;
2704
2705   // Passing an empty map should be a no-op.
2706   backend_->ExpireHistory(expire_list);
2707   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
2708   EXPECT_EQ(4U, visits.size());
2709
2710   // Trying to delete an unknown URL with the time of the first visit should
2711   // also be a no-op.
2712   expire_list.resize(expire_list.size() + 1);
2713   expire_list[0].SetTimeRangeForOneDay(args[0].time);
2714   expire_list[0].urls.insert(GURL("http://google.does-not-exist"));
2715   backend_->ExpireHistory(expire_list);
2716   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
2717   EXPECT_EQ(4U, visits.size());
2718
2719   // Now add the first URL with the same time -- it should get deleted.
2720   expire_list.back().urls.insert(url_rows[0].url());
2721   backend_->ExpireHistory(expire_list);
2722
2723   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
2724   ASSERT_EQ(3U, visits.size());
2725   EXPECT_EQ(visits[0].url_id, url_rows[1].id());
2726   EXPECT_EQ(visits[1].url_id, url_rows[2].id());
2727   EXPECT_EQ(visits[2].url_id, url_rows[3].id());
2728
2729   // The first recorded time should also get updated.
2730   EXPECT_EQ(backend_->GetFirstRecordedTimeForTest(), args[1].time);
2731
2732   // Now delete the rest of the visits in one call.
2733   for (unsigned int i = 1; i < arraysize(args); ++i) {
2734     expire_list.resize(expire_list.size() + 1);
2735     expire_list[i].SetTimeRangeForOneDay(args[i].time);
2736     expire_list[i].urls.insert(args[i].url);
2737   }
2738   backend_->ExpireHistory(expire_list);
2739
2740   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
2741   ASSERT_EQ(0U, visits.size());
2742 }
2743
2744 class HistoryBackendSegmentDurationTest : public HistoryBackendTest {
2745  public:
2746   HistoryBackendSegmentDurationTest() {}
2747
2748   virtual void SetUp() {
2749     CommandLine::ForCurrentProcess()->AppendSwitch(
2750         switches::kTrackActiveVisitTime);
2751     HistoryBackendTest::SetUp();
2752   }
2753
2754  private:
2755   DISALLOW_COPY_AND_ASSIGN(HistoryBackendSegmentDurationTest);
2756 };
2757
2758 // Assertions around segment durations.
2759 TEST_F(HistoryBackendSegmentDurationTest, SegmentDuration) {
2760   const GURL url1("http://www.google.com");
2761   const GURL url2("http://www.foo.com/m");
2762   const std::string segment1(VisitSegmentDatabase::ComputeSegmentName(url1));
2763   const std::string segment2(VisitSegmentDatabase::ComputeSegmentName(url2));
2764
2765   Time segment_time(VisitSegmentDatabase::SegmentTime(Time::Now()));
2766   URLRow url_info1(url1);
2767   url_info1.set_visit_count(0);
2768   url_info1.set_typed_count(0);
2769   url_info1.set_last_visit(segment_time);
2770   url_info1.set_hidden(false);
2771   const URLID url1_id = backend_->db()->AddURL(url_info1);
2772   EXPECT_NE(0, url1_id);
2773
2774   URLRow url_info2(url2);
2775   url_info2.set_visit_count(0);
2776   url_info2.set_typed_count(0);
2777   url_info2.set_last_visit(Time());
2778   url_info2.set_hidden(false);
2779   const URLID url2_id = backend_->db()->AddURL(url_info2);
2780   EXPECT_NE(0, url2_id);
2781   EXPECT_NE(url1_id, url2_id);
2782
2783   // Should not have any segments for the urls.
2784   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment1));
2785   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment2));
2786
2787   // Update the duration, which should implicitly create the segments.
2788   const TimeDelta segment1_time_delta(TimeDelta::FromHours(1));
2789   const TimeDelta segment2_time_delta(TimeDelta::FromHours(2));
2790   backend_->IncreaseSegmentDuration(url1, segment_time, segment1_time_delta);
2791   backend_->IncreaseSegmentDuration(url2, segment_time, segment2_time_delta);
2792
2793   // Get the ids of the segments that were created.
2794   const SegmentID segment1_id = backend_->db()->GetSegmentNamed(segment1);
2795   EXPECT_NE(0, segment1_id);
2796   const SegmentID segment2_id = backend_->db()->GetSegmentNamed(segment2);
2797   EXPECT_NE(0, segment2_id);
2798   EXPECT_NE(segment1_id, segment2_id);
2799
2800   // Make sure the values made it to the db.
2801   SegmentDurationID segment1_duration_id;
2802   TimeDelta fetched_delta;
2803   EXPECT_TRUE(backend_->db()->GetSegmentDuration(
2804                   segment1_id, segment_time, &segment1_duration_id,
2805                   &fetched_delta));
2806   EXPECT_NE(0, segment1_duration_id);
2807   EXPECT_EQ(segment1_time_delta.InHours(), fetched_delta.InHours());
2808
2809   SegmentDurationID segment2_duration_id;
2810   EXPECT_TRUE(backend_->db()->GetSegmentDuration(
2811                   segment2_id, segment_time, &segment2_duration_id,
2812                   &fetched_delta));
2813   EXPECT_NE(0, segment2_duration_id);
2814   EXPECT_NE(segment1_duration_id, segment2_duration_id);
2815   EXPECT_EQ(segment2_time_delta.InHours(), fetched_delta.InHours());
2816
2817   // Query by duration. |url2| should be first as it has a longer view time.
2818   ScopedVector<PageUsageData> data;
2819   backend_->db()->QuerySegmentDuration(segment_time, 10, &data.get());
2820   ASSERT_EQ(2u, data.size());
2821   EXPECT_EQ(url2.spec(), data[0]->GetURL().spec());
2822   EXPECT_EQ(url2_id, data[0]->GetID());
2823   EXPECT_EQ(segment2_time_delta.InHours(), data[0]->duration().InHours());
2824
2825   EXPECT_EQ(url1.spec(), data[1]->GetURL().spec());
2826   EXPECT_EQ(url1_id, data[1]->GetID());
2827   EXPECT_EQ(segment1_time_delta.InHours(), data[1]->duration().InHours());
2828 }
2829
2830 // Simple test that removes a bookmark. This test exercises the code paths in
2831 // History that block till bookmark bar model is loaded.
2832 TEST_F(HistoryBackendTest, RemoveNotification) {
2833   scoped_ptr<TestingProfile> profile(new TestingProfile());
2834
2835   ASSERT_TRUE(profile->CreateHistoryService(false, false));
2836   profile->CreateBookmarkModel(true);
2837   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile.get());
2838   test::WaitForBookmarkModelToLoad(model);
2839
2840   // Add a URL.
2841   GURL url("http://www.google.com");
2842   bookmark_utils::AddIfNotBookmarked(model, url, base::string16());
2843
2844   HistoryService* service = HistoryServiceFactory::GetForProfile(
2845       profile.get(), Profile::EXPLICIT_ACCESS);
2846
2847   service->AddPage(
2848       url, base::Time::Now(), NULL, 1, GURL(), RedirectList(),
2849       content::PAGE_TRANSITION_TYPED, SOURCE_BROWSED, false);
2850
2851   // This won't actually delete the URL, rather it'll empty out the visits.
2852   // This triggers blocking on the BookmarkModel.
2853   service->DeleteURL(url);
2854 }
2855
2856 // Test DeleteFTSIndexDatabases deletes expected files.
2857 TEST_F(HistoryBackendTest, DeleteFTSIndexDatabases) {
2858   ASSERT_TRUE(backend_.get());
2859
2860   base::FilePath history_path(getTestDir());
2861   base::FilePath db1(history_path.AppendASCII("History Index 2013-05"));
2862   base::FilePath db1_journal(db1.InsertBeforeExtensionASCII("-journal"));
2863   base::FilePath db1_wal(db1.InsertBeforeExtensionASCII("-wal"));
2864   base::FilePath db2_symlink(history_path.AppendASCII("History Index 2013-06"));
2865   base::FilePath db2_actual(history_path.AppendASCII("Underlying DB"));
2866
2867   // Setup dummy index database files.
2868   const char* data = "Dummy";
2869   const size_t data_len = 5;
2870   ASSERT_TRUE(file_util::WriteFile(db1, data, data_len));
2871   ASSERT_TRUE(file_util::WriteFile(db1_journal, data, data_len));
2872   ASSERT_TRUE(file_util::WriteFile(db1_wal, data, data_len));
2873   ASSERT_TRUE(file_util::WriteFile(db2_actual, data, data_len));
2874 #if defined(OS_POSIX)
2875   EXPECT_TRUE(file_util::CreateSymbolicLink(db2_actual, db2_symlink));
2876 #endif
2877
2878   // Delete all DTS index databases.
2879   backend_->DeleteFTSIndexDatabases();
2880   EXPECT_FALSE(base::PathExists(db1));
2881   EXPECT_FALSE(base::PathExists(db1_wal));
2882   EXPECT_FALSE(base::PathExists(db1_journal));
2883   EXPECT_FALSE(base::PathExists(db2_symlink));
2884   EXPECT_TRUE(base::PathExists(db2_actual));  // Symlinks shouldn't be followed.
2885 }
2886
2887 }  // namespace history