summaryrefslogtreecommitdiffstats
path: root/components/history
diff options
context:
space:
mode:
authorblundell <blundell@chromium.org>2015-10-26 01:12:55 -0700
committerCommit bot <commit-bot@chromium.org>2015-10-26 08:14:06 +0000
commitb458c69d81cceaafce4fde649f19e01b22759595 (patch)
tree725d475400f022f8f50ae68a4e182689bc40b097 /components/history
parentefafc6b60a513935f821512b9ad132b0c9a3f83b (diff)
downloadchromium_src-b458c69d81cceaafce4fde649f19e01b22759595.zip
chromium_src-b458c69d81cceaafce4fde649f19e01b22759595.tar.gz
chromium_src-b458c69d81cceaafce4fde649f19e01b22759595.tar.bz2
[sync] Componentize TypedUrlModelAssociator unittest
content::TestBrowserThreadBundle dependency is removed by manually spinning up a base::Thread instance instead. BUG=544975 Review URL: https://codereview.chromium.org/1416623002 Cr-Commit-Position: refs/heads/master@{#356020}
Diffstat (limited to 'components/history')
-rw-r--r--components/history/core/browser/BUILD.gn2
-rw-r--r--components/history/core/browser/typed_url_model_associator_unittest.cc432
2 files changed, 434 insertions, 0 deletions
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index a3f8216..e78b34e 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -150,6 +150,7 @@ source_set("unit_tests") {
"top_sites_cache_unittest.cc",
"top_sites_database_unittest.cc",
"top_sites_impl_unittest.cc",
+ "typed_url_model_associator_unittest.cc",
"typed_url_syncable_service_unittest.cc",
"url_database_unittest.cc",
"url_utils_unittest.cc",
@@ -165,6 +166,7 @@ source_set("unit_tests") {
"//components/favicon_base",
"//components/history/core/common",
"//components/history/core/test",
+ "//components/sync_driver:test_support",
"//sql",
"//sql:test_support",
"//sync:test_support_sync_api",
diff --git a/components/history/core/browser/typed_url_model_associator_unittest.cc b/components/history/core/browser/typed_url_model_associator_unittest.cc
new file mode 100644
index 0000000..ab8fec4
--- /dev/null
+++ b/components/history/core/browser/typed_url_model_associator_unittest.cc
@@ -0,0 +1,432 @@
+// Copyright (c) 2012 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 "base/basictypes.h"
+#include "base/bind.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/history/core/browser/typed_url_model_associator.h"
+#include "components/sync_driver/fake_sync_service.h"
+#include "sync/protocol/typed_url_specifics.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using browser_sync::TypedUrlModelAssociator;
+
+namespace {
+class SyncTypedUrlModelAssociatorTest : public testing::Test {
+ public:
+ static history::URLRow MakeTypedUrlRow(const char* url,
+ const char* title,
+ int typed_count,
+ int64 last_visit,
+ bool hidden,
+ history::VisitVector* visits) {
+ GURL gurl(url);
+ history::URLRow history_url(gurl);
+ history_url.set_title(base::UTF8ToUTF16(title));
+ history_url.set_typed_count(typed_count);
+ history_url.set_last_visit(
+ base::Time::FromInternalValue(last_visit));
+ history_url.set_hidden(hidden);
+ visits->push_back(history::VisitRow(
+ history_url.id(), history_url.last_visit(), 0,
+ ui::PAGE_TRANSITION_RELOAD, 0));
+ history_url.set_visit_count(visits->size());
+ return history_url;
+ }
+
+ static sync_pb::TypedUrlSpecifics MakeTypedUrlSpecifics(const char* url,
+ const char* title,
+ int64 last_visit,
+ bool hidden) {
+ sync_pb::TypedUrlSpecifics typed_url;
+ typed_url.set_url(url);
+ typed_url.set_title(title);
+ typed_url.set_hidden(hidden);
+ typed_url.add_visits(last_visit);
+ typed_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ return typed_url;
+ }
+
+ static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
+ // Only compare synced fields (ignore typed_count and visit_count as those
+ // are maintained by the history subsystem).
+ return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
+ (lhs.title().compare(rhs.title()) == 0) &&
+ (lhs.hidden() == rhs.hidden());
+ }
+};
+
+static void CreateModelAssociatorAsync(base::WaitableEvent* startup,
+ base::WaitableEvent* aborted,
+ base::WaitableEvent* done,
+ TypedUrlModelAssociator** associator,
+ sync_driver::SyncService* service) {
+ // Grab the done lock - when we exit, this will be released and allow the
+ // test to finish.
+ *associator = new TypedUrlModelAssociator(service, NULL, NULL);
+
+ // Signal frontend to call AbortAssociation and proceed after it's called.
+ startup->Signal();
+ aborted->Wait();
+ syncer::SyncError error = (*associator)->AssociateModels(NULL, NULL);
+ EXPECT_TRUE(error.IsSet());
+ EXPECT_EQ("Association was aborted.", error.message());
+ delete *associator;
+ done->Signal();
+}
+
+} // namespace
+
+TEST_F(SyncTypedUrlModelAssociatorTest, MergeUrls) {
+ history::VisitVector visits1;
+ history::URLRow row1(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, false, &visits1));
+ sync_pb::TypedUrlSpecifics specs1(MakeTypedUrlSpecifics("http://pie.com/",
+ "pie",
+ 3, false));
+ history::URLRow new_row1(GURL("http://pie.com/"));
+ std::vector<history::VisitInfo> new_visits1;
+ EXPECT_TRUE(TypedUrlModelAssociator::MergeUrls(specs1, row1, &visits1,
+ &new_row1, &new_visits1) == TypedUrlModelAssociator::DIFF_NONE);
+
+ history::VisitVector visits2;
+ history::URLRow row2(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, false, &visits2));
+ sync_pb::TypedUrlSpecifics specs2(MakeTypedUrlSpecifics("http://pie.com/",
+ "pie",
+ 3, true));
+ history::VisitVector expected_visits2;
+ history::URLRow expected2(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, true, &expected_visits2));
+ history::URLRow new_row2(GURL("http://pie.com/"));
+ std::vector<history::VisitInfo> new_visits2;
+ EXPECT_TRUE(TypedUrlModelAssociator::MergeUrls(specs2, row2, &visits2,
+ &new_row2, &new_visits2) ==
+ TypedUrlModelAssociator::DIFF_LOCAL_ROW_CHANGED);
+ EXPECT_TRUE(URLsEqual(new_row2, expected2));
+
+ history::VisitVector visits3;
+ history::URLRow row3(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, false, &visits3));
+ sync_pb::TypedUrlSpecifics specs3(MakeTypedUrlSpecifics("http://pie.com/",
+ "pie2",
+ 3, true));
+ history::VisitVector expected_visits3;
+ history::URLRow expected3(MakeTypedUrlRow("http://pie.com/", "pie2",
+ 2, 3, true, &expected_visits3));
+ history::URLRow new_row3(GURL("http://pie.com/"));
+ std::vector<history::VisitInfo> new_visits3;
+ EXPECT_EQ(TypedUrlModelAssociator::DIFF_LOCAL_ROW_CHANGED |
+ TypedUrlModelAssociator::DIFF_NONE,
+ TypedUrlModelAssociator::MergeUrls(specs3, row3, &visits3,
+ &new_row3, &new_visits3));
+ EXPECT_TRUE(URLsEqual(new_row3, expected3));
+
+ // Create one node in history DB with timestamp of 3, and one node in sync
+ // DB with timestamp of 4. Result should contain one new item (4).
+ history::VisitVector visits4;
+ history::URLRow row4(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, false, &visits4));
+ sync_pb::TypedUrlSpecifics specs4(MakeTypedUrlSpecifics("http://pie.com/",
+ "pie2",
+ 4, false));
+ history::VisitVector expected_visits4;
+ history::URLRow expected4(MakeTypedUrlRow("http://pie.com/", "pie2",
+ 2, 4, false, &expected_visits4));
+ history::URLRow new_row4(GURL("http://pie.com/"));
+ std::vector<history::VisitInfo> new_visits4;
+ EXPECT_EQ(TypedUrlModelAssociator::DIFF_UPDATE_NODE |
+ TypedUrlModelAssociator::DIFF_LOCAL_ROW_CHANGED |
+ TypedUrlModelAssociator::DIFF_LOCAL_VISITS_ADDED,
+ TypedUrlModelAssociator::MergeUrls(specs4, row4, &visits4,
+ &new_row4, &new_visits4));
+ EXPECT_EQ(1U, new_visits4.size());
+ EXPECT_EQ(specs4.visits(0), new_visits4[0].first.ToInternalValue());
+ EXPECT_TRUE(URLsEqual(new_row4, expected4));
+ EXPECT_EQ(2U, visits4.size());
+
+ history::VisitVector visits5;
+ history::URLRow row5(MakeTypedUrlRow("http://pie.com/", "pie",
+ 1, 4, false, &visits5));
+ sync_pb::TypedUrlSpecifics specs5(MakeTypedUrlSpecifics("http://pie.com/",
+ "pie",
+ 3, false));
+ history::VisitVector expected_visits5;
+ history::URLRow expected5(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, false, &expected_visits5));
+ history::URLRow new_row5(GURL("http://pie.com/"));
+ std::vector<history::VisitInfo> new_visits5;
+
+ // UPDATE_NODE should be set because row5 has a newer last_visit timestamp.
+ EXPECT_EQ(TypedUrlModelAssociator::DIFF_UPDATE_NODE |
+ TypedUrlModelAssociator::DIFF_NONE,
+ TypedUrlModelAssociator::MergeUrls(specs5, row5, &visits5,
+ &new_row5, &new_visits5));
+ EXPECT_TRUE(URLsEqual(new_row5, expected5));
+ EXPECT_EQ(0U, new_visits5.size());
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, MergeUrlsAfterExpiration) {
+ // Tests to ensure that we don't resurrect expired URLs (URLs that have been
+ // deleted from the history DB but still exist in the sync DB).
+
+ // First, create a history row that has two visits, with timestamps 2 and 3.
+ history::VisitVector(history_visits);
+ history_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(2), 0, ui::PAGE_TRANSITION_TYPED,
+ 0));
+ history::URLRow history_url(MakeTypedUrlRow("http://pie.com/", "pie",
+ 2, 3, false, &history_visits));
+
+ // Now, create a sync node with visits at timestamps 1, 2, 3, 4.
+ sync_pb::TypedUrlSpecifics node(MakeTypedUrlSpecifics("http://pie.com/",
+ "pie", 1, false));
+ node.add_visits(2);
+ node.add_visits(3);
+ node.add_visits(4);
+ node.add_visit_transitions(2);
+ node.add_visit_transitions(3);
+ node.add_visit_transitions(4);
+ history::URLRow new_history_url(history_url.url());
+ std::vector<history::VisitInfo> new_visits;
+ EXPECT_EQ(TypedUrlModelAssociator::DIFF_NONE |
+ TypedUrlModelAssociator::DIFF_LOCAL_VISITS_ADDED,
+ TypedUrlModelAssociator::MergeUrls(
+ node, history_url, &history_visits, &new_history_url,
+ &new_visits));
+ EXPECT_TRUE(URLsEqual(history_url, new_history_url));
+ EXPECT_EQ(1U, new_visits.size());
+ EXPECT_EQ(4U, new_visits[0].first.ToInternalValue());
+ // We should not sync the visit with timestamp #1 since it is earlier than
+ // any other visit for this URL in the history DB. But we should sync visit
+ // #4.
+ EXPECT_EQ(3U, history_visits.size());
+ EXPECT_EQ(2U, history_visits[0].visit_time.ToInternalValue());
+ EXPECT_EQ(3U, history_visits[1].visit_time.ToInternalValue());
+ EXPECT_EQ(4U, history_visits[2].visit_time.ToInternalValue());
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, DiffVisitsSame) {
+ history::VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64 visits[] = { 1024, 2065, 65534, 1237684 };
+
+ for (size_t c = 0; c < arraysize(visits); ++c) {
+ old_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(visits[c]), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ new_url.add_visits(visits[c]);
+ new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ }
+
+ std::vector<history::VisitInfo> new_visits;
+ history::VisitVector removed_visits;
+
+ TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
+ &new_visits, &removed_visits);
+ EXPECT_TRUE(new_visits.empty());
+ EXPECT_TRUE(removed_visits.empty());
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, DiffVisitsRemove) {
+ history::VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64 visits_left[] = { 1, 2, 1024, 1500, 2065, 6000,
+ 65534, 1237684, 2237684 };
+ const int64 visits_right[] = { 1024, 2065, 65534, 1237684 };
+
+ // DiffVisits will not remove the first visit, because we never delete visits
+ // from the start of the array (since those visits can get truncated by the
+ // size-limiting code).
+ const int64 visits_removed[] = { 1500, 6000, 2237684 };
+
+ for (size_t c = 0; c < arraysize(visits_left); ++c) {
+ old_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(visits_left[c]), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ }
+
+ for (size_t c = 0; c < arraysize(visits_right); ++c) {
+ new_url.add_visits(visits_right[c]);
+ new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ }
+
+ std::vector<history::VisitInfo> new_visits;
+ history::VisitVector removed_visits;
+
+ TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
+ &new_visits, &removed_visits);
+ EXPECT_TRUE(new_visits.empty());
+ ASSERT_EQ(removed_visits.size(), arraysize(visits_removed));
+ for (size_t c = 0; c < arraysize(visits_removed); ++c) {
+ EXPECT_EQ(removed_visits[c].visit_time.ToInternalValue(),
+ visits_removed[c]);
+ }
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, DiffVisitsAdd) {
+ history::VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64 visits_left[] = { 1024, 2065, 65534, 1237684 };
+ const int64 visits_right[] = { 1, 1024, 1500, 2065, 6000,
+ 65534, 1237684, 2237684 };
+
+ const int64 visits_added[] = { 1, 1500, 6000, 2237684 };
+
+ for (size_t c = 0; c < arraysize(visits_left); ++c) {
+ old_visits.push_back(history::VisitRow(
+ 0, base::Time::FromInternalValue(visits_left[c]), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ }
+
+ for (size_t c = 0; c < arraysize(visits_right); ++c) {
+ new_url.add_visits(visits_right[c]);
+ new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ }
+
+ std::vector<history::VisitInfo> new_visits;
+ history::VisitVector removed_visits;
+
+ TypedUrlModelAssociator::DiffVisits(old_visits, new_url,
+ &new_visits, &removed_visits);
+ EXPECT_TRUE(removed_visits.empty());
+ ASSERT_TRUE(new_visits.size() == arraysize(visits_added));
+ for (size_t c = 0; c < arraysize(visits_added); ++c) {
+ EXPECT_EQ(new_visits[c].first.ToInternalValue(),
+ visits_added[c]);
+ EXPECT_EQ(new_visits[c].second, ui::PAGE_TRANSITION_TYPED);
+ }
+}
+
+static history::VisitRow CreateVisit(ui::PageTransition type,
+ int64 timestamp) {
+ return history::VisitRow(0, base::Time::FromInternalValue(timestamp), 0,
+ type, 0);
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, WriteTypedUrlSpecifics) {
+ history::VisitVector visits;
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, 1));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, 2));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, 3));
+
+ history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
+ 1, 100, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // RELOAD visits should be removed.
+ EXPECT_EQ(2, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ EXPECT_EQ(1, typed_url.visits(0));
+ EXPECT_EQ(3, typed_url.visits(1));
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
+ ui::PageTransitionFromInt(typed_url.visit_transitions(0)));
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
+ ui::PageTransitionFromInt(typed_url.visit_transitions(1)));
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, TooManyVisits) {
+ history::VisitVector visits;
+ int64 timestamp = 1000;
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
+ for (int i = 0 ; i < 100; ++i) {
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++));
+ }
+ history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
+ 1, timestamp++, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // # visits should be capped at 100.
+ EXPECT_EQ(100, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ EXPECT_EQ(1000, typed_url.visits(0));
+ // Visit with timestamp of 1001 should be omitted since we should have
+ // skipped that visit to stay under the cap.
+ EXPECT_EQ(1002, typed_url.visits(1));
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
+ ui::PageTransitionFromInt(typed_url.visit_transitions(0)));
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
+ ui::PageTransitionFromInt(typed_url.visit_transitions(1)));
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, TooManyTypedVisits) {
+ history::VisitVector visits;
+ int64 timestamp = 1000;
+ for (int i = 0 ; i < 102; ++i) {
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, timestamp++));
+ }
+ history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
+ 1, timestamp++, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // # visits should be capped at 100.
+ EXPECT_EQ(100, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ // First two typed visits should be skipped.
+ EXPECT_EQ(1006, typed_url.visits(0));
+
+ // Ensure there are no non-typed visits since that's all that should fit.
+ for (int i = 0; i < typed_url.visits_size(); ++i) {
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
+ ui::PageTransitionFromInt(typed_url.visit_transitions(i)));
+ }
+}
+
+TEST_F(SyncTypedUrlModelAssociatorTest, NoTypedVisits) {
+ history::VisitVector visits;
+ history::URLRow url(MakeTypedUrlRow("http://pie.com/", "pie",
+ 1, 1000, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ TypedUrlModelAssociator::WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // URLs with no typed URL visits should be translated to a URL with one
+ // reload visit.
+ EXPECT_EQ(1, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ // First two typed visits should be skipped.
+ EXPECT_EQ(1000, typed_url.visits(0));
+ EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD,
+ ui::PageTransitionFromInt(typed_url.visit_transitions(0)));
+}
+
+// This test verifies that we can abort model association from the UI thread.
+// We start up the model associator on the DB thread, block until we abort the
+// association on the UI thread, then ensure that AssociateModels() returns
+// false.
+TEST_F(SyncTypedUrlModelAssociatorTest, TestAbort) {
+ base::Thread db_thread("DB_Thread");
+ db_thread.Start();
+
+ base::WaitableEvent startup(false, false);
+ base::WaitableEvent aborted(false, false);
+ base::WaitableEvent done(false, false);
+ sync_driver::FakeSyncService service;
+ TypedUrlModelAssociator* associator(NULL);
+ // Fire off to the DB thread to create the model associator and start
+ // model association.
+ base::Closure callback = base::Bind(
+ &CreateModelAssociatorAsync, &startup, &aborted, &done, &associator,
+ &service);
+ db_thread.task_runner()->PostTask(FROM_HERE, callback);
+ // Wait for the model associator to get created and start assocation.
+ ASSERT_TRUE(startup.TimedWait(TestTimeouts::action_timeout()));
+ // Abort the model assocation - this should be callable from any thread.
+ associator->AbortAssociation();
+ // Tell the remote thread to continue.
+ aborted.Signal();
+ // Block until CreateModelAssociator() exits.
+ ASSERT_TRUE(done.TimedWait(TestTimeouts::action_timeout()));
+ db_thread.Stop();
+}