OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 "components/history/core/browser/typed_url_sync_bridge.h" |
| 6 |
| 7 #include "base/files/scoped_temp_dir.h" |
| 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "base/threading/thread_task_runner_handle.h" |
| 11 #include "components/history/core/browser/history_backend.h" |
| 12 #include "components/history/core/browser/history_backend_client.h" |
| 13 #include "components/history/core/browser/history_database_params.h" |
| 14 #include "components/history/core/browser/in_memory_history_backend.h" |
| 15 #include "components/history/core/test/test_history_database.h" |
| 16 #include "components/sync/model/data_batch.h" |
| 17 #include "components/sync/model/recording_model_type_change_processor.h" |
| 18 #include "components/sync/model/sync_metadata_store.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 |
| 21 using sync_pb::TypedUrlSpecifics; |
| 22 using syncer::DataBatch; |
| 23 using syncer::EntityData; |
| 24 using syncer::EntityDataPtr; |
| 25 using syncer::KeyAndData; |
| 26 using syncer::RecordingModelTypeChangeProcessor; |
| 27 |
| 28 namespace history { |
| 29 |
| 30 namespace { |
| 31 |
| 32 // Visits with this timestamp are treated as expired. |
| 33 const int kExpiredVisit = -1; |
| 34 |
| 35 // Helper constants for tests. |
| 36 const char kTitle[] = "pie"; |
| 37 const char kTitle2[] = "cookie"; |
| 38 const char kURL[] = "http://pie.com/"; |
| 39 const char kURL2[] = "http://cookie.com/"; |
| 40 |
| 41 // Create a new row object and the typed visit çorresponding with the time at |
| 42 // |last_visit| in the |visits| vector. |
| 43 URLRow MakeTypedUrlRow(const std::string& url, |
| 44 const std::string& title, |
| 45 int typed_count, |
| 46 int64_t last_visit, |
| 47 bool hidden, |
| 48 VisitVector* visits) { |
| 49 // Give each URL a unique ID, to mimic the behavior of the real database. |
| 50 GURL gurl(url); |
| 51 URLRow history_url(gurl); |
| 52 history_url.set_title(base::UTF8ToUTF16(title)); |
| 53 history_url.set_typed_count(typed_count); |
| 54 history_url.set_hidden(hidden); |
| 55 |
| 56 base::Time last_visit_time = base::Time::FromInternalValue(last_visit); |
| 57 history_url.set_last_visit(last_visit_time); |
| 58 |
| 59 if (typed_count > 0) { |
| 60 // Add a typed visit for time |last_visit|. |
| 61 visits->push_back(VisitRow(history_url.id(), last_visit_time, 0, |
| 62 ui::PAGE_TRANSITION_TYPED, 0)); |
| 63 } else { |
| 64 // Add a non-typed visit for time |last_visit|. |
| 65 visits->push_back(VisitRow(history_url.id(), last_visit_time, 0, |
| 66 ui::PAGE_TRANSITION_RELOAD, 0)); |
| 67 } |
| 68 |
| 69 history_url.set_visit_count(visits->size()); |
| 70 return history_url; |
| 71 } |
| 72 |
| 73 void VerifyEqual(const TypedUrlSpecifics& s1, const TypedUrlSpecifics& s2) { |
| 74 // Instead of just comparing serialized strings, manually check fields to show |
| 75 // differences on failure. |
| 76 EXPECT_EQ(s1.url(), s2.url()); |
| 77 EXPECT_EQ(s1.title(), s2.title()); |
| 78 EXPECT_EQ(s1.hidden(), s2.hidden()); |
| 79 EXPECT_EQ(s1.visits_size(), s2.visits_size()); |
| 80 EXPECT_EQ(s1.visit_transitions_size(), s2.visit_transitions_size()); |
| 81 EXPECT_EQ(s1.visits_size(), s1.visit_transitions_size()); |
| 82 int size = s1.visits_size(); |
| 83 for (int i = 0; i < size; ++i) { |
| 84 EXPECT_EQ(s1.visits(i), s2.visits(i)) << "visits differ at index " << i; |
| 85 EXPECT_EQ(s1.visit_transitions(i), s2.visit_transitions(i)) |
| 86 << "visit_transitions differ at index " << i; |
| 87 } |
| 88 } |
| 89 |
| 90 void VerifyDataBatch(std::map<std::string, TypedUrlSpecifics> expected, |
| 91 std::unique_ptr<DataBatch> batch) { |
| 92 while (batch->HasNext()) { |
| 93 const KeyAndData& pair = batch->Next(); |
| 94 auto iter = expected.find(pair.first); |
| 95 ASSERT_NE(iter, expected.end()); |
| 96 VerifyEqual(iter->second, pair.second->specifics.typed_url()); |
| 97 // Removing allows us to verify we don't see the same item multiple times, |
| 98 // and that we saw everything we expected. |
| 99 expected.erase(iter); |
| 100 } |
| 101 EXPECT_TRUE(expected.empty()); |
| 102 } |
| 103 |
| 104 class TestHistoryBackendDelegate : public HistoryBackend::Delegate { |
| 105 public: |
| 106 TestHistoryBackendDelegate() {} |
| 107 |
| 108 void NotifyProfileError(sql::InitStatus init_status, |
| 109 const std::string& diagnostics) override {} |
| 110 void SetInMemoryBackend( |
| 111 std::unique_ptr<InMemoryHistoryBackend> backend) override{}; |
| 112 void NotifyFaviconsChanged(const std::set<GURL>& page_urls, |
| 113 const GURL& icon_url) override{}; |
| 114 void NotifyURLVisited(ui::PageTransition transition, |
| 115 const URLRow& row, |
| 116 const RedirectList& redirects, |
| 117 base::Time visit_time) override{}; |
| 118 void NotifyURLsModified(const URLRows& changed_urls) override{}; |
| 119 void NotifyURLsDeleted(bool all_history, |
| 120 bool expired, |
| 121 const URLRows& deleted_rows, |
| 122 const std::set<GURL>& favicon_urls) override{}; |
| 123 void NotifyKeywordSearchTermUpdated(const URLRow& row, |
| 124 KeywordID keyword_id, |
| 125 const base::string16& term) override{}; |
| 126 void NotifyKeywordSearchTermDeleted(URLID url_id) override{}; |
| 127 void DBLoaded() override{}; |
| 128 |
| 129 private: |
| 130 DISALLOW_COPY_AND_ASSIGN(TestHistoryBackendDelegate); |
| 131 }; |
| 132 |
| 133 class TestHistoryBackend : public HistoryBackend { |
| 134 public: |
| 135 TestHistoryBackend() |
| 136 : HistoryBackend(new TestHistoryBackendDelegate(), |
| 137 nullptr, |
| 138 base::ThreadTaskRunnerHandle::Get()) {} |
| 139 |
| 140 bool IsExpiredVisitTime(const base::Time& time) override { |
| 141 return time.ToInternalValue() == kExpiredVisit; |
| 142 } |
| 143 |
| 144 URLID GetIdByUrl(const GURL& gurl) { |
| 145 return db()->GetRowForURL(gurl, nullptr); |
| 146 } |
| 147 |
| 148 void SetVisitsForUrl(URLRow& new_url, const VisitVector visits) { |
| 149 std::vector<history::VisitInfo> added_visits; |
| 150 URLRows new_urls; |
| 151 DeleteURL(new_url.url()); |
| 152 for (const auto& visit : visits) { |
| 153 added_visits.push_back( |
| 154 history::VisitInfo(visit.visit_time, visit.transition)); |
| 155 } |
| 156 new_urls.push_back(new_url); |
| 157 AddPagesWithDetails(new_urls, history::SOURCE_SYNCED); |
| 158 AddVisits(new_url.url(), added_visits, history::SOURCE_SYNCED); |
| 159 new_url.set_id(GetIdByUrl(new_url.url())); |
| 160 } |
| 161 |
| 162 private: |
| 163 ~TestHistoryBackend() override {} |
| 164 }; |
| 165 |
| 166 } // namespace |
| 167 |
| 168 class TypedURLSyncBridgeTest : public testing::Test { |
| 169 public: |
| 170 TypedURLSyncBridgeTest() : typed_url_sync_bridge_(NULL) {} |
| 171 ~TypedURLSyncBridgeTest() override {} |
| 172 |
| 173 void SetUp() override { |
| 174 fake_history_backend_ = new TestHistoryBackend(); |
| 175 ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); |
| 176 fake_history_backend_->Init( |
| 177 false, TestHistoryDatabaseParamsForPath(test_dir_.GetPath())); |
| 178 std::unique_ptr<TypedURLSyncBridge> bridge = |
| 179 base::MakeUnique<TypedURLSyncBridge>( |
| 180 fake_history_backend_.get(), fake_history_backend_->db(), |
| 181 RecordingModelTypeChangeProcessor::FactoryForBridgeTest(&processor_, |
| 182 false)); |
| 183 typed_url_sync_bridge_ = bridge.get(); |
| 184 typed_url_sync_bridge_->Init(); |
| 185 fake_history_backend_->SetTypedURLSyncBridgeForTest(std::move(bridge)); |
| 186 } |
| 187 |
| 188 void TearDown() override { fake_history_backend_->Closing(); } |
| 189 |
| 190 // Fills |specifics| with the sync data for |url| and |visits|. |
| 191 static bool WriteToTypedUrlSpecifics(const URLRow& url, |
| 192 const VisitVector& visits, |
| 193 sync_pb::TypedUrlSpecifics* specifics) { |
| 194 return TypedURLSyncBridge::WriteToTypedUrlSpecifics(url, visits, specifics); |
| 195 } |
| 196 |
| 197 std::string GetStorageKey(const TypedUrlSpecifics& specifics) { |
| 198 std::string key = |
| 199 bridge()->GetStorageKey(SpecificsToEntity(specifics).value()); |
| 200 EXPECT_FALSE(key.empty()); |
| 201 return key; |
| 202 } |
| 203 |
| 204 EntityDataPtr SpecificsToEntity(const TypedUrlSpecifics& specifics) { |
| 205 EntityData data; |
| 206 data.client_tag_hash = "ignored"; |
| 207 *data.specifics.mutable_typed_url() = specifics; |
| 208 return data.PassToPtr(); |
| 209 } |
| 210 |
| 211 std::map<std::string, TypedUrlSpecifics> ExpectedMap( |
| 212 const std::vector<TypedUrlSpecifics>& specifics_vector) { |
| 213 std::map<std::string, TypedUrlSpecifics> map; |
| 214 for (const auto& specifics : specifics_vector) { |
| 215 map[GetStorageKey(specifics)] = specifics; |
| 216 } |
| 217 return map; |
| 218 } |
| 219 |
| 220 void VerifyLocalHistoryData(const std::vector<TypedUrlSpecifics>& expected) { |
| 221 bridge()->GetAllData(base::Bind(&VerifyDataBatch, ExpectedMap(expected))); |
| 222 } |
| 223 |
| 224 TypedURLSyncBridge* bridge() { return typed_url_sync_bridge_; } |
| 225 |
| 226 TypedURLSyncMetadataDatabase* metadata_store() { |
| 227 return bridge()->sync_metadata_database_; |
| 228 } |
| 229 |
| 230 const RecordingModelTypeChangeProcessor& processor() { return *processor_; } |
| 231 |
| 232 protected: |
| 233 base::MessageLoop message_loop_; |
| 234 base::ScopedTempDir test_dir_; |
| 235 scoped_refptr<TestHistoryBackend> fake_history_backend_; |
| 236 TypedURLSyncBridge* typed_url_sync_bridge_; |
| 237 // A non-owning pointer to the processor given to the bridge. Will be null |
| 238 // before being given to the bridge, to make ownership easier. |
| 239 RecordingModelTypeChangeProcessor* processor_ = nullptr; |
| 240 }; |
| 241 |
| 242 // Add two typed urls locally and verify bridge can get them from GetAllData. |
| 243 TEST_F(TypedURLSyncBridgeTest, GetAllData) { |
| 244 // Add two urls to backend. |
| 245 VisitVector visits1, visits2; |
| 246 URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1); |
| 247 URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2); |
| 248 fake_history_backend_->SetVisitsForUrl(row1, visits1); |
| 249 fake_history_backend_->SetVisitsForUrl(row2, visits2); |
| 250 |
| 251 // Create the same data in sync. |
| 252 sync_pb::TypedUrlSpecifics typed_url1, typed_url2; |
| 253 WriteToTypedUrlSpecifics(row1, visits1, &typed_url1); |
| 254 WriteToTypedUrlSpecifics(row2, visits2, &typed_url2); |
| 255 |
| 256 // Check that the local cache is still correct. |
| 257 VerifyLocalHistoryData({typed_url1, typed_url2}); |
| 258 } |
| 259 |
| 260 } // namespace history |
OLD | NEW |