1 // Copyright 2014 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.
5 #include "base/files/file_path.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/strings/string_util.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "components/history/core/browser/keyword_search_term.h"
10 #include "components/history/core/browser/url_database.h"
11 #include "sql/connection.h"
12 #include "testing/gtest/include/gtest/gtest.h"
15 using base::TimeDelta;
21 bool IsURLRowEqual(const URLRow& a,
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();
35 class URLDatabaseTest : public testing::Test,
42 // Provided for URL/VisitDatabase.
43 sql::Connection& GetDB() override { return db_; }
47 void SetUp() override {
48 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
49 base::FilePath db_file = temp_dir_.path().AppendASCII("URLTest.db");
51 EXPECT_TRUE(db_.Open(db_file));
53 // Initialize the tables for this test.
54 CreateURLTable(false);
56 InitKeywordSearchTermsTable();
57 CreateKeywordSearchTermsIndices();
59 void TearDown() override { db_.Close(); }
61 base::ScopedTempDir temp_dir_;
65 // Test add, update, upsert, and query for the URL table in the HistoryDatabase.
66 TEST_F(URLDatabaseTest, AddAndUpdateURL) {
67 // First, add two URLs.
68 const GURL url1("http://www.google.com/");
69 URLRow url_info1(url1);
70 url_info1.set_title(base::UTF8ToUTF16("Google"));
71 url_info1.set_visit_count(4);
72 url_info1.set_typed_count(2);
73 url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
74 url_info1.set_hidden(false);
75 URLID id1_initially = AddURL(url_info1);
76 EXPECT_TRUE(id1_initially);
78 const GURL url2("http://mail.google.com/");
79 URLRow url_info2(url2);
80 url_info2.set_title(base::UTF8ToUTF16("Google Mail"));
81 url_info2.set_visit_count(3);
82 url_info2.set_typed_count(0);
83 url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(2));
84 url_info2.set_hidden(true);
85 EXPECT_TRUE(AddURL(url_info2));
87 // Query both of them.
89 EXPECT_TRUE(GetRowForURL(url1, &info));
90 EXPECT_TRUE(IsURLRowEqual(url_info1, info));
91 URLID id2 = GetRowForURL(url2, &info);
93 EXPECT_TRUE(IsURLRowEqual(url_info2, info));
96 url_info2.set_title(base::UTF8ToUTF16("Google Mail Too"));
97 url_info2.set_visit_count(4);
98 url_info2.set_typed_count(1);
99 url_info2.set_typed_count(91011);
100 url_info2.set_hidden(false);
101 EXPECT_TRUE(UpdateURLRow(id2, url_info2));
103 // Make sure it got updated.
105 EXPECT_TRUE(GetRowForURL(url2, &info2));
106 EXPECT_TRUE(IsURLRowEqual(url_info2, info2));
108 // Try updating a non-existing row. This should fail and have no effects.
109 const GURL url3("http://youtube.com/");
110 URLRow url_info3(url3);
111 url_info3.set_id(42);
112 EXPECT_FALSE(UpdateURLRow(url_info3.id(), url_info3));
113 EXPECT_EQ(0, GetRowForURL(url3, &info));
115 // Update an existing URL and insert a new one using the upsert operation.
116 url_info1.set_id(id1_initially);
117 url_info1.set_title(base::UTF8ToUTF16("Google Again!"));
118 url_info1.set_visit_count(5);
119 url_info1.set_typed_count(3);
120 url_info1.set_last_visit(Time::Now());
121 url_info1.set_hidden(true);
122 EXPECT_TRUE(InsertOrUpdateURLRowByID(url_info1));
124 const GURL url4("http://maps.google.com/");
125 URLRow url_info4(url4);
126 url_info4.set_id(43);
127 url_info4.set_title(base::UTF8ToUTF16("Google Maps"));
128 url_info4.set_visit_count(7);
129 url_info4.set_typed_count(6);
130 url_info4.set_last_visit(Time::Now() - TimeDelta::FromDays(3));
131 url_info4.set_hidden(false);
132 EXPECT_TRUE(InsertOrUpdateURLRowByID(url_info4));
134 // Query both of these as well.
135 URLID id1 = GetRowForURL(url1, &info);
136 EXPECT_EQ(id1_initially, id1);
137 EXPECT_TRUE(IsURLRowEqual(url_info1, info));
138 URLID id4 = GetRowForURL(url4, &info);
140 EXPECT_TRUE(IsURLRowEqual(url_info4, info));
142 // Query a nonexistent URL.
143 EXPECT_EQ(0, GetRowForURL(GURL("http://news.google.com/"), &info));
145 // Delete all urls in the domain.
146 // TODO(acw): test the new url based delete domain
147 // EXPECT_TRUE(db.DeleteDomain(kDomainID));
149 // Make sure the urls have been properly removed.
150 // TODO(acw): commented out because remove no longer works.
151 // EXPECT_TRUE(db.GetURLInfo(url1, NULL) == NULL);
152 // EXPECT_TRUE(db.GetURLInfo(url2, NULL) == NULL);
155 // Tests adding, querying and deleting keyword visits.
156 TEST_F(URLDatabaseTest, KeywordSearchTermVisit) {
157 URLRow url_info1(GURL("http://www.google.com/"));
158 url_info1.set_title(base::UTF8ToUTF16("Google"));
159 url_info1.set_visit_count(4);
160 url_info1.set_typed_count(2);
161 url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
162 url_info1.set_hidden(false);
163 URLID url_id = AddURL(url_info1);
164 ASSERT_NE(0, url_id);
166 // Add a keyword visit.
167 KeywordID keyword_id = 100;
168 base::string16 keyword = base::UTF8ToUTF16("visit");
169 ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id, keyword_id, keyword));
171 // Make sure we get it back.
172 std::vector<KeywordSearchTermVisit> matches;
173 GetMostRecentKeywordSearchTerms(keyword_id, keyword, 10, &matches);
174 ASSERT_EQ(1U, matches.size());
175 ASSERT_EQ(keyword, matches[0].term);
177 KeywordSearchTermRow keyword_search_term_row;
178 ASSERT_TRUE(GetKeywordSearchTermRow(url_id, &keyword_search_term_row));
179 EXPECT_EQ(keyword_id, keyword_search_term_row.keyword_id);
180 EXPECT_EQ(url_id, keyword_search_term_row.url_id);
181 EXPECT_EQ(keyword, keyword_search_term_row.term);
183 // Delete the keyword visit.
184 DeleteAllSearchTermsForKeyword(keyword_id);
186 // Make sure we don't get it back when querying.
188 GetMostRecentKeywordSearchTerms(keyword_id, keyword, 10, &matches);
189 ASSERT_EQ(0U, matches.size());
191 ASSERT_FALSE(GetKeywordSearchTermRow(url_id, &keyword_search_term_row));
194 // Make sure deleting a URL also deletes a keyword visit.
195 TEST_F(URLDatabaseTest, DeleteURLDeletesKeywordSearchTermVisit) {
196 URLRow url_info1(GURL("http://www.google.com/"));
197 url_info1.set_title(base::UTF8ToUTF16("Google"));
198 url_info1.set_visit_count(4);
199 url_info1.set_typed_count(2);
200 url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
201 url_info1.set_hidden(false);
202 URLID url_id = AddURL(url_info1);
203 ASSERT_NE(0, url_id);
205 // Add a keyword visit.
207 SetKeywordSearchTermsForURL(url_id, 1, base::UTF8ToUTF16("visit")));
210 ASSERT_TRUE(DeleteURLRow(url_id));
212 // Make sure the keyword visit was deleted.
213 std::vector<KeywordSearchTermVisit> matches;
214 GetMostRecentKeywordSearchTerms(1, base::UTF8ToUTF16("visit"), 10, &matches);
215 ASSERT_EQ(0U, matches.size());
218 TEST_F(URLDatabaseTest, EnumeratorForSignificant) {
219 std::set<std::string> good_urls;
220 // Add URLs which do and don't meet the criteria.
221 URLRow url_no_match(GURL("http://www.url_no_match.com/"));
222 EXPECT_TRUE(AddURL(url_no_match));
224 std::string url_string2("http://www.url_match_visit_count.com/");
225 good_urls.insert("http://www.url_match_visit_count.com/");
226 URLRow url_match_visit_count(GURL("http://www.url_match_visit_count.com/"));
227 url_match_visit_count.set_visit_count(kLowQualityMatchVisitLimit);
228 EXPECT_TRUE(AddURL(url_match_visit_count));
230 good_urls.insert("http://www.url_match_typed_count.com/");
231 URLRow url_match_typed_count(GURL("http://www.url_match_typed_count.com/"));
232 url_match_typed_count.set_typed_count(kLowQualityMatchTypedLimit);
233 EXPECT_TRUE(AddURL(url_match_typed_count));
235 good_urls.insert("http://www.url_match_last_visit.com/");
236 URLRow url_match_last_visit(GURL("http://www.url_match_last_visit.com/"));
237 url_match_last_visit.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
238 EXPECT_TRUE(AddURL(url_match_last_visit));
240 URLRow url_no_match_last_visit(GURL(
241 "http://www.url_no_match_last_visit.com/"));
242 url_no_match_last_visit.set_last_visit(Time::Now() -
243 TimeDelta::FromDays(kLowQualityMatchAgeLimitInDays + 1));
244 EXPECT_TRUE(AddURL(url_no_match_last_visit));
246 URLDatabase::URLEnumerator history_enum;
247 EXPECT_TRUE(InitURLEnumeratorForSignificant(&history_enum));
250 for (; history_enum.GetNextURL(&row); ++row_count)
251 EXPECT_EQ(1U, good_urls.count(row.url().spec()));
252 EXPECT_EQ(3, row_count);
255 // Test GetKeywordSearchTermRows and DeleteSearchTerm
256 TEST_F(URLDatabaseTest, GetAndDeleteKeywordSearchTermByTerm) {
257 URLRow url_info1(GURL("http://www.google.com/"));
258 url_info1.set_title(base::UTF8ToUTF16("Google"));
259 url_info1.set_visit_count(4);
260 url_info1.set_typed_count(2);
261 url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
262 url_info1.set_hidden(false);
263 URLID url_id1 = AddURL(url_info1);
264 ASSERT_NE(0, url_id1);
266 // Add a keyword visit.
267 KeywordID keyword_id = 100;
268 base::string16 keyword = base::UTF8ToUTF16("visit");
269 ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id1, keyword_id, keyword));
271 URLRow url_info2(GURL("https://www.google.com/"));
272 url_info2.set_title(base::UTF8ToUTF16("Google"));
273 url_info2.set_visit_count(4);
274 url_info2.set_typed_count(2);
275 url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
276 url_info2.set_hidden(false);
277 URLID url_id2 = AddURL(url_info2);
278 ASSERT_NE(0, url_id2);
279 // Add the same keyword for url_info2.
280 ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id2, keyword_id, keyword));
282 // Add another URL for different keyword.
283 URLRow url_info3(GURL("https://www.google.com/search"));
284 url_info3.set_title(base::UTF8ToUTF16("Google"));
285 url_info3.set_visit_count(4);
286 url_info3.set_typed_count(2);
287 url_info3.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
288 url_info3.set_hidden(false);
289 URLID url_id3 = AddURL(url_info3);
290 ASSERT_NE(0, url_id3);
291 base::string16 keyword2 = base::UTF8ToUTF16("Search");
293 ASSERT_TRUE(SetKeywordSearchTermsForURL(url_id3, keyword_id, keyword2));
295 // We should get 2 rows for |keyword|.
296 std::vector<KeywordSearchTermRow> rows;
297 ASSERT_TRUE(GetKeywordSearchTermRows(keyword, &rows));
298 ASSERT_EQ(2u, rows.size());
299 if (rows[0].url_id == url_id1) {
300 EXPECT_EQ(keyword, rows[0].term);
301 EXPECT_EQ(keyword, rows[1].term);
302 EXPECT_EQ(url_id2, rows[1].url_id);
304 EXPECT_EQ(keyword, rows[0].term);
305 EXPECT_EQ(url_id1, rows[1].url_id);
306 EXPECT_EQ(keyword, rows[1].term);
307 EXPECT_EQ(url_id2, rows[0].url_id);
310 // We should get 1 row for |keyword2|.
312 ASSERT_TRUE(GetKeywordSearchTermRows(keyword2, &rows));
313 ASSERT_EQ(1u, rows.size());
314 EXPECT_EQ(keyword2, rows[0].term);
315 EXPECT_EQ(url_id3, rows[0].url_id);
317 // Delete all rows have keyword.
318 ASSERT_TRUE(DeleteKeywordSearchTerm(keyword));
320 // We should still find keyword2.
321 ASSERT_TRUE(GetKeywordSearchTermRows(keyword2, &rows));
322 ASSERT_EQ(1u, rows.size());
323 EXPECT_EQ(keyword2, rows[0].term);
324 EXPECT_EQ(url_id3, rows[0].url_id);
326 // No row for keyword.
327 ASSERT_TRUE(GetKeywordSearchTermRows(keyword, &rows));
328 EXPECT_TRUE(rows.empty());
331 } // namespace history