Home | History | Annotate | Download | only in history
      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/path_service.h"
      9 #include "base/string_util.h"
     10 #include "base/memory/scoped_temp_dir.h"
     11 #include "chrome/browser/history/url_database.h"
     12 #include "chrome/browser/history/visit_database.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "testing/platform_test.h"
     15 
     16 using base::Time;
     17 using base::TimeDelta;
     18 
     19 namespace history {
     20 
     21 namespace {
     22 
     23 bool IsVisitInfoEqual(const VisitRow& a,
     24                       const VisitRow& b) {
     25   return a.visit_id == b.visit_id &&
     26          a.url_id == b.url_id &&
     27          a.visit_time == b.visit_time &&
     28          a.referring_visit == b.referring_visit &&
     29          a.transition == b.transition &&
     30          a.is_indexed == b.is_indexed;
     31 }
     32 
     33 }  // namespace
     34 
     35 class VisitDatabaseTest : public PlatformTest,
     36                           public URLDatabase,
     37                           public VisitDatabase {
     38  public:
     39   VisitDatabaseTest() {
     40   }
     41 
     42  private:
     43   // Test setup.
     44   void SetUp() {
     45     PlatformTest::SetUp();
     46     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     47     FilePath db_file = temp_dir_.path().AppendASCII("VisitTest.db");
     48 
     49     EXPECT_TRUE(db_.Open(db_file));
     50 
     51     // Initialize the tables for this test.
     52     CreateURLTable(false);
     53     CreateMainURLIndex();
     54     InitVisitTable();
     55   }
     56   void TearDown() {
     57     db_.Close();
     58     PlatformTest::TearDown();
     59   }
     60 
     61   // Provided for URL/VisitDatabase.
     62   virtual sql::Connection& GetDB() {
     63     return db_;
     64   }
     65 
     66   ScopedTempDir temp_dir_;
     67   sql::Connection db_;
     68 };
     69 
     70 TEST_F(VisitDatabaseTest, Add) {
     71   // Add one visit.
     72   VisitRow visit_info1(1, Time::Now(), 0, PageTransition::LINK, 0);
     73   EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
     74 
     75   // Add second visit for the same page.
     76   VisitRow visit_info2(visit_info1.url_id,
     77       visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
     78       PageTransition::TYPED, 0);
     79   EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
     80 
     81   // Add third visit for a different page.
     82   VisitRow visit_info3(2,
     83       visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
     84       PageTransition::LINK, 0);
     85   EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
     86 
     87   // Query the first two.
     88   std::vector<VisitRow> matches;
     89   EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches));
     90   EXPECT_EQ(static_cast<size_t>(2), matches.size());
     91 
     92   // Make sure we got both (order in result set is visit time).
     93   EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) &&
     94               IsVisitInfoEqual(matches[1], visit_info2));
     95 }
     96 
     97 TEST_F(VisitDatabaseTest, Delete) {
     98   // Add three visits that form a chain of navigation, and then delete the
     99   // middle one. We should be left with the outer two visits, and the chain
    100   // should link them.
    101   static const int kTime1 = 1000;
    102   VisitRow visit_info1(1, Time::FromInternalValue(kTime1), 0,
    103                        PageTransition::LINK, 0);
    104   EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
    105 
    106   static const int kTime2 = kTime1 + 1;
    107   VisitRow visit_info2(1, Time::FromInternalValue(kTime2),
    108                        visit_info1.visit_id, PageTransition::LINK, 0);
    109   EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
    110 
    111   static const int kTime3 = kTime2 + 1;
    112   VisitRow visit_info3(1, Time::FromInternalValue(kTime3),
    113                        visit_info2.visit_id, PageTransition::LINK, 0);
    114   EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
    115 
    116   // First make sure all the visits are there.
    117   std::vector<VisitRow> matches;
    118   EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches));
    119   EXPECT_EQ(static_cast<size_t>(3), matches.size());
    120   EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) &&
    121               IsVisitInfoEqual(matches[1], visit_info2) &&
    122               IsVisitInfoEqual(matches[2], visit_info3));
    123 
    124   // Delete the middle one.
    125   DeleteVisit(visit_info2);
    126 
    127   // The outer two should be left, and the last one should have the first as
    128   // the referrer.
    129   visit_info3.referring_visit = visit_info1.visit_id;
    130   matches.clear();
    131   EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches));
    132   EXPECT_EQ(static_cast<size_t>(2), matches.size());
    133   EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) &&
    134               IsVisitInfoEqual(matches[1], visit_info3));
    135 }
    136 
    137 TEST_F(VisitDatabaseTest, Update) {
    138   // Make something in the database.
    139   VisitRow original(1, Time::Now(), 23, 22, 19);
    140   AddVisit(&original, SOURCE_BROWSED);
    141 
    142   // Mutate that row.
    143   VisitRow modification(original);
    144   modification.url_id = 2;
    145   modification.transition = PageTransition::TYPED;
    146   modification.visit_time = Time::Now() + TimeDelta::FromDays(1);
    147   modification.referring_visit = 9292;
    148   modification.is_indexed = true;
    149   UpdateVisitRow(modification);
    150 
    151   // Check that the mutated version was written.
    152   VisitRow final;
    153   GetRowForVisit(original.visit_id, &final);
    154   EXPECT_TRUE(IsVisitInfoEqual(modification, final));
    155 }
    156 
    157 // TODO(brettw) write test for GetMostRecentVisitForURL!
    158 
    159 TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
    160   // Add one visit.
    161   VisitRow visit_info1(1, Time::Now(), 0,
    162       static_cast<PageTransition::Type>(PageTransition::LINK |
    163                                         PageTransition::CHAIN_START |
    164                                         PageTransition::CHAIN_END),
    165       0);
    166   visit_info1.visit_id = 1;
    167   EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
    168 
    169   // Add second visit for the same page.
    170   VisitRow visit_info2(visit_info1.url_id,
    171       visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
    172       static_cast<PageTransition::Type>(PageTransition::TYPED |
    173                                         PageTransition::CHAIN_START |
    174                                         PageTransition::CHAIN_END),
    175       0);
    176   visit_info2.visit_id = 2;
    177   EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
    178 
    179   // Add third visit for a different page.
    180   VisitRow visit_info3(2,
    181       visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
    182       static_cast<PageTransition::Type>(PageTransition::LINK |
    183                                         PageTransition::CHAIN_START),
    184       0);
    185   visit_info3.visit_id = 3;
    186   EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
    187 
    188   // Add a redirect visit from the last page.
    189   VisitRow visit_info4(3,
    190       visit_info1.visit_time + TimeDelta::FromSeconds(3), visit_info3.visit_id,
    191       static_cast<PageTransition::Type>(PageTransition::SERVER_REDIRECT |
    192                                         PageTransition::CHAIN_END),
    193       0);
    194   visit_info4.visit_id = 4;
    195   EXPECT_TRUE(AddVisit(&visit_info4, SOURCE_BROWSED));
    196 
    197   // Add a subframe visit.
    198   VisitRow visit_info5(4,
    199       visit_info1.visit_time + TimeDelta::FromSeconds(4), visit_info4.visit_id,
    200       static_cast<PageTransition::Type>(PageTransition::AUTO_SUBFRAME |
    201                                         PageTransition::CHAIN_START |
    202                                         PageTransition::CHAIN_END),
    203       0);
    204   visit_info5.visit_id = 5;
    205   EXPECT_TRUE(AddVisit(&visit_info5, SOURCE_BROWSED));
    206 
    207   // Query the visits for all time, we should not get the first (duplicate of
    208   // the second) or the redirect or subframe visits.
    209   VisitVector results;
    210   GetVisibleVisitsInRange(Time(), Time(), 0, &results);
    211   ASSERT_EQ(static_cast<size_t>(2), results.size());
    212   EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info4) &&
    213               IsVisitInfoEqual(results[1], visit_info2));
    214 
    215   // Query a time range and make sure beginning is inclusive and ending is
    216   // exclusive.
    217   GetVisibleVisitsInRange(visit_info2.visit_time, visit_info4.visit_time, 0,
    218                           &results);
    219   ASSERT_EQ(static_cast<size_t>(1), results.size());
    220   EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info2));
    221 
    222   // Query for a max count and make sure we get only that number.
    223   GetVisibleVisitsInRange(Time(), Time(), 1, &results);
    224   ASSERT_EQ(static_cast<size_t>(1), results.size());
    225   EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info4));
    226 }
    227 
    228 TEST_F(VisitDatabaseTest, VisitSource) {
    229   // Add visits.
    230   VisitRow visit_info1(111, Time::Now(), 0, PageTransition::LINK, 0);
    231   ASSERT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
    232 
    233   VisitRow visit_info2(112, Time::Now(), 1, PageTransition::TYPED, 0);
    234   ASSERT_TRUE(AddVisit(&visit_info2, SOURCE_SYNCED));
    235 
    236   VisitRow visit_info3(113, Time::Now(), 0, PageTransition::TYPED, 0);
    237   ASSERT_TRUE(AddVisit(&visit_info3, SOURCE_EXTENSION));
    238 
    239   // Query each visit.
    240   std::vector<VisitRow> matches;
    241   ASSERT_TRUE(GetVisitsForURL(111, &matches));
    242   ASSERT_EQ(1U, matches.size());
    243   VisitSourceMap sources;
    244   GetVisitsSource(matches, &sources);
    245   EXPECT_EQ(0U, sources.size());
    246 
    247   ASSERT_TRUE(GetVisitsForURL(112, &matches));
    248   ASSERT_EQ(1U, matches.size());
    249   GetVisitsSource(matches, &sources);
    250   ASSERT_EQ(1U, sources.size());
    251   EXPECT_EQ(SOURCE_SYNCED, sources[matches[0].visit_id]);
    252 
    253   ASSERT_TRUE(GetVisitsForURL(113, &matches));
    254   ASSERT_EQ(1U, matches.size());
    255   GetVisitsSource(matches, &sources);
    256   ASSERT_EQ(1U, sources.size());
    257   EXPECT_EQ(SOURCE_EXTENSION, sources[matches[0].visit_id]);
    258 }
    259 
    260 }  // namespace history
    261