Home | History | Annotate | Download | only in history
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/files/file_path.h"
      6 #include "base/files/scoped_temp_dir.h"
      7 #include "base/path_service.h"
      8 #include "base/strings/string_util.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/browser/history/url_database.h"
     11 #include "sql/connection.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 using base::Time;
     15 using base::TimeDelta;
     16 
     17 namespace history {
     18 
     19 namespace {
     20 
     21 bool IsURLRowEqual(const URLRow& a,
     22                    const URLRow& b) {
     23   // TODO(brettw) when the database stores an actual Time value rather than
     24   // a time_t, do a reaul comparison. Instead, we have to do a more rough
     25   // comparison since the conversion reduces the precision.
     26   return a.title() == b.title() &&
     27       a.visit_count() == b.visit_count() &&
     28       a.typed_count() == b.typed_count() &&
     29       a.last_visit() - b.last_visit() <= TimeDelta::FromSeconds(1) &&
     30       a.hidden() == b.hidden();
     31 }
     32 
     33 }  // namespace
     34 
     35 class URLDatabaseTest : public testing::Test,
     36                         public URLDatabase {
     37  public:
     38   URLDatabaseTest() {
     39   }
     40 
     41  protected:
     42   // Provided for URL/VisitDatabase.
     43   virtual sql::Connection& GetDB() OVERRIDE {
     44     return db_;
     45   }
     46 
     47  private:
     48   // Test setup.
     49   virtual void SetUp() {
     50     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     51     base::FilePath db_file = temp_dir_.path().AppendASCII("URLTest.db");
     52 
     53     EXPECT_TRUE(db_.Open(db_file));
     54 
     55     // Initialize the tables for this test.
     56     CreateURLTable(false);
     57     CreateMainURLIndex();
     58     InitKeywordSearchTermsTable();
     59     CreateKeywordSearchTermsIndices();
     60   }
     61   virtual void TearDown() {
     62     db_.Close();
     63   }
     64 
     65   base::ScopedTempDir temp_dir_;
     66   sql::Connection db_;
     67 };
     68 
     69 // Test add and query for the URL table in the HistoryDatabase.
     70 TEST_F(URLDatabaseTest, AddURL) {
     71   // First, add two URLs.
     72   const GURL url1("http://www.google.com/");
     73   URLRow url_info1(url1);
     74   url_info1.set_title(UTF8ToUTF16("Google"));
     75   url_info1.set_visit_count(4);
     76   url_info1.set_typed_count(2);
     77   url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
     78   url_info1.set_hidden(false);
     79   EXPECT_TRUE(AddURL(url_info1));
     80 
     81   const GURL url2("http://mail.google.com/");
     82   URLRow url_info2(url2);
     83   url_info2.set_title(UTF8ToUTF16("Google Mail"));
     84   url_info2.set_visit_count(3);
     85   url_info2.set_typed_count(0);
     86   url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(2));
     87   url_info2.set_hidden(true);
     88   EXPECT_TRUE(AddURL(url_info2));
     89 
     90   // Query both of them.
     91   URLRow info;
     92   EXPECT_TRUE(GetRowForURL(url1, &info));
     93   EXPECT_TRUE(IsURLRowEqual(url_info1, info));
     94   URLID id2 = GetRowForURL(url2, &info);
     95   EXPECT_TRUE(id2);
     96   EXPECT_TRUE(IsURLRowEqual(url_info2, info));
     97 
     98   // Update the second.
     99   url_info2.set_title(UTF8ToUTF16("Google Mail Too"));
    100   url_info2.set_visit_count(4);
    101   url_info2.set_typed_count(1);
    102   url_info2.set_typed_count(91011);
    103   url_info2.set_hidden(false);
    104   EXPECT_TRUE(UpdateURLRow(id2, url_info2));
    105 
    106   // Make sure it got updated.
    107   URLRow info2;
    108   EXPECT_TRUE(GetRowForURL(url2, &info2));
    109   EXPECT_TRUE(IsURLRowEqual(url_info2, info2));
    110 
    111   // Query a nonexistent URL.
    112   EXPECT_EQ(0, GetRowForURL(GURL("http://news.google.com/"), &info));
    113 
    114   // Delete all urls in the domain.
    115   // TODO(acw): test the new url based delete domain
    116   // EXPECT_TRUE(db.DeleteDomain(kDomainID));
    117 
    118   // Make sure the urls have been properly removed.
    119   // TODO(acw): commented out because remove no longer works.
    120   // EXPECT_TRUE(db.GetURLInfo(url1, NULL) == NULL);
    121   // EXPECT_TRUE(db.GetURLInfo(url2, NULL) == NULL);
    122 }
    123 
    124 // Tests adding, querying and deleting keyword visits.
    125 TEST_F(URLDatabaseTest, KeywordSearchTermVisit) {
    126   URLRow url_info1(GURL("http://www.google.com/"));
    127   url_info1.set_title(UTF8ToUTF16("Google"));
    128   url_info1.set_visit_count(4);
    129   url_info1.set_typed_count(2);
    130   url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    131   url_info1.set_hidden(false);
    132   URLID url_id = AddURL(url_info1);
    133   ASSERT_NE(0, url_id);
    134 
    135   // Add a keyword visit.
    136   TemplateURLID keyword_id = 100;
    137   string16 keyword = UTF8ToUTF16("visit");
    138   ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id, keyword_id, keyword));
    139 
    140   // Make sure we get it back.
    141   std::vector<KeywordSearchTermVisit> matches;
    142   GetMostRecentKeywordSearchTerms(keyword_id, keyword, 10, &matches);
    143   ASSERT_EQ(1U, matches.size());
    144   ASSERT_EQ(keyword, matches[0].term);
    145 
    146   KeywordSearchTermRow keyword_search_term_row;
    147   ASSERT_TRUE(GetKeywordSearchTermRow(url_id, &keyword_search_term_row));
    148   EXPECT_EQ(keyword_id, keyword_search_term_row.keyword_id);
    149   EXPECT_EQ(url_id, keyword_search_term_row.url_id);
    150   EXPECT_EQ(keyword, keyword_search_term_row.term);
    151 
    152   // Delete the keyword visit.
    153   DeleteAllSearchTermsForKeyword(keyword_id);
    154 
    155   // Make sure we don't get it back when querying.
    156   matches.clear();
    157   GetMostRecentKeywordSearchTerms(keyword_id, keyword, 10, &matches);
    158   ASSERT_EQ(0U, matches.size());
    159 
    160   ASSERT_FALSE(GetKeywordSearchTermRow(url_id, &keyword_search_term_row));
    161 }
    162 
    163 // Make sure deleting a URL also deletes a keyword visit.
    164 TEST_F(URLDatabaseTest, DeleteURLDeletesKeywordSearchTermVisit) {
    165   URLRow url_info1(GURL("http://www.google.com/"));
    166   url_info1.set_title(UTF8ToUTF16("Google"));
    167   url_info1.set_visit_count(4);
    168   url_info1.set_typed_count(2);
    169   url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    170   url_info1.set_hidden(false);
    171   URLID url_id = AddURL(url_info1);
    172   ASSERT_NE(0, url_id);
    173 
    174   // Add a keyword visit.
    175   ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id, 1, UTF8ToUTF16("visit")));
    176 
    177   // Delete the url.
    178   ASSERT_TRUE(DeleteURLRow(url_id));
    179 
    180   // Make sure the keyword visit was deleted.
    181   std::vector<KeywordSearchTermVisit> matches;
    182   GetMostRecentKeywordSearchTerms(1, UTF8ToUTF16("visit"), 10, &matches);
    183   ASSERT_EQ(0U, matches.size());
    184 }
    185 
    186 TEST_F(URLDatabaseTest, EnumeratorForSignificant) {
    187   std::set<std::string> good_urls;
    188   // Add URLs which do and don't meet the criteria.
    189   URLRow url_no_match(GURL("http://www.url_no_match.com/"));
    190   EXPECT_TRUE(AddURL(url_no_match));
    191 
    192   std::string url_string2("http://www.url_match_visit_count.com/");
    193   good_urls.insert("http://www.url_match_visit_count.com/");
    194   URLRow url_match_visit_count(GURL("http://www.url_match_visit_count.com/"));
    195   url_match_visit_count.set_visit_count(kLowQualityMatchVisitLimit);
    196   EXPECT_TRUE(AddURL(url_match_visit_count));
    197 
    198   good_urls.insert("http://www.url_match_typed_count.com/");
    199   URLRow url_match_typed_count(GURL("http://www.url_match_typed_count.com/"));
    200   url_match_typed_count.set_typed_count(kLowQualityMatchTypedLimit);
    201   EXPECT_TRUE(AddURL(url_match_typed_count));
    202 
    203   good_urls.insert("http://www.url_match_last_visit.com/");
    204   URLRow url_match_last_visit(GURL("http://www.url_match_last_visit.com/"));
    205   url_match_last_visit.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    206   EXPECT_TRUE(AddURL(url_match_last_visit));
    207 
    208   URLRow url_no_match_last_visit(GURL(
    209       "http://www.url_no_match_last_visit.com/"));
    210   url_no_match_last_visit.set_last_visit(Time::Now() -
    211       TimeDelta::FromDays(kLowQualityMatchAgeLimitInDays + 1));
    212   EXPECT_TRUE(AddURL(url_no_match_last_visit));
    213 
    214   URLDatabase::URLEnumerator history_enum;
    215   EXPECT_TRUE(InitURLEnumeratorForSignificant(&history_enum));
    216   URLRow row;
    217   int row_count = 0;
    218   for (; history_enum.GetNextURL(&row); ++row_count)
    219     EXPECT_EQ(1U, good_urls.count(row.url().spec()));
    220   EXPECT_EQ(3, row_count);
    221 }
    222 
    223 TEST_F(URLDatabaseTest, IconMappingEnumerator) {
    224   const GURL url1("http://www.google.com/");
    225   URLRow url_info1(url1);
    226   url_info1.set_title(UTF8ToUTF16("Google"));
    227   url_info1.set_visit_count(4);
    228   url_info1.set_typed_count(2);
    229   url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    230   url_info1.set_hidden(false);
    231 
    232   // Insert a row with favicon
    233   URLID url_id1 = AddURL(url_info1);
    234   ASSERT_NE(0, url_id1);
    235 
    236   chrome::FaviconID icon_id = 1;
    237   sql::Statement statement(GetDB().GetCachedStatement(
    238       SQL_FROM_HERE,
    239       "UPDATE urls SET favicon_id =? WHERE id=?"));
    240 
    241   ASSERT_TRUE(statement.is_valid());
    242 
    243   statement.BindInt64(0, icon_id);
    244   statement.BindInt64(1, url_id1);
    245   ASSERT_TRUE(statement.Run());
    246 
    247   // Insert another row without favicon
    248   const GURL url2("http://www.google.com/no_icon");
    249   URLRow url_info2(url2);
    250   url_info2.set_title(UTF8ToUTF16("Google"));
    251   url_info2.set_visit_count(4);
    252   url_info2.set_typed_count(2);
    253   url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    254   url_info2.set_hidden(false);
    255 
    256   // Insert a row with favicon
    257   URLID url_id2 = AddURL(url_info2);
    258   ASSERT_NE(0, url_id2);
    259 
    260   IconMappingEnumerator e;
    261   InitIconMappingEnumeratorForEverything(&e);
    262   IconMapping icon_mapping;
    263   ASSERT_TRUE(e.GetNextIconMapping(&icon_mapping));
    264   ASSERT_EQ(url1, icon_mapping.page_url);
    265   ASSERT_EQ(icon_id, icon_mapping.icon_id);
    266   ASSERT_FALSE(e.GetNextIconMapping(&icon_mapping));
    267 }
    268 
    269 // Test GetKeywordSearchTermRows and DeleteSearchTerm
    270 TEST_F(URLDatabaseTest, GetAndDeleteKeywordSearchTermByTerm) {
    271   URLRow url_info1(GURL("http://www.google.com/"));
    272   url_info1.set_title(UTF8ToUTF16("Google"));
    273   url_info1.set_visit_count(4);
    274   url_info1.set_typed_count(2);
    275   url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    276   url_info1.set_hidden(false);
    277   URLID url_id1 = AddURL(url_info1);
    278   ASSERT_NE(0, url_id1);
    279 
    280   // Add a keyword visit.
    281   TemplateURLID keyword_id = 100;
    282   string16 keyword = UTF8ToUTF16("visit");
    283   ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id1, keyword_id, keyword));
    284 
    285   URLRow url_info2(GURL("https://www.google.com/"));
    286   url_info2.set_title(UTF8ToUTF16("Google"));
    287   url_info2.set_visit_count(4);
    288   url_info2.set_typed_count(2);
    289   url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    290   url_info2.set_hidden(false);
    291   URLID url_id2 = AddURL(url_info2);
    292   ASSERT_NE(0, url_id2);
    293   // Add the same keyword for url_info2.
    294   ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id2, keyword_id, keyword));
    295 
    296   // Add another URL for different keyword.
    297   URLRow url_info3(GURL("https://www.google.com/search"));
    298   url_info3.set_title(UTF8ToUTF16("Google"));
    299   url_info3.set_visit_count(4);
    300   url_info3.set_typed_count(2);
    301   url_info3.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
    302   url_info3.set_hidden(false);
    303   URLID url_id3 = AddURL(url_info3);
    304   ASSERT_NE(0, url_id3);
    305   string16 keyword2 = UTF8ToUTF16("Search");
    306 
    307   ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id3, keyword_id, keyword2));
    308 
    309   // We should get 2 rows for |keyword|.
    310   std::vector<KeywordSearchTermRow> rows;
    311   ASSERT_TRUE(GetKeywordSearchTermRows(keyword, &rows));
    312   ASSERT_EQ(2u, rows.size());
    313   if (rows[0].url_id == url_id1) {
    314     EXPECT_EQ(keyword, rows[0].term);
    315     EXPECT_EQ(keyword, rows[1].term);
    316     EXPECT_EQ(url_id2, rows[1].url_id);
    317   } else {
    318     EXPECT_EQ(keyword, rows[0].term);
    319     EXPECT_EQ(url_id1, rows[1].url_id);
    320     EXPECT_EQ(keyword, rows[1].term);
    321     EXPECT_EQ(url_id2, rows[0].url_id);
    322   }
    323 
    324   // We should get 1 row for |keyword2|.
    325   rows.clear();
    326   ASSERT_TRUE(GetKeywordSearchTermRows(keyword2, &rows));
    327   ASSERT_EQ(1u, rows.size());
    328   EXPECT_EQ(keyword2, rows[0].term);
    329   EXPECT_EQ(url_id3, rows[0].url_id);
    330 
    331   // Delete all rows have keyword.
    332   ASSERT_TRUE(DeleteKeywordSearchTerm(keyword));
    333   rows.clear();
    334   // We should still find keyword2.
    335   ASSERT_TRUE(GetKeywordSearchTermRows(keyword2, &rows));
    336   ASSERT_EQ(1u, rows.size());
    337   EXPECT_EQ(keyword2, rows[0].term);
    338   EXPECT_EQ(url_id3, rows[0].url_id);
    339   rows.clear();
    340   // No row for keyword.
    341   ASSERT_TRUE(GetKeywordSearchTermRows(keyword, &rows));
    342   EXPECT_TRUE(rows.empty());
    343 }
    344 
    345 }  // namespace history
    346