diff options
author | blundell <blundell@chromium.org> | 2015-10-26 01:12:55 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-26 08:14:06 +0000 |
commit | b458c69d81cceaafce4fde649f19e01b22759595 (patch) | |
tree | 725d475400f022f8f50ae68a4e182689bc40b097 /components/history | |
parent | efafc6b60a513935f821512b9ad132b0c9a3f83b (diff) | |
download | chromium_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.gn | 2 | ||||
-rw-r--r-- | components/history/core/browser/typed_url_model_associator_unittest.cc | 432 |
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(); +} |