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