| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "app/sql/connection.h" |
| #include "base/file_path.h" |
| #include "base/file_util.h" |
| #include "base/path_service.h" |
| #include "base/string_util.h" |
| #include "base/memory/scoped_temp_dir.h" |
| #include "chrome/browser/history/url_database.h" |
| #include "chrome/browser/history/visit_database.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| |
| using base::Time; |
| using base::TimeDelta; |
| |
| namespace history { |
| |
| namespace { |
| |
| bool IsVisitInfoEqual(const VisitRow& a, |
| const VisitRow& b) { |
| return a.visit_id == b.visit_id && |
| a.url_id == b.url_id && |
| a.visit_time == b.visit_time && |
| a.referring_visit == b.referring_visit && |
| a.transition == b.transition && |
| a.is_indexed == b.is_indexed; |
| } |
| |
| } // namespace |
| |
| class VisitDatabaseTest : public PlatformTest, |
| public URLDatabase, |
| public VisitDatabase { |
| public: |
| VisitDatabaseTest() { |
| } |
| |
| private: |
| // Test setup. |
| void SetUp() { |
| PlatformTest::SetUp(); |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| FilePath db_file = temp_dir_.path().AppendASCII("VisitTest.db"); |
| |
| EXPECT_TRUE(db_.Open(db_file)); |
| |
| // Initialize the tables for this test. |
| CreateURLTable(false); |
| CreateMainURLIndex(); |
| InitVisitTable(); |
| } |
| void TearDown() { |
| db_.Close(); |
| PlatformTest::TearDown(); |
| } |
| |
| // Provided for URL/VisitDatabase. |
| virtual sql::Connection& GetDB() { |
| return db_; |
| } |
| |
| ScopedTempDir temp_dir_; |
| sql::Connection db_; |
| }; |
| |
| TEST_F(VisitDatabaseTest, Add) { |
| // Add one visit. |
| VisitRow visit_info1(1, Time::Now(), 0, PageTransition::LINK, 0); |
| EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED)); |
| |
| // Add second visit for the same page. |
| VisitRow visit_info2(visit_info1.url_id, |
| visit_info1.visit_time + TimeDelta::FromSeconds(1), 1, |
| PageTransition::TYPED, 0); |
| EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED)); |
| |
| // Add third visit for a different page. |
| VisitRow visit_info3(2, |
| visit_info1.visit_time + TimeDelta::FromSeconds(2), 0, |
| PageTransition::LINK, 0); |
| EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED)); |
| |
| // Query the first two. |
| std::vector<VisitRow> matches; |
| EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches)); |
| EXPECT_EQ(static_cast<size_t>(2), matches.size()); |
| |
| // Make sure we got both (order in result set is visit time). |
| EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) && |
| IsVisitInfoEqual(matches[1], visit_info2)); |
| } |
| |
| TEST_F(VisitDatabaseTest, Delete) { |
| // Add three visits that form a chain of navigation, and then delete the |
| // middle one. We should be left with the outer two visits, and the chain |
| // should link them. |
| static const int kTime1 = 1000; |
| VisitRow visit_info1(1, Time::FromInternalValue(kTime1), 0, |
| PageTransition::LINK, 0); |
| EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED)); |
| |
| static const int kTime2 = kTime1 + 1; |
| VisitRow visit_info2(1, Time::FromInternalValue(kTime2), |
| visit_info1.visit_id, PageTransition::LINK, 0); |
| EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED)); |
| |
| static const int kTime3 = kTime2 + 1; |
| VisitRow visit_info3(1, Time::FromInternalValue(kTime3), |
| visit_info2.visit_id, PageTransition::LINK, 0); |
| EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED)); |
| |
| // First make sure all the visits are there. |
| std::vector<VisitRow> matches; |
| EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches)); |
| EXPECT_EQ(static_cast<size_t>(3), matches.size()); |
| EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) && |
| IsVisitInfoEqual(matches[1], visit_info2) && |
| IsVisitInfoEqual(matches[2], visit_info3)); |
| |
| // Delete the middle one. |
| DeleteVisit(visit_info2); |
| |
| // The outer two should be left, and the last one should have the first as |
| // the referrer. |
| visit_info3.referring_visit = visit_info1.visit_id; |
| matches.clear(); |
| EXPECT_TRUE(GetVisitsForURL(visit_info1.url_id, &matches)); |
| EXPECT_EQ(static_cast<size_t>(2), matches.size()); |
| EXPECT_TRUE(IsVisitInfoEqual(matches[0], visit_info1) && |
| IsVisitInfoEqual(matches[1], visit_info3)); |
| } |
| |
| TEST_F(VisitDatabaseTest, Update) { |
| // Make something in the database. |
| VisitRow original(1, Time::Now(), 23, 22, 19); |
| AddVisit(&original, SOURCE_BROWSED); |
| |
| // Mutate that row. |
| VisitRow modification(original); |
| modification.url_id = 2; |
| modification.transition = PageTransition::TYPED; |
| modification.visit_time = Time::Now() + TimeDelta::FromDays(1); |
| modification.referring_visit = 9292; |
| modification.is_indexed = true; |
| UpdateVisitRow(modification); |
| |
| // Check that the mutated version was written. |
| VisitRow final; |
| GetRowForVisit(original.visit_id, &final); |
| EXPECT_TRUE(IsVisitInfoEqual(modification, final)); |
| } |
| |
| // TODO(brettw) write test for GetMostRecentVisitForURL! |
| |
| TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) { |
| // Add one visit. |
| VisitRow visit_info1(1, Time::Now(), 0, |
| static_cast<PageTransition::Type>(PageTransition::LINK | |
| PageTransition::CHAIN_START | |
| PageTransition::CHAIN_END), |
| 0); |
| visit_info1.visit_id = 1; |
| EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED)); |
| |
| // Add second visit for the same page. |
| VisitRow visit_info2(visit_info1.url_id, |
| visit_info1.visit_time + TimeDelta::FromSeconds(1), 1, |
| static_cast<PageTransition::Type>(PageTransition::TYPED | |
| PageTransition::CHAIN_START | |
| PageTransition::CHAIN_END), |
| 0); |
| visit_info2.visit_id = 2; |
| EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED)); |
| |
| // Add third visit for a different page. |
| VisitRow visit_info3(2, |
| visit_info1.visit_time + TimeDelta::FromSeconds(2), 0, |
| static_cast<PageTransition::Type>(PageTransition::LINK | |
| PageTransition::CHAIN_START), |
| 0); |
| visit_info3.visit_id = 3; |
| EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED)); |
| |
| // Add a redirect visit from the last page. |
| VisitRow visit_info4(3, |
| visit_info1.visit_time + TimeDelta::FromSeconds(3), visit_info3.visit_id, |
| static_cast<PageTransition::Type>(PageTransition::SERVER_REDIRECT | |
| PageTransition::CHAIN_END), |
| 0); |
| visit_info4.visit_id = 4; |
| EXPECT_TRUE(AddVisit(&visit_info4, SOURCE_BROWSED)); |
| |
| // Add a subframe visit. |
| VisitRow visit_info5(4, |
| visit_info1.visit_time + TimeDelta::FromSeconds(4), visit_info4.visit_id, |
| static_cast<PageTransition::Type>(PageTransition::AUTO_SUBFRAME | |
| PageTransition::CHAIN_START | |
| PageTransition::CHAIN_END), |
| 0); |
| visit_info5.visit_id = 5; |
| EXPECT_TRUE(AddVisit(&visit_info5, SOURCE_BROWSED)); |
| |
| // Query the visits for all time, we should not get the first (duplicate of |
| // the second) or the redirect or subframe visits. |
| VisitVector results; |
| GetVisibleVisitsInRange(Time(), Time(), 0, &results); |
| ASSERT_EQ(static_cast<size_t>(2), results.size()); |
| EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info4) && |
| IsVisitInfoEqual(results[1], visit_info2)); |
| |
| // Query a time range and make sure beginning is inclusive and ending is |
| // exclusive. |
| GetVisibleVisitsInRange(visit_info2.visit_time, visit_info4.visit_time, 0, |
| &results); |
| ASSERT_EQ(static_cast<size_t>(1), results.size()); |
| EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info2)); |
| |
| // Query for a max count and make sure we get only that number. |
| GetVisibleVisitsInRange(Time(), Time(), 1, &results); |
| ASSERT_EQ(static_cast<size_t>(1), results.size()); |
| EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info4)); |
| } |
| |
| TEST_F(VisitDatabaseTest, VisitSource) { |
| // Add visits. |
| VisitRow visit_info1(111, Time::Now(), 0, PageTransition::LINK, 0); |
| ASSERT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED)); |
| |
| VisitRow visit_info2(112, Time::Now(), 1, PageTransition::TYPED, 0); |
| ASSERT_TRUE(AddVisit(&visit_info2, SOURCE_SYNCED)); |
| |
| VisitRow visit_info3(113, Time::Now(), 0, PageTransition::TYPED, 0); |
| ASSERT_TRUE(AddVisit(&visit_info3, SOURCE_EXTENSION)); |
| |
| // Query each visit. |
| std::vector<VisitRow> matches; |
| ASSERT_TRUE(GetVisitsForURL(111, &matches)); |
| ASSERT_EQ(1U, matches.size()); |
| VisitSourceMap sources; |
| GetVisitsSource(matches, &sources); |
| EXPECT_EQ(0U, sources.size()); |
| |
| ASSERT_TRUE(GetVisitsForURL(112, &matches)); |
| ASSERT_EQ(1U, matches.size()); |
| GetVisitsSource(matches, &sources); |
| ASSERT_EQ(1U, sources.size()); |
| EXPECT_EQ(SOURCE_SYNCED, sources[matches[0].visit_id]); |
| |
| ASSERT_TRUE(GetVisitsForURL(113, &matches)); |
| ASSERT_EQ(1U, matches.size()); |
| GetVisitsSource(matches, &sources); |
| ASSERT_EQ(1U, sources.size()); |
| EXPECT_EQ(SOURCE_EXTENSION, sources[matches[0].visit_id]); |
| } |
| |
| } // namespace history |