Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / visit_database_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 <set>
6 #include <vector>
7
8 #include "base/files/file_path.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/path_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/time/time.h"
13 #include "chrome/browser/history/url_database.h"
14 #include "chrome/browser/history/visit_database.h"
15 #include "sql/connection.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
18
19 using base::Time;
20 using base::TimeDelta;
21
22 namespace history {
23
24 namespace {
25
26 bool IsVisitInfoEqual(const VisitRow& a,
27                       const VisitRow& b) {
28   return a.visit_id == b.visit_id &&
29          a.url_id == b.url_id &&
30          a.visit_time == b.visit_time &&
31          a.referring_visit == b.referring_visit &&
32          a.transition == b.transition;
33 }
34
35 }  // namespace
36
37 class VisitDatabaseTest : public PlatformTest,
38                           public URLDatabase,
39                           public VisitDatabase {
40  public:
41   VisitDatabaseTest() {
42   }
43
44  private:
45   // Test setup.
46   virtual void SetUp() {
47     PlatformTest::SetUp();
48     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
49     base::FilePath db_file = temp_dir_.path().AppendASCII("VisitTest.db");
50
51     EXPECT_TRUE(db_.Open(db_file));
52
53     // Initialize the tables for this test.
54     CreateURLTable(false);
55     CreateMainURLIndex();
56     InitVisitTable();
57   }
58   virtual void TearDown() {
59     db_.Close();
60     PlatformTest::TearDown();
61   }
62
63   // Provided for URL/VisitDatabase.
64   virtual sql::Connection& GetDB() OVERRIDE {
65     return db_;
66   }
67
68   base::ScopedTempDir temp_dir_;
69   sql::Connection db_;
70 };
71
72 TEST_F(VisitDatabaseTest, Add) {
73   // Add one visit.
74   VisitRow visit_info1(1, Time::Now(), 0, content::PAGE_TRANSITION_LINK, 0);
75   EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
76
77   // Add second visit for the same page.
78   VisitRow visit_info2(visit_info1.url_id,
79       visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
80       content::PAGE_TRANSITION_TYPED, 0);
81   EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
82
83   // Add third visit for a different page.
84   VisitRow visit_info3(2,
85       visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
86       content::PAGE_TRANSITION_LINK, 0);
87   EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
88
89   // Query the first two.
90   std::vector<VisitRow> matches;
91   EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches));
92   EXPECT_EQ(static_cast<size_t>(2), matches.size());
93
94   // Make sure we got both (order in result set is visit time).
95   EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) &&
96               IsVisitInfoEqual(matches[1], visit_info2));
97 }
98
99 TEST_F(VisitDatabaseTest, Delete) {
100   // Add three visits that form a chain of navigation, and then delete the
101   // middle one. We should be left with the outer two visits, and the chain
102   // should link them.
103   static const int kTime1 = 1000;
104   VisitRow visit_info1(1, Time::FromInternalValue(kTime1), 0,
105                        content::PAGE_TRANSITION_LINK, 0);
106   EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
107
108   static const int kTime2 = kTime1 + 1;
109   VisitRow visit_info2(1, Time::FromInternalValue(kTime2),
110                        visit_info1.visit_id, content::PAGE_TRANSITION_LINK, 0);
111   EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
112
113   static const int kTime3 = kTime2 + 1;
114   VisitRow visit_info3(1, Time::FromInternalValue(kTime3),
115                        visit_info2.visit_id, content::PAGE_TRANSITION_LINK, 0);
116   EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
117
118   // First make sure all the visits are there.
119   std::vector<VisitRow> matches;
120   EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches));
121   EXPECT_EQ(static_cast<size_t>(3), matches.size());
122   EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) &&
123               IsVisitInfoEqual(matches[1], visit_info2) &&
124               IsVisitInfoEqual(matches[2], visit_info3));
125
126   // Delete the middle one.
127   DeleteVisit(visit_info2);
128
129   // The outer two should be left, and the last one should have the first as
130   // the referrer.
131   visit_info3.referring_visit = visit_info1.visit_id;
132   matches.clear();
133   EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches));
134   EXPECT_EQ(static_cast<size_t>(2), matches.size());
135   EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) &&
136               IsVisitInfoEqual(matches[1], visit_info3));
137 }
138
139 TEST_F(VisitDatabaseTest, Update) {
140   // Make something in the database.
141   VisitRow original(1, Time::Now(), 23, content::PageTransitionFromInt(0), 19);
142   AddVisit(&original, SOURCE_BROWSED);
143
144   // Mutate that row.
145   VisitRow modification(original);
146   modification.url_id = 2;
147   modification.transition = content::PAGE_TRANSITION_TYPED;
148   modification.visit_time = Time::Now() + TimeDelta::FromDays(1);
149   modification.referring_visit = 9292;
150   UpdateVisitRow(modification);
151
152   // Check that the mutated version was written.
153   VisitRow final;
154   GetRowForVisit(original.visit_id, &final);
155   EXPECT_TRUE(IsVisitInfoEqual(modification, final));
156 }
157
158 // TODO(brettw) write test for GetMostRecentVisitForURL!
159
160 namespace {
161
162 std::vector<VisitRow> GetTestVisitRows() {
163   // Tests can be sensitive to the local timezone, so use a local time as the
164   // basis for all visit times.
165   base::Time base_time = Time::UnixEpoch().LocalMidnight();
166
167   // Add one visit.
168   VisitRow visit_info1(1, base_time + TimeDelta::FromMinutes(1), 0,
169       static_cast<content::PageTransition>(
170           content::PAGE_TRANSITION_LINK |
171           content::PAGE_TRANSITION_CHAIN_START |
172           content::PAGE_TRANSITION_CHAIN_END),
173       0);
174   visit_info1.visit_id = 1;
175
176   // Add second visit for the same page.
177   VisitRow visit_info2(visit_info1.url_id,
178       visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
179       static_cast<content::PageTransition>(
180           content::PAGE_TRANSITION_TYPED |
181           content::PAGE_TRANSITION_CHAIN_START |
182           content::PAGE_TRANSITION_CHAIN_END),
183       0);
184   visit_info2.visit_id = 2;
185
186   // Add third visit for a different page.
187   VisitRow visit_info3(2,
188       visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
189       static_cast<content::PageTransition>(
190           content::PAGE_TRANSITION_LINK |
191           content::PAGE_TRANSITION_CHAIN_START),
192       0);
193   visit_info3.visit_id = 3;
194
195   // Add a redirect visit from the last page.
196   VisitRow visit_info4(3,
197       visit_info1.visit_time + TimeDelta::FromSeconds(3), visit_info3.visit_id,
198       static_cast<content::PageTransition>(
199           content::PAGE_TRANSITION_SERVER_REDIRECT |
200           content::PAGE_TRANSITION_CHAIN_END),
201       0);
202   visit_info4.visit_id = 4;
203
204   // Add a subframe visit.
205   VisitRow visit_info5(4,
206       visit_info1.visit_time + TimeDelta::FromSeconds(4), visit_info4.visit_id,
207       static_cast<content::PageTransition>(
208           content::PAGE_TRANSITION_AUTO_SUBFRAME |
209           content::PAGE_TRANSITION_CHAIN_START |
210           content::PAGE_TRANSITION_CHAIN_END),
211       0);
212   visit_info5.visit_id = 5;
213
214   // Add third visit for the same URL as visit 1 and 2, but exactly a day
215   // later than visit 2.
216   VisitRow visit_info6(visit_info1.url_id,
217       visit_info2.visit_time + TimeDelta::FromDays(1), 1,
218       static_cast<content::PageTransition>(
219           content::PAGE_TRANSITION_TYPED |
220           content::PAGE_TRANSITION_CHAIN_START |
221           content::PAGE_TRANSITION_CHAIN_END),
222       0);
223   visit_info6.visit_id = 6;
224
225   std::vector<VisitRow> test_visit_rows;
226   test_visit_rows.push_back(visit_info1);
227   test_visit_rows.push_back(visit_info2);
228   test_visit_rows.push_back(visit_info3);
229   test_visit_rows.push_back(visit_info4);
230   test_visit_rows.push_back(visit_info5);
231   test_visit_rows.push_back(visit_info6);
232   return test_visit_rows;
233 }
234
235 }  // namespace
236
237 TEST_F(VisitDatabaseTest, GetVisitsForTimes) {
238   std::vector<VisitRow> test_visit_rows = GetTestVisitRows();
239
240   for (size_t i = 0; i < test_visit_rows.size(); ++i) {
241     EXPECT_TRUE(AddVisit(&test_visit_rows[i], SOURCE_BROWSED));
242   }
243
244   // Query the visits for all our times.  We should get all visits.
245   {
246     std::vector<base::Time> times;
247     for (size_t i = 0; i < test_visit_rows.size(); ++i) {
248       times.push_back(test_visit_rows[i].visit_time);
249     }
250     VisitVector results;
251     GetVisitsForTimes(times, &results);
252     EXPECT_EQ(test_visit_rows.size(), results.size());
253   }
254
255   // Query the visits for a single time.
256   for (size_t i = 0; i < test_visit_rows.size(); ++i) {
257     std::vector<base::Time> times;
258     times.push_back(test_visit_rows[i].visit_time);
259     VisitVector results;
260     GetVisitsForTimes(times, &results);
261     ASSERT_EQ(static_cast<size_t>(1), results.size());
262     EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[i]));
263   }
264 }
265
266 TEST_F(VisitDatabaseTest, GetAllVisitsInRange) {
267   std::vector<VisitRow> test_visit_rows = GetTestVisitRows();
268
269   for (size_t i = 0; i < test_visit_rows.size(); ++i) {
270     EXPECT_TRUE(AddVisit(&test_visit_rows[i], SOURCE_BROWSED));
271   }
272
273   // Query the visits for all time.  We should get all visits.
274   VisitVector results;
275   GetAllVisitsInRange(Time(), Time(), 0, &results);
276   ASSERT_EQ(test_visit_rows.size(), results.size());
277   for (size_t i = 0; i < test_visit_rows.size(); ++i) {
278     EXPECT_TRUE(IsVisitInfoEqual(results[i], test_visit_rows[i]));
279   }
280
281   // Query a time range and make sure beginning is inclusive and ending is
282   // exclusive.
283   GetAllVisitsInRange(test_visit_rows[1].visit_time,
284                       test_visit_rows[3].visit_time, 0,
285                       &results);
286   ASSERT_EQ(static_cast<size_t>(2), results.size());
287   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[1]));
288   EXPECT_TRUE(IsVisitInfoEqual(results[1], test_visit_rows[2]));
289
290   // Query for a max count and make sure we get only that number.
291   GetAllVisitsInRange(Time(), Time(), 1, &results);
292   ASSERT_EQ(static_cast<size_t>(1), results.size());
293   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[0]));
294 }
295
296 TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
297   std::vector<VisitRow> test_visit_rows = GetTestVisitRows();
298
299   for (size_t i = 0; i < test_visit_rows.size(); ++i) {
300     EXPECT_TRUE(AddVisit(&test_visit_rows[i], SOURCE_BROWSED));
301   }
302
303   // Query the visits for all time.  We should not get the first or the second
304   // visit (duplicates of the sixth) or the redirect or subframe visits.
305   VisitVector results;
306   QueryOptions options;
307   GetVisibleVisitsInRange(options, &results);
308   ASSERT_EQ(static_cast<size_t>(2), results.size());
309   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
310   EXPECT_TRUE(IsVisitInfoEqual(results[1], test_visit_rows[3]));
311
312   // Now try with only per-day de-duping -- the second visit should appear,
313   // since it's a duplicate of visit6 but on a different day.
314   options.duplicate_policy = QueryOptions::REMOVE_DUPLICATES_PER_DAY;
315   GetVisibleVisitsInRange(options, &results);
316   ASSERT_EQ(static_cast<size_t>(3), results.size());
317   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
318   EXPECT_TRUE(IsVisitInfoEqual(results[1], test_visit_rows[3]));
319   EXPECT_TRUE(IsVisitInfoEqual(results[2], test_visit_rows[1]));
320
321   // Now try without de-duping, expect to see all visible visits.
322   options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
323   GetVisibleVisitsInRange(options, &results);
324   ASSERT_EQ(static_cast<size_t>(4), results.size());
325   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
326   EXPECT_TRUE(IsVisitInfoEqual(results[1], test_visit_rows[3]));
327   EXPECT_TRUE(IsVisitInfoEqual(results[2], test_visit_rows[1]));
328   EXPECT_TRUE(IsVisitInfoEqual(results[3], test_visit_rows[0]));
329
330   // Set the end time to exclude the second visit. The first visit should be
331   // returned. Even though the second is a more recent visit, it's not in the
332   // query range.
333   options.end_time = test_visit_rows[1].visit_time;
334   GetVisibleVisitsInRange(options, &results);
335   ASSERT_EQ(static_cast<size_t>(1), results.size());
336   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[0]));
337
338   options = QueryOptions();  // Reset to options to default.
339
340   // Query for a max count and make sure we get only that number.
341   options.max_count = 1;
342   GetVisibleVisitsInRange(options, &results);
343   ASSERT_EQ(static_cast<size_t>(1), results.size());
344   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
345
346   // Query a time range and make sure beginning is inclusive and ending is
347   // exclusive.
348   options.begin_time = test_visit_rows[1].visit_time;
349   options.end_time = test_visit_rows[3].visit_time;
350   options.max_count = 0;
351   GetVisibleVisitsInRange(options, &results);
352   ASSERT_EQ(static_cast<size_t>(1), results.size());
353   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[1]));
354 }
355
356 TEST_F(VisitDatabaseTest, VisitSource) {
357   // Add visits.
358   VisitRow visit_info1(111, Time::Now(), 0, content::PAGE_TRANSITION_LINK, 0);
359   ASSERT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
360
361   VisitRow visit_info2(112, Time::Now(), 1, content::PAGE_TRANSITION_TYPED, 0);
362   ASSERT_TRUE(AddVisit(&visit_info2, SOURCE_SYNCED));
363
364   VisitRow visit_info3(113, Time::Now(), 0, content::PAGE_TRANSITION_TYPED, 0);
365   ASSERT_TRUE(AddVisit(&visit_info3, SOURCE_EXTENSION));
366
367   // Query each visit.
368   std::vector<VisitRow> matches;
369   ASSERT_TRUE(GetVisitsForURL(111, &matches));
370   ASSERT_EQ(1U, matches.size());
371   VisitSourceMap sources;
372   GetVisitsSource(matches, &sources);
373   EXPECT_EQ(0U, sources.size());
374
375   ASSERT_TRUE(GetVisitsForURL(112, &matches));
376   ASSERT_EQ(1U, matches.size());
377   GetVisitsSource(matches, &sources);
378   ASSERT_EQ(1U, sources.size());
379   EXPECT_EQ(SOURCE_SYNCED, sources[matches[0].visit_id]);
380
381   ASSERT_TRUE(GetVisitsForURL(113, &matches));
382   ASSERT_EQ(1U, matches.size());
383   GetVisitsSource(matches, &sources);
384   ASSERT_EQ(1U, sources.size());
385   EXPECT_EQ(SOURCE_EXTENSION, sources[matches[0].visit_id]);
386 }
387
388 TEST_F(VisitDatabaseTest, GetVisibleVisitsForURL) {
389   std::vector<VisitRow> test_visit_rows = GetTestVisitRows();
390
391   for (size_t i = 0; i < test_visit_rows.size(); ++i) {
392     EXPECT_TRUE(AddVisit(&test_visit_rows[i], SOURCE_BROWSED));
393   }
394
395   // Query the visits for the first url id.  We should not get the first or the
396   // second visit (duplicates of the sixth) or any other urls, redirects or
397   // subframe visits.
398   VisitVector results;
399   QueryOptions options;
400   int url_id = test_visit_rows[0].url_id;
401   GetVisibleVisitsForURL(url_id, options, &results);
402   ASSERT_EQ(static_cast<size_t>(1), results.size());
403   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
404
405   // Now try with only per-day de-duping -- the second visit should appear,
406   // since it's a duplicate of visit6 but on a different day.
407   options.duplicate_policy = QueryOptions::REMOVE_DUPLICATES_PER_DAY;
408   GetVisibleVisitsForURL(url_id, options, &results);
409   ASSERT_EQ(static_cast<size_t>(2), results.size());
410   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
411   EXPECT_TRUE(IsVisitInfoEqual(results[1], test_visit_rows[1]));
412
413   // Now try without de-duping, expect to see all visible visits to url id 1.
414   options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
415   GetVisibleVisitsForURL(url_id, options, &results);
416   ASSERT_EQ(static_cast<size_t>(3), results.size());
417   EXPECT_TRUE(IsVisitInfoEqual(results[0], test_visit_rows[5]));
418   EXPECT_TRUE(IsVisitInfoEqual(results[1], test_visit_rows[1]));
419   EXPECT_TRUE(IsVisitInfoEqual(results[2], test_visit_rows[0]));
420 }
421
422 }  // namespace history