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