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