Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/history/core/browser/typed_url_sync_bridge.h" | 5 #include "components/history/core/browser/typed_url_sync_bridge.h" |
| 6 | 6 |
| 7 #include "base/big_endian.h" | |
| 7 #include "base/files/scoped_temp_dir.h" | 8 #include "base/files/scoped_temp_dir.h" |
| 8 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| 10 #include "base/threading/thread_task_runner_handle.h" | 11 #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.h" |
| 12 #include "components/history/core/browser/history_backend_client.h" | 13 #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/history_database_params.h" |
| 14 #include "components/history/core/browser/in_memory_history_backend.h" | 15 #include "components/history/core/browser/in_memory_history_backend.h" |
| 15 #include "components/history/core/test/test_history_database.h" | 16 #include "components/history/core/test/test_history_database.h" |
| 16 #include "components/sync/model/data_batch.h" | 17 #include "components/sync/model/data_batch.h" |
| 17 #include "components/sync/model/recording_model_type_change_processor.h" | 18 #include "components/sync/model/recording_model_type_change_processor.h" |
| 18 #include "components/sync/model/sync_metadata_store.h" | 19 #include "components/sync/model/sync_metadata_store.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 21 |
| 21 using sync_pb::TypedUrlSpecifics; | 22 using sync_pb::TypedUrlSpecifics; |
| 22 using syncer::DataBatch; | 23 using syncer::DataBatch; |
| 23 using syncer::EntityChange; | 24 using syncer::EntityChange; |
| 24 using syncer::EntityChangeList; | 25 using syncer::EntityChangeList; |
| 25 using syncer::EntityData; | 26 using syncer::EntityData; |
| 26 using syncer::EntityDataPtr; | 27 using syncer::EntityDataPtr; |
| 27 using syncer::KeyAndData; | 28 using syncer::KeyAndData; |
| 28 using syncer::MetadataBatch; | 29 using syncer::MetadataBatch; |
| 30 using syncer::MetadataChangeList; | |
| 29 using syncer::RecordingModelTypeChangeProcessor; | 31 using syncer::RecordingModelTypeChangeProcessor; |
| 30 | 32 |
| 31 namespace history { | 33 namespace history { |
| 32 | 34 |
| 33 namespace { | 35 namespace { |
| 34 | 36 |
| 37 // Constants used to limit size of visits processed. See | |
| 38 // equivalent constants in typed_url_sync_bridge.cc for descriptions. | |
| 39 const int kMaxTypedUrlVisits = 100; | |
| 40 const int kVisitThrottleThreshold = 10; | |
| 41 const int kVisitThrottleMultiple = 10; | |
| 42 | |
| 35 // Visits with this timestamp are treated as expired. | 43 // Visits with this timestamp are treated as expired. |
| 36 const int kExpiredVisit = -1; | 44 const int kExpiredVisit = -1; |
| 37 | 45 |
| 38 // Helper constants for tests. | 46 // Helper constants for tests. |
| 39 const char kTitle[] = "pie"; | 47 const char kTitle[] = "pie"; |
| 40 const char kTitle2[] = "cookie"; | 48 const char kTitle2[] = "cookie"; |
| 41 const char kURL[] = "http://pie.com/"; | 49 const char kURL[] = "http://pie.com/"; |
| 42 const char kURL2[] = "http://cookie.com/"; | 50 const char kURL2[] = "http://cookie.com/"; |
| 43 | 51 |
| 52 bool URLsEqual(URLRow& row, sync_pb::TypedUrlSpecifics& specifics) { | |
| 53 return ((row.url().spec().compare(specifics.url()) == 0) && | |
| 54 (base::UTF16ToUTF8(row.title()).compare(specifics.title()) == 0) && | |
| 55 (row.hidden() == specifics.hidden())); | |
| 56 } | |
| 57 | |
| 58 bool URLsEqual(URLRow& lhs, URLRow& rhs) { | |
| 59 // Only compare synced fields (ignore typed_count and visit_count as those | |
| 60 // are maintained by the history subsystem). | |
| 61 return (lhs.url().spec().compare(rhs.url().spec()) == 0) && | |
| 62 (lhs.title().compare(rhs.title()) == 0) && | |
| 63 (lhs.hidden() == rhs.hidden()); | |
| 64 } | |
| 65 | |
| 66 void AddNewestVisit(ui::PageTransition transition, | |
| 67 int64_t visit_time, | |
| 68 URLRow* url, | |
| 69 VisitVector* visits) { | |
| 70 base::Time time = base::Time::FromInternalValue(visit_time); | |
| 71 visits->insert(visits->begin(), VisitRow(url->id(), time, 0, transition, 0)); | |
| 72 | |
| 73 if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) { | |
| 74 url->set_typed_count(url->typed_count() + 1); | |
| 75 } | |
| 76 | |
| 77 url->set_last_visit(time); | |
| 78 url->set_visit_count(visits->size()); | |
| 79 } | |
| 80 | |
| 81 void AddOldestVisit(ui::PageTransition transition, | |
| 82 int64_t visit_time, | |
| 83 URLRow* url, | |
| 84 VisitVector* visits) { | |
| 85 base::Time time = base::Time::FromInternalValue(visit_time); | |
| 86 visits->push_back(VisitRow(url->id(), time, 0, transition, 0)); | |
| 87 | |
| 88 if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) { | |
| 89 url->set_typed_count(url->typed_count() + 1); | |
| 90 } | |
| 91 | |
| 92 url->set_visit_count(visits->size()); | |
| 93 } | |
| 94 | |
| 44 // Create a new row object and the typed visit çorresponding with the time at | 95 // Create a new row object and the typed visit çorresponding with the time at |
| 45 // |last_visit| in the |visits| vector. | 96 // |last_visit| in the |visits| vector. |
| 46 URLRow MakeTypedUrlRow(const std::string& url, | 97 URLRow MakeTypedUrlRow(const std::string& url, |
| 47 const std::string& title, | 98 const std::string& title, |
| 48 int typed_count, | 99 int typed_count, |
| 49 int64_t last_visit, | 100 int64_t last_visit, |
| 50 bool hidden, | 101 bool hidden, |
| 51 VisitVector* visits) { | 102 VisitVector* visits) { |
| 52 // Give each URL a unique ID, to mimic the behavior of the real database. | 103 // Give each URL a unique ID, to mimic the behavior of the real database. |
| 53 GURL gurl(url); | 104 GURL gurl(url); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 auto iter = expected.find(pair.first); | 148 auto iter = expected.find(pair.first); |
| 98 ASSERT_NE(iter, expected.end()); | 149 ASSERT_NE(iter, expected.end()); |
| 99 VerifyEqual(iter->second, pair.second->specifics.typed_url()); | 150 VerifyEqual(iter->second, pair.second->specifics.typed_url()); |
| 100 // Removing allows us to verify we don't see the same item multiple times, | 151 // Removing allows us to verify we don't see the same item multiple times, |
| 101 // and that we saw everything we expected. | 152 // and that we saw everything we expected. |
| 102 expected.erase(iter); | 153 expected.erase(iter); |
| 103 } | 154 } |
| 104 EXPECT_TRUE(expected.empty()); | 155 EXPECT_TRUE(expected.empty()); |
| 105 } | 156 } |
| 106 | 157 |
| 158 std::string IntToStroageKey(int id) { | |
| 159 std::string storage_key(sizeof(URLID), 0); | |
| 160 base::WriteBigEndian<URLID>(&storage_key[0], id); | |
| 161 return storage_key; | |
| 162 } | |
| 163 | |
| 107 class TestHistoryBackendDelegate : public HistoryBackend::Delegate { | 164 class TestHistoryBackendDelegate : public HistoryBackend::Delegate { |
| 108 public: | 165 public: |
| 109 TestHistoryBackendDelegate() {} | 166 TestHistoryBackendDelegate() {} |
| 110 | 167 |
| 111 void NotifyProfileError(sql::InitStatus init_status, | 168 void NotifyProfileError(sql::InitStatus init_status, |
| 112 const std::string& diagnostics) override {} | 169 const std::string& diagnostics) override {} |
| 113 void SetInMemoryBackend( | 170 void SetInMemoryBackend( |
| 114 std::unique_ptr<InMemoryHistoryBackend> backend) override {} | 171 std::unique_ptr<InMemoryHistoryBackend> backend) override {} |
| 115 void NotifyFaviconsChanged(const std::set<GURL>& page_urls, | 172 void NotifyFaviconsChanged(const std::set<GURL>& page_urls, |
| 116 const GURL& icon_url) override {} | 173 const GURL& icon_url) override {} |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 142 | 199 |
| 143 bool IsExpiredVisitTime(const base::Time& time) override { | 200 bool IsExpiredVisitTime(const base::Time& time) override { |
| 144 return time.ToInternalValue() == kExpiredVisit; | 201 return time.ToInternalValue() == kExpiredVisit; |
| 145 } | 202 } |
| 146 | 203 |
| 147 URLID GetIdByUrl(const GURL& gurl) { | 204 URLID GetIdByUrl(const GURL& gurl) { |
| 148 return db()->GetRowForURL(gurl, nullptr); | 205 return db()->GetRowForURL(gurl, nullptr); |
| 149 } | 206 } |
| 150 | 207 |
| 151 void SetVisitsForUrl(URLRow& new_url, const VisitVector visits) { | 208 void SetVisitsForUrl(URLRow& new_url, const VisitVector visits) { |
| 152 std::vector<history::VisitInfo> added_visits; | 209 if (!GetURL(new_url.url(), nullptr)) { |
| 153 URLRows new_urls; | 210 URLRows new_urls; |
| 154 DeleteURL(new_url.url()); | 211 new_urls.push_back(new_url); |
| 212 AddPagesWithDetails(new_urls, SOURCE_SYNCED); | |
| 213 } | |
| 214 | |
| 215 std::vector<VisitInfo> added_visits; | |
| 155 for (const auto& visit : visits) { | 216 for (const auto& visit : visits) { |
| 156 added_visits.push_back( | 217 added_visits.push_back(VisitInfo(visit.visit_time, visit.transition)); |
| 157 history::VisitInfo(visit.visit_time, visit.transition)); | |
| 158 } | 218 } |
| 159 new_urls.push_back(new_url); | 219 AddVisits(new_url.url(), added_visits, SOURCE_SYNCED); |
| 160 AddPagesWithDetails(new_urls, history::SOURCE_SYNCED); | |
| 161 AddVisits(new_url.url(), added_visits, history::SOURCE_SYNCED); | |
| 162 new_url.set_id(GetIdByUrl(new_url.url())); | 220 new_url.set_id(GetIdByUrl(new_url.url())); |
| 163 } | 221 } |
| 164 | 222 |
| 165 private: | 223 private: |
| 166 ~TestHistoryBackend() override {} | 224 ~TestHistoryBackend() override {} |
| 167 }; | 225 }; |
| 168 | 226 |
| 169 } // namespace | 227 } // namespace |
| 170 | 228 |
| 171 class TypedURLSyncBridgeTest : public testing::Test { | 229 class TypedURLSyncBridgeTest : public testing::Test { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 182 base::MakeUnique<TypedURLSyncBridge>( | 240 base::MakeUnique<TypedURLSyncBridge>( |
| 183 fake_history_backend_.get(), fake_history_backend_->db(), | 241 fake_history_backend_.get(), fake_history_backend_->db(), |
| 184 RecordingModelTypeChangeProcessor::FactoryForBridgeTest(&processor_, | 242 RecordingModelTypeChangeProcessor::FactoryForBridgeTest(&processor_, |
| 185 false)); | 243 false)); |
| 186 typed_url_sync_bridge_ = bridge.get(); | 244 typed_url_sync_bridge_ = bridge.get(); |
| 187 typed_url_sync_bridge_->Init(); | 245 typed_url_sync_bridge_->Init(); |
| 188 typed_url_sync_bridge_->history_backend_observer_.RemoveAll(); | 246 typed_url_sync_bridge_->history_backend_observer_.RemoveAll(); |
| 189 fake_history_backend_->SetTypedURLSyncBridgeForTest(std::move(bridge)); | 247 fake_history_backend_->SetTypedURLSyncBridgeForTest(std::move(bridge)); |
| 190 } | 248 } |
| 191 | 249 |
| 192 void TearDown() override { fake_history_backend_->Closing(); } | 250 void TearDown() override { |
| 251 VerifyProcessorReceivedValidEntityData(); | |
| 252 fake_history_backend_->Closing(); | |
| 253 } | |
| 193 | 254 |
| 194 // Starts sync for |typed_url_sync_bridge_| with |initial_data| as the | 255 // Starts sync for |typed_url_sync_bridge_| with |initial_data| as the |
| 195 // initial sync data. | 256 // initial sync data. |
| 196 void StartSyncing(const std::vector<TypedUrlSpecifics>& specifics) { | 257 void StartSyncing(const std::vector<TypedUrlSpecifics>& specifics) { |
| 197 // Set change processor. | 258 // Set change processor. |
| 198 const auto error = | 259 const auto error = |
| 199 bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(), | 260 bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(), |
| 200 CreateEntityChangeList(specifics)); | 261 CreateEntityChangeList(specifics)); |
| 201 | 262 |
| 202 EXPECT_FALSE(error); | 263 EXPECT_FALSE(error); |
| 203 } | 264 } |
| 204 | 265 |
| 266 bool BuildAndPushLocalChanges(unsigned int num_typed_urls, | |
| 267 unsigned int num_reload_urls, | |
| 268 const std::vector<std::string>& urls, | |
| 269 URLRows* rows, | |
| 270 std::vector<VisitVector>* visit_vectors) { | |
| 271 unsigned int total_urls = num_typed_urls + num_reload_urls; | |
| 272 DCHECK(urls.size() >= total_urls); | |
| 273 if (!bridge()) | |
| 274 return false; | |
| 275 | |
| 276 if (total_urls) { | |
| 277 // Create new URL rows, populate the mock backend with its visits, and | |
| 278 // send to the sync service. | |
| 279 URLRows changed_urls; | |
| 280 | |
| 281 for (unsigned int i = 0; i < total_urls; ++i) { | |
| 282 int typed = i < num_typed_urls ? 1 : 0; | |
| 283 VisitVector visits; | |
| 284 visit_vectors->push_back(visits); | |
| 285 rows->push_back(MakeTypedUrlRow(urls[i], kTitle, typed, i + 3, false, | |
| 286 &visit_vectors->back())); | |
| 287 fake_history_backend_->SetVisitsForUrl(rows->back(), | |
| 288 visit_vectors->back()); | |
| 289 changed_urls.push_back(rows->back()); | |
| 290 } | |
| 291 | |
| 292 bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls); | |
| 293 } | |
| 294 | |
| 295 // Check that communication with sync was successful. | |
| 296 if (num_typed_urls != processor().put_multimap().size()) | |
| 297 return false; | |
| 298 return true; | |
| 299 } | |
| 300 | |
| 301 VisitVector ApplyUrlAndVisitsChange(const std::string& url, | |
| 302 const std::string& title, | |
| 303 int typed_count, | |
| 304 int64_t last_visit, | |
| 305 bool hidden, | |
| 306 EntityChange::ChangeType change_type) { | |
| 307 VisitVector visits; | |
| 308 URLRow row = | |
| 309 MakeTypedUrlRow(url, title, typed_count, last_visit, hidden, &visits); | |
| 310 sync_pb::TypedUrlSpecifics typed_url_specifics; | |
| 311 WriteToTypedUrlSpecifics(row, visits, &typed_url_specifics); | |
| 312 std::unique_ptr<MetadataChangeList> metadata_changes = | |
| 313 bridge()->CreateMetadataChangeList(); | |
| 314 EntityChangeList entity_changes; | |
| 315 switch (change_type) { | |
| 316 case EntityChange::ACTION_ADD: | |
| 317 entity_changes.push_back(EntityChange::CreateAdd( | |
| 318 std::string(), SpecificsToEntity(typed_url_specifics))); | |
| 319 break; | |
| 320 case EntityChange::ACTION_UPDATE: | |
| 321 entity_changes.push_back( | |
| 322 EntityChange::CreateUpdate(GetStorageKey(typed_url_specifics.url()), | |
| 323 SpecificsToEntity(typed_url_specifics))); | |
| 324 break; | |
| 325 case EntityChange::ACTION_DELETE: | |
| 326 entity_changes.push_back(EntityChange::CreateDelete( | |
| 327 GetStorageKey(typed_url_specifics.url()))); | |
| 328 break; | |
| 329 } | |
| 330 bridge()->ApplySyncChanges(std::move(metadata_changes), entity_changes); | |
| 331 return visits; | |
| 332 } | |
| 333 | |
| 334 void AddObserver() { | |
| 335 bridge()->history_backend_observer_.Add(fake_history_backend_.get()); | |
| 336 } | |
| 337 | |
| 338 void RemoveObserver() { bridge()->history_backend_observer_.RemoveAll(); } | |
| 339 | |
| 205 // Fills |specifics| with the sync data for |url| and |visits|. | 340 // Fills |specifics| with the sync data for |url| and |visits|. |
| 206 static bool WriteToTypedUrlSpecifics(const URLRow& url, | 341 static bool WriteToTypedUrlSpecifics(const URLRow& url, |
| 207 const VisitVector& visits, | 342 const VisitVector& visits, |
| 208 TypedUrlSpecifics* specifics) { | 343 TypedUrlSpecifics* specifics) { |
| 209 return TypedURLSyncBridge::WriteToTypedUrlSpecifics(url, visits, specifics); | 344 return TypedURLSyncBridge::WriteToTypedUrlSpecifics(url, visits, specifics); |
| 210 } | 345 } |
| 211 | 346 |
| 212 std::string GetStorageKey(const TypedUrlSpecifics& specifics) { | 347 std::string GetStorageKey(const std::string& url) { |
| 213 std::string key = bridge()->GetStorageKeyInternal(specifics.url()); | 348 return bridge()->GetStorageKeyInternal(url); |
| 214 return key; | |
| 215 } | 349 } |
| 216 | 350 |
| 217 EntityDataPtr SpecificsToEntity(const TypedUrlSpecifics& specifics) { | 351 EntityDataPtr SpecificsToEntity(const TypedUrlSpecifics& specifics) { |
| 218 EntityData data; | 352 EntityData data; |
| 219 data.client_tag_hash = "ignored"; | 353 data.client_tag_hash = "ignored"; |
| 220 *data.specifics.mutable_typed_url() = specifics; | 354 *data.specifics.mutable_typed_url() = specifics; |
| 221 return data.PassToPtr(); | 355 return data.PassToPtr(); |
| 222 } | 356 } |
| 223 | 357 |
| 224 EntityChangeList CreateEntityChangeList( | 358 EntityChangeList CreateEntityChangeList( |
| 225 const std::vector<TypedUrlSpecifics>& specifics_vector) { | 359 const std::vector<TypedUrlSpecifics>& specifics_vector) { |
| 226 EntityChangeList entity_change_list; | 360 EntityChangeList entity_change_list; |
| 227 for (const auto& specifics : specifics_vector) { | 361 for (const auto& specifics : specifics_vector) { |
| 228 entity_change_list.push_back(EntityChange::CreateAdd( | 362 entity_change_list.push_back(EntityChange::CreateAdd( |
| 229 GetStorageKey(specifics), SpecificsToEntity(specifics))); | 363 GetStorageKey(specifics.url()), SpecificsToEntity(specifics))); |
| 230 } | 364 } |
| 231 return entity_change_list; | 365 return entity_change_list; |
| 232 } | 366 } |
| 233 | 367 |
| 234 std::map<std::string, TypedUrlSpecifics> ExpectedMap( | 368 std::map<std::string, TypedUrlSpecifics> ExpectedMap( |
| 235 const std::vector<TypedUrlSpecifics>& specifics_vector) { | 369 const std::vector<TypedUrlSpecifics>& specifics_vector) { |
| 236 std::map<std::string, TypedUrlSpecifics> map; | 370 std::map<std::string, TypedUrlSpecifics> map; |
| 237 for (const auto& specifics : specifics_vector) { | 371 for (const auto& specifics : specifics_vector) { |
| 238 map[GetStorageKey(specifics)] = specifics; | 372 map[GetStorageKey(specifics.url())] = specifics; |
| 239 } | 373 } |
| 240 return map; | 374 return map; |
| 241 } | 375 } |
| 242 | 376 |
| 243 void VerifyLocalHistoryData(const std::vector<TypedUrlSpecifics>& expected) { | 377 void VerifyAllLocalHistoryData( |
| 378 const std::vector<TypedUrlSpecifics>& expected) { | |
| 244 bridge()->GetAllData(base::Bind(&VerifyDataBatch, ExpectedMap(expected))); | 379 bridge()->GetAllData(base::Bind(&VerifyDataBatch, ExpectedMap(expected))); |
| 245 } | 380 } |
| 246 | 381 |
| 382 void VerifyGetData(TypedURLSyncBridge::StorageKeyList storage_keys, | |
| 383 const std::vector<TypedUrlSpecifics>& expected) { | |
| 384 bridge()->GetData(storage_keys, | |
| 385 base::Bind(&VerifyDataBatch, ExpectedMap(expected))); | |
| 386 } | |
| 387 | |
| 388 void VerifyProcessorReceivedValidEntityData() { | |
| 389 for (const auto& it : processor().put_multimap()) { | |
| 390 EXPECT_GT(TypedURLSyncMetadataDatabase::StorageKeyToURLID(it.first), 0); | |
| 391 EXPECT_TRUE(it.second->specifics.has_typed_url()); | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 sync_pb::TypedUrlSpecifics GetLastUpdateForURL(const std::string& url) { | |
| 396 const std::string storage_key = GetStorageKey(url); | |
| 397 auto recorded_specifics_iterator = | |
| 398 processor().put_multimap().find(storage_key); | |
|
pavely
2017/07/18 01:17:56
You still didn't address my comment. Imagine you i
Gang Wu
2017/07/18 19:11:57
I see, I misunderstand the comments. fixed.
| |
| 399 EXPECT_NE(processor().put_multimap().end(), recorded_specifics_iterator); | |
| 400 EXPECT_TRUE(recorded_specifics_iterator->second->specifics.has_typed_url()); | |
| 401 | |
| 402 EntityData* entity_data = recorded_specifics_iterator->second.get(); | |
| 403 size_t count = processor().put_multimap().count(storage_key); | |
| 404 while (count > 1) { | |
| 405 recorded_specifics_iterator++; | |
| 406 EXPECT_NE(processor().put_multimap().end(), recorded_specifics_iterator); | |
| 407 --count; | |
| 408 | |
| 409 if (entity_data->modification_time < | |
| 410 recorded_specifics_iterator->second->modification_time) | |
| 411 entity_data = recorded_specifics_iterator->second.get(); | |
| 412 } | |
| 413 | |
| 414 EXPECT_TRUE(entity_data->specifics.has_typed_url()); | |
| 415 | |
| 416 return entity_data->specifics.typed_url(); | |
| 417 } | |
| 418 | |
| 419 static void DiffVisits(const VisitVector& history_visits, | |
| 420 const sync_pb::TypedUrlSpecifics& sync_specifics, | |
| 421 std::vector<VisitInfo>* new_visits, | |
| 422 VisitVector* removed_visits) { | |
| 423 TypedURLSyncBridge::DiffVisits(history_visits, sync_specifics, new_visits, | |
| 424 removed_visits); | |
| 425 } | |
| 426 | |
| 427 static VisitRow CreateVisit(ui::PageTransition type, int64_t timestamp) { | |
| 428 return VisitRow(0, base::Time::FromInternalValue(timestamp), 0, type, 0); | |
| 429 } | |
| 430 | |
| 431 static TypedURLSyncBridge::MergeResult MergeUrls( | |
| 432 const sync_pb::TypedUrlSpecifics& typed_url, | |
| 433 const URLRow& url, | |
| 434 VisitVector* visits, | |
| 435 URLRow* new_url, | |
| 436 std::vector<VisitInfo>* new_visits) { | |
| 437 return TypedURLSyncBridge::MergeUrls(typed_url, url, visits, new_url, | |
| 438 new_visits); | |
| 439 } | |
| 440 | |
| 441 static sync_pb::TypedUrlSpecifics MakeTypedUrlSpecifics(const char* url, | |
| 442 const char* title, | |
| 443 int64_t last_visit, | |
| 444 bool hidden) { | |
| 445 sync_pb::TypedUrlSpecifics typed_url; | |
| 446 typed_url.set_url(url); | |
| 447 typed_url.set_title(title); | |
| 448 typed_url.set_hidden(hidden); | |
| 449 typed_url.add_visits(last_visit); | |
| 450 typed_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED); | |
| 451 return typed_url; | |
| 452 } | |
| 453 | |
| 454 static const TypedURLSyncBridge::MergeResult DIFF_NONE = | |
| 455 TypedURLSyncBridge::DIFF_NONE; | |
| 456 static const TypedURLSyncBridge::MergeResult DIFF_UPDATE_NODE = | |
| 457 TypedURLSyncBridge::DIFF_UPDATE_NODE; | |
| 458 static const TypedURLSyncBridge::MergeResult DIFF_LOCAL_ROW_CHANGED = | |
| 459 TypedURLSyncBridge::DIFF_LOCAL_ROW_CHANGED; | |
| 460 static const TypedURLSyncBridge::MergeResult DIFF_LOCAL_VISITS_ADDED = | |
| 461 TypedURLSyncBridge::DIFF_LOCAL_VISITS_ADDED; | |
| 462 | |
| 247 TypedURLSyncBridge* bridge() { return typed_url_sync_bridge_; } | 463 TypedURLSyncBridge* bridge() { return typed_url_sync_bridge_; } |
| 248 | 464 |
| 249 TypedURLSyncMetadataDatabase* metadata_store() { | 465 TypedURLSyncMetadataDatabase* metadata_store() { |
| 250 return bridge()->sync_metadata_database_; | 466 return bridge()->sync_metadata_database_; |
| 251 } | 467 } |
| 252 | 468 |
| 253 const RecordingModelTypeChangeProcessor& processor() { return *processor_; } | 469 const RecordingModelTypeChangeProcessor& processor() { return *processor_; } |
| 254 | 470 |
| 255 protected: | 471 protected: |
| 256 base::MessageLoop message_loop_; | 472 base::MessageLoop message_loop_; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 270 URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2); | 486 URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2); |
| 271 fake_history_backend_->SetVisitsForUrl(row1, visits1); | 487 fake_history_backend_->SetVisitsForUrl(row1, visits1); |
| 272 fake_history_backend_->SetVisitsForUrl(row2, visits2); | 488 fake_history_backend_->SetVisitsForUrl(row2, visits2); |
| 273 | 489 |
| 274 // Create the same data in sync. | 490 // Create the same data in sync. |
| 275 TypedUrlSpecifics typed_url1, typed_url2; | 491 TypedUrlSpecifics typed_url1, typed_url2; |
| 276 WriteToTypedUrlSpecifics(row1, visits1, &typed_url1); | 492 WriteToTypedUrlSpecifics(row1, visits1, &typed_url1); |
| 277 WriteToTypedUrlSpecifics(row2, visits2, &typed_url2); | 493 WriteToTypedUrlSpecifics(row2, visits2, &typed_url2); |
| 278 | 494 |
| 279 // Check that the local cache is still correct. | 495 // Check that the local cache is still correct. |
| 280 VerifyLocalHistoryData({typed_url1, typed_url2}); | 496 VerifyAllLocalHistoryData({typed_url1, typed_url2}); |
| 497 } | |
| 498 | |
| 499 // Add two typed urls locally and verify bridge can get them from GetData. | |
| 500 TEST_F(TypedURLSyncBridgeTest, GetData) { | |
| 501 // Add two urls to backend. | |
| 502 VisitVector visits1, visits2; | |
| 503 URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1); | |
| 504 URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2); | |
| 505 fake_history_backend_->SetVisitsForUrl(row1, visits1); | |
| 506 fake_history_backend_->SetVisitsForUrl(row2, visits2); | |
| 507 | |
| 508 // Create the same data in sync. | |
| 509 TypedUrlSpecifics typed_url1, typed_url2; | |
| 510 WriteToTypedUrlSpecifics(row1, visits1, &typed_url1); | |
| 511 WriteToTypedUrlSpecifics(row2, visits2, &typed_url2); | |
| 512 | |
| 513 // Check that the local cache is still correct. | |
| 514 VerifyGetData({IntToStroageKey(1)}, {typed_url1}); | |
| 515 VerifyGetData({IntToStroageKey(2)}, {typed_url2}); | |
| 281 } | 516 } |
| 282 | 517 |
| 283 // Add a typed url locally and one to sync with the same data. Starting sync | 518 // Add a typed url locally and one to sync with the same data. Starting sync |
| 284 // should result in no changes. | 519 // should result in no changes. |
| 285 TEST_F(TypedURLSyncBridgeTest, MergeUrlNoChange) { | 520 TEST_F(TypedURLSyncBridgeTest, MergeUrlNoChange) { |
| 286 // Add a url to backend. | 521 // Add a url to backend. |
| 287 VisitVector visits; | 522 VisitVector visits; |
| 288 URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); | 523 URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); |
| 289 fake_history_backend_->SetVisitsForUrl(row, visits); | 524 fake_history_backend_->SetVisitsForUrl(row, visits); |
| 290 | 525 |
| 291 // Create the same data in sync. | 526 // Create the same data in sync. |
| 292 sync_pb::EntitySpecifics entity_specifics; | 527 sync_pb::EntitySpecifics entity_specifics; |
| 293 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); | 528 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); |
| 294 WriteToTypedUrlSpecifics(row, visits, typed_url); | 529 WriteToTypedUrlSpecifics(row, visits, typed_url); |
| 295 | 530 |
| 296 StartSyncing({*typed_url}); | 531 StartSyncing({*typed_url}); |
| 297 EXPECT_TRUE(processor().put_multimap().empty()); | 532 EXPECT_TRUE(processor().put_multimap().empty()); |
| 298 | 533 |
| 534 // Even Sync already know the url, bridge still need to tell sync about | |
| 535 // storage keys. | |
| 536 EXPECT_EQ(1u, processor().update_multimap().size()); | |
| 537 | |
| 538 // Verify processor receive correct upate storage key. | |
| 539 const auto& it = processor().update_multimap().begin(); | |
| 540 EXPECT_EQ(it->first, IntToStroageKey(1)); | |
| 541 EXPECT_TRUE(it->second->specifics.has_typed_url()); | |
| 542 EXPECT_EQ(it->second->specifics.typed_url().url(), kURL); | |
| 543 EXPECT_EQ(it->second->specifics.typed_url().title(), kTitle); | |
| 544 | |
| 299 // Check that the local cache was is still correct. | 545 // Check that the local cache was is still correct. |
| 300 VerifyLocalHistoryData({*typed_url}); | 546 VerifyAllLocalHistoryData({*typed_url}); |
| 301 } | 547 } |
| 302 | 548 |
| 303 // Add a corupted typed url locally, has typed url count 1, but no real typed | 549 // Add a corupted typed url locally, has typed url count 1, but no real typed |
| 304 // url visit. Starting sync should not pick up this url. | 550 // url visit. Starting sync should not pick up this url. |
| 305 TEST_F(TypedURLSyncBridgeTest, MergeUrlNoTypedUrl) { | 551 TEST_F(TypedURLSyncBridgeTest, MergeUrlNoTypedUrl) { |
| 306 // Add a url to backend. | 552 // Add a url to backend. |
| 307 VisitVector visits; | 553 VisitVector visits; |
| 308 URLRow row = MakeTypedUrlRow(kURL, kTitle, 0, 3, false, &visits); | 554 URLRow row = MakeTypedUrlRow(kURL, kTitle, 0, 3, false, &visits); |
| 309 | 555 |
| 310 // Mark typed_count to 1 even when there is no typed url visit. | 556 // Mark typed_count to 1 even when there is no typed url visit. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 325 VisitVector visits; | 571 VisitVector visits; |
| 326 URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); | 572 URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); |
| 327 fake_history_backend_->SetVisitsForUrl(row, visits); | 573 fake_history_backend_->SetVisitsForUrl(row, visits); |
| 328 | 574 |
| 329 StartSyncing(std::vector<TypedUrlSpecifics>()); | 575 StartSyncing(std::vector<TypedUrlSpecifics>()); |
| 330 | 576 |
| 331 // Check that the local cache was is still correct. | 577 // Check that the local cache was is still correct. |
| 332 sync_pb::EntitySpecifics entity_specifics; | 578 sync_pb::EntitySpecifics entity_specifics; |
| 333 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); | 579 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); |
| 334 WriteToTypedUrlSpecifics(row, visits, typed_url); | 580 WriteToTypedUrlSpecifics(row, visits, typed_url); |
| 335 VerifyLocalHistoryData({*typed_url}); | 581 VerifyAllLocalHistoryData({*typed_url}); |
| 336 | 582 |
| 337 // Check that the server was updated correctly. | 583 // Check that the server was updated correctly. |
| 338 ASSERT_EQ(1U, processor().put_multimap().size()); | 584 ASSERT_EQ(1U, processor().put_multimap().size()); |
| 339 auto recorded_specifics_iterator = | 585 auto recorded_specifics_iterator = |
| 340 processor().put_multimap().find(GetStorageKey(*typed_url)); | 586 processor().put_multimap().find(GetStorageKey(typed_url->url())); |
| 341 EXPECT_NE(processor().put_multimap().end(), recorded_specifics_iterator); | 587 EXPECT_NE(processor().put_multimap().end(), recorded_specifics_iterator); |
| 342 TypedUrlSpecifics recorded_specifics = | 588 TypedUrlSpecifics recorded_specifics = |
| 343 recorded_specifics_iterator->second->specifics.typed_url(); | 589 recorded_specifics_iterator->second->specifics.typed_url(); |
| 344 | 590 |
| 345 ASSERT_EQ(1, recorded_specifics.visits_size()); | 591 ASSERT_EQ(1, recorded_specifics.visits_size()); |
| 346 EXPECT_EQ(3, recorded_specifics.visits(0)); | 592 EXPECT_EQ(3, recorded_specifics.visits(0)); |
| 347 ASSERT_EQ(1, recorded_specifics.visit_transitions_size()); | 593 ASSERT_EQ(1, recorded_specifics.visit_transitions_size()); |
| 348 EXPECT_EQ(static_cast<const int>(visits[0].transition), | 594 EXPECT_EQ(static_cast<const int>(visits[0].transition), |
| 349 recorded_specifics.visit_transitions(0)); | 595 recorded_specifics.visit_transitions(0)); |
| 350 } | 596 } |
| 351 | 597 |
| 352 // Starting sync with no local data should just push the synced url into the | 598 // Starting sync with no local data should just push the synced url into the |
| 353 // backend. | 599 // backend. |
| 354 TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) { | 600 TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) { |
| 355 // Create the sync data. | 601 // Create the sync data. |
| 356 VisitVector visits; | 602 VisitVector visits; |
| 357 URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); | 603 URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); |
| 358 sync_pb::EntitySpecifics entity_specifics; | 604 sync_pb::EntitySpecifics entity_specifics; |
| 359 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); | 605 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); |
| 360 WriteToTypedUrlSpecifics(row, visits, typed_url); | 606 WriteToTypedUrlSpecifics(row, visits, typed_url); |
| 361 | 607 |
| 362 StartSyncing({*typed_url}); | 608 StartSyncing({*typed_url}); |
| 363 EXPECT_EQ(0u, processor().put_multimap().size()); | 609 EXPECT_EQ(0u, processor().put_multimap().size()); |
| 610 EXPECT_EQ(1u, processor().update_multimap().size()); | |
| 611 | |
| 612 // Verify processor receive correct upate storage key. | |
| 613 const auto& it = processor().update_multimap().begin(); | |
| 614 EXPECT_EQ(it->first, IntToStroageKey(1)); | |
| 615 EXPECT_TRUE(it->second->specifics.has_typed_url()); | |
| 616 EXPECT_EQ(it->second->specifics.typed_url().url(), kURL); | |
| 617 EXPECT_EQ(it->second->specifics.typed_url().title(), kTitle); | |
| 364 | 618 |
| 365 // Check that the backend was updated correctly. | 619 // Check that the backend was updated correctly. |
| 366 VisitVector all_visits; | 620 VisitVector all_visits; |
| 367 base::Time server_time = base::Time::FromInternalValue(3); | 621 base::Time server_time = base::Time::FromInternalValue(3); |
| 368 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | 622 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); |
| 369 ASSERT_NE(0, url_id); | 623 ASSERT_NE(0, url_id); |
| 370 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | 624 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); |
| 371 ASSERT_EQ(1U, all_visits.size()); | 625 ASSERT_EQ(1U, all_visits.size()); |
| 372 EXPECT_EQ(server_time, all_visits[0].visit_time); | 626 EXPECT_EQ(server_time, all_visits[0].visit_time); |
| 373 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | 627 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( |
| 374 all_visits[0].transition, visits[0].transition)); | 628 all_visits[0].transition, visits[0].transition)); |
| 375 } | 629 } |
| 376 | 630 |
| 631 // Add a url to the local and sync data before sync begins, with the sync data | |
| 632 // having more recent visits. Check that starting sync updates the backend | |
| 633 // with the sync visit, while the older local visit is not pushed to sync. | |
| 634 // The title should be updated to the sync version due to the more recent | |
| 635 // timestamp. | |
| 636 TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) { | |
| 637 // Add a url to backend. | |
| 638 VisitVector visits; | |
| 639 URLRow local_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); | |
| 640 fake_history_backend_->SetVisitsForUrl(local_row, visits); | |
| 641 | |
| 642 // Create sync data for the same url with a more recent visit. | |
| 643 VisitVector server_visits; | |
| 644 URLRow server_row = | |
| 645 MakeTypedUrlRow(kURL, kTitle2, 1, 6, false, &server_visits); | |
| 646 server_row.set_id(fake_history_backend_->GetIdByUrl(GURL(kURL))); | |
| 647 sync_pb::EntitySpecifics entity_specifics; | |
| 648 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); | |
| 649 WriteToTypedUrlSpecifics(server_row, server_visits, typed_url); | |
| 650 StartSyncing({*typed_url}); | |
| 651 | |
| 652 // Check that the backend was updated correctly. | |
| 653 VisitVector all_visits; | |
| 654 base::Time server_time = base::Time::FromInternalValue(6); | |
| 655 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 656 ASSERT_NE(0, url_id); | |
| 657 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | |
| 658 ASSERT_EQ(2U, all_visits.size()); | |
| 659 EXPECT_EQ(server_time, all_visits.back().visit_time); | |
| 660 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | |
| 661 all_visits.back().transition, server_visits[0].transition)); | |
| 662 URLRow url_row; | |
| 663 EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row)); | |
| 664 EXPECT_EQ(kTitle2, base::UTF16ToUTF8(url_row.title())); | |
| 665 | |
| 666 // Check that the sync was updated correctly. | |
| 667 // The local history visit should not be added to sync because it is older | |
| 668 // than sync's oldest visit. | |
| 669 ASSERT_EQ(1U, processor().put_multimap().size()); | |
| 670 | |
| 671 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 672 ASSERT_EQ(1, url_specifics.visits_size()); | |
| 673 EXPECT_EQ(6, url_specifics.visits(0)); | |
| 674 ASSERT_EQ(1, url_specifics.visit_transitions_size()); | |
| 675 EXPECT_EQ(static_cast<const int>(visits[0].transition), | |
| 676 url_specifics.visit_transitions(0)); | |
| 677 } | |
| 678 | |
| 679 // Add a url to the local and sync data before sync begins, with the local data | |
| 680 // having more recent visits. Check that starting sync updates the sync | |
| 681 // with the local visits, while the older sync visit is not pushed to the | |
| 682 // backend. Sync's title should be updated to the local version due to the more | |
| 683 // recent timestamp. | |
| 684 TEST_F(TypedURLSyncBridgeTest, MergeUrlOldSync) { | |
| 685 // Add a url to backend. | |
| 686 VisitVector visits; | |
| 687 URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits); | |
| 688 fake_history_backend_->SetVisitsForUrl(local_row, visits); | |
| 689 | |
| 690 // Create sync data for the same url with an older visit. | |
| 691 VisitVector server_visits; | |
| 692 URLRow server_row = | |
| 693 MakeTypedUrlRow(kURL, kTitle, 1, 2, false, &server_visits); | |
| 694 sync_pb::EntitySpecifics entity_specifics; | |
| 695 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); | |
| 696 WriteToTypedUrlSpecifics(server_row, server_visits, typed_url); | |
| 697 StartSyncing({*typed_url}); | |
| 698 | |
| 699 // Check that the backend was not updated. | |
| 700 VisitVector all_visits; | |
| 701 base::Time local_visit_time = base::Time::FromInternalValue(3); | |
| 702 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 703 ASSERT_NE(0, url_id); | |
| 704 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | |
| 705 ASSERT_EQ(1U, all_visits.size()); | |
| 706 EXPECT_EQ(local_visit_time, all_visits[0].visit_time); | |
| 707 | |
| 708 // Check that the server was updated correctly. | |
| 709 // The local history visit should not be added to sync because it is older | |
| 710 // than sync's oldest visit. | |
| 711 ASSERT_EQ(1U, processor().put_multimap().size()); | |
| 712 | |
| 713 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 714 ASSERT_EQ(1, url_specifics.visits_size()); | |
| 715 EXPECT_EQ(3, url_specifics.visits(0)); | |
| 716 EXPECT_EQ(kTitle2, url_specifics.title()); | |
| 717 ASSERT_EQ(1, url_specifics.visit_transitions_size()); | |
| 718 EXPECT_EQ(static_cast<const int>(visits[0].transition), | |
| 719 url_specifics.visit_transitions(0)); | |
| 720 } | |
| 721 | |
| 722 // Check that there is no crash during start sync, if history backend and sync | |
| 723 // have same url, but sync has username/password in it. | |
| 724 // Also check sync will not accept url with username and password. | |
| 725 TEST_F(TypedURLSyncBridgeTest, MergeUrlsWithUsernameAndPassword) { | |
| 726 const char kURLWithUsernameAndPassword[] = | |
| 727 "http://username:password@pie.com/"; | |
| 728 | |
| 729 // Add a url to backend. | |
| 730 VisitVector visits; | |
| 731 URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits); | |
| 732 fake_history_backend_->SetVisitsForUrl(local_row, visits); | |
| 733 | |
| 734 // Create sync data for the same url but contain username and password. | |
| 735 VisitVector server_visits; | |
| 736 URLRow server_row = MakeTypedUrlRow(kURLWithUsernameAndPassword, kTitle, 1, 3, | |
| 737 false, &server_visits); | |
| 738 sync_pb::EntitySpecifics entity_specifics; | |
| 739 sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); | |
| 740 WriteToTypedUrlSpecifics(server_row, server_visits, typed_url); | |
| 741 | |
| 742 // Make sure there is no crash when merge two urls. | |
| 743 StartSyncing({*typed_url}); | |
| 744 | |
| 745 // Notify typed url sync service of the update. | |
| 746 bridge()->OnURLVisited(fake_history_backend_.get(), ui::PAGE_TRANSITION_TYPED, | |
| 747 server_row, RedirectList(), | |
| 748 base::Time::FromInternalValue(7)); | |
| 749 | |
| 750 // Check username/password url is not synced. | |
| 751 ASSERT_EQ(1U, processor().put_multimap().size()); | |
| 752 } | |
| 753 | |
| 377 // Starting sync with both local and sync have same typed URL, but different | 754 // Starting sync with both local and sync have same typed URL, but different |
| 378 // visit. After merge, both local and sync should have two same visits. | 755 // visit. After merge, both local and sync should have two same visits. |
| 379 TEST_F(TypedURLSyncBridgeTest, SimpleMerge) { | 756 TEST_F(TypedURLSyncBridgeTest, SimpleMerge) { |
| 380 // Add a url to backend. | 757 // Add a url to backend. |
| 381 VisitVector visits1; | 758 VisitVector visits1; |
| 382 URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1); | 759 URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1); |
| 383 fake_history_backend_->SetVisitsForUrl(row1, visits1); | 760 fake_history_backend_->SetVisitsForUrl(row1, visits1); |
| 384 | 761 |
| 385 // Create the sync data. | 762 // Create the sync data. |
| 386 VisitVector visits2; | 763 VisitVector visits2; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 399 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | 776 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); |
| 400 ASSERT_EQ(2U, all_visits.size()); | 777 ASSERT_EQ(2U, all_visits.size()); |
| 401 EXPECT_EQ(base::Time::FromInternalValue(3), all_visits[0].visit_time); | 778 EXPECT_EQ(base::Time::FromInternalValue(3), all_visits[0].visit_time); |
| 402 EXPECT_EQ(base::Time::FromInternalValue(4), all_visits[1].visit_time); | 779 EXPECT_EQ(base::Time::FromInternalValue(4), all_visits[1].visit_time); |
| 403 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | 780 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( |
| 404 all_visits[0].transition, visits1[0].transition)); | 781 all_visits[0].transition, visits1[0].transition)); |
| 405 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | 782 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( |
| 406 all_visits[1].transition, visits2[0].transition)); | 783 all_visits[1].transition, visits2[0].transition)); |
| 407 } | 784 } |
| 408 | 785 |
| 786 // Create a local typed URL with one TYPED visit after sync has started. Check | |
| 787 // that sync is sent an ADD change for the new URL. | |
| 788 TEST_F(TypedURLSyncBridgeTest, AddLocalTypedUrl) { | |
| 789 // Create a local typed URL (simulate a typed visit) that is not already | |
| 790 // in sync. Check that sync is sent an ADD change for the existing URL. | |
| 791 URLRows url_rows; | |
| 792 std::vector<VisitVector> visit_vectors; | |
| 793 std::vector<std::string> urls; | |
| 794 urls.push_back(kURL); | |
| 795 | |
| 796 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 797 ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors)); | |
| 798 | |
| 799 URLRow url_row = url_rows.front(); | |
| 800 VisitVector visits = visit_vectors.front(); | |
| 801 | |
| 802 // Check change processor. | |
| 803 ASSERT_EQ(1U, processor().put_multimap().size()); | |
| 804 | |
| 805 // Get typed url specifics. | |
| 806 auto it = processor().put_multimap().begin(); | |
| 807 sync_pb::TypedUrlSpecifics url_specifics = it->second->specifics.typed_url(); | |
| 808 | |
| 809 EXPECT_TRUE(URLsEqual(url_row, url_specifics)); | |
| 810 ASSERT_EQ(1, url_specifics.visits_size()); | |
| 811 ASSERT_EQ(static_cast<const int>(visits.size()), url_specifics.visits_size()); | |
| 812 EXPECT_EQ(visits[0].visit_time.ToInternalValue(), url_specifics.visits(0)); | |
| 813 EXPECT_EQ(static_cast<const int>(visits[0].transition), | |
| 814 url_specifics.visit_transitions(0)); | |
| 815 } | |
| 816 | |
| 817 // Update a local typed URL that is already synced. Check that sync is sent an | |
| 818 // UPDATE for the existing url, but RELOAD visits aren't synced. | |
| 819 TEST_F(TypedURLSyncBridgeTest, UpdateLocalTypedUrl) { | |
| 820 URLRows url_rows; | |
| 821 std::vector<VisitVector> visit_vectors; | |
| 822 std::vector<std::string> urls; | |
| 823 urls.push_back(kURL); | |
| 824 | |
| 825 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 826 | |
| 827 // Update the URL row, adding another typed visit to the visit vector. | |
| 828 URLRows changed_urls; | |
| 829 VisitVector visits; | |
| 830 URLRow url_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); | |
| 831 AddNewestVisit(ui::PAGE_TRANSITION_TYPED, 7, &url_row, &visits); | |
| 832 AddNewestVisit(ui::PAGE_TRANSITION_RELOAD, 8, &url_row, &visits); | |
| 833 AddNewestVisit(ui::PAGE_TRANSITION_LINK, 9, &url_row, &visits); | |
| 834 fake_history_backend_->SetVisitsForUrl(url_row, visits); | |
| 835 changed_urls.push_back(url_row); | |
| 836 | |
| 837 // Notify typed url sync service of the update. | |
| 838 const auto& changes_multimap = processor().put_multimap(); | |
| 839 ASSERT_EQ(0U, changes_multimap.size()); | |
| 840 bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls); | |
| 841 ASSERT_EQ(1U, changes_multimap.size()); | |
| 842 | |
| 843 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 844 EXPECT_TRUE(URLsEqual(url_row, url_specifics)); | |
| 845 ASSERT_EQ(3, url_specifics.visits_size()); | |
| 846 | |
| 847 // Check that each visit has been translated/communicated correctly. | |
| 848 // Note that the specifics record visits in chronological order, and the | |
| 849 // visits from the db are in reverse chronological order. | |
| 850 EXPECT_EQ(visits[0].visit_time.ToInternalValue(), url_specifics.visits(2)); | |
| 851 EXPECT_EQ(static_cast<const int>(visits[0].transition), | |
| 852 url_specifics.visit_transitions(2)); | |
| 853 EXPECT_EQ(visits[2].visit_time.ToInternalValue(), url_specifics.visits(1)); | |
| 854 EXPECT_EQ(static_cast<const int>(visits[2].transition), | |
| 855 url_specifics.visit_transitions(1)); | |
| 856 EXPECT_EQ(visits[3].visit_time.ToInternalValue(), url_specifics.visits(0)); | |
| 857 EXPECT_EQ(static_cast<const int>(visits[3].transition), | |
| 858 url_specifics.visit_transitions(0)); | |
| 859 } | |
| 860 | |
| 861 // Append a RELOAD visit to a typed url that is already synced. Check that sync | |
| 862 // does not receive any updates. | |
| 863 TEST_F(TypedURLSyncBridgeTest, ReloadVisitLocalTypedUrl) { | |
| 864 URLRows url_rows; | |
| 865 std::vector<VisitVector> visit_vectors; | |
| 866 std::vector<std::string> urls; | |
| 867 urls.push_back(kURL); | |
| 868 | |
| 869 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 870 ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors)); | |
| 871 const auto& changes_multimap = processor().put_multimap(); | |
| 872 ASSERT_EQ(1U, changes_multimap.size()); | |
| 873 | |
| 874 // Update the URL row, adding another typed visit to the visit vector. | |
| 875 URLRow url_row = url_rows.front(); | |
| 876 URLRows changed_urls; | |
| 877 VisitVector new_visits; | |
| 878 AddNewestVisit(ui::PAGE_TRANSITION_RELOAD, 7, &url_row, &new_visits); | |
| 879 fake_history_backend_->SetVisitsForUrl(url_row, new_visits); | |
| 880 changed_urls.push_back(url_row); | |
| 881 | |
| 882 // Notify typed url sync service of the update. | |
| 883 bridge()->OnURLVisited(fake_history_backend_.get(), | |
| 884 ui::PAGE_TRANSITION_RELOAD, url_row, RedirectList(), | |
| 885 base::Time::FromInternalValue(7)); | |
| 886 // No change pass to processor | |
| 887 ASSERT_EQ(1U, changes_multimap.size()); | |
| 888 } | |
| 889 | |
| 890 // Appends a LINK visit to an existing typed url. Check that sync does not | |
| 891 // receive any changes. | |
| 892 TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) { | |
| 893 URLRows url_rows; | |
| 894 std::vector<VisitVector> visit_vectors; | |
| 895 std::vector<std::string> urls; | |
| 896 urls.push_back(kURL); | |
| 897 | |
| 898 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 899 ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors)); | |
| 900 const auto& changes_multimap = processor().put_multimap(); | |
| 901 ASSERT_EQ(1U, changes_multimap.size()); | |
| 902 | |
| 903 // Update the URL row, adding a non-typed visit to the visit vector. | |
| 904 URLRow url_row = url_rows.front(); | |
| 905 VisitVector new_visits; | |
| 906 AddNewestVisit(ui::PAGE_TRANSITION_LINK, 6, &url_row, &new_visits); | |
| 907 fake_history_backend_->SetVisitsForUrl(url_row, new_visits); | |
| 908 | |
| 909 ui::PageTransition transition = ui::PAGE_TRANSITION_LINK; | |
| 910 // Notify typed url sync service of non-typed visit, expect no change. | |
| 911 bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row, | |
| 912 RedirectList(), base::Time::FromInternalValue(6)); | |
| 913 // No change pass to processor | |
| 914 ASSERT_EQ(1U, changes_multimap.size()); | |
| 915 } | |
| 916 | |
| 917 // Appends a series of LINK visits followed by a TYPED one to an existing typed | |
| 918 // url. Check that sync receives an UPDATE with the newest visit data. | |
| 919 TEST_F(TypedURLSyncBridgeTest, TypedVisitLocalTypedUrl) { | |
| 920 URLRows url_rows; | |
| 921 std::vector<VisitVector> visit_vectors; | |
| 922 std::vector<std::string> urls; | |
| 923 urls.push_back(kURL); | |
| 924 | |
| 925 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 926 | |
| 927 // Update the URL row, adding another typed visit to the visit vector. | |
| 928 VisitVector visits; | |
| 929 URLRow url_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits); | |
| 930 AddOldestVisit(ui::PAGE_TRANSITION_LINK, 1, &url_row, &visits); | |
| 931 AddNewestVisit(ui::PAGE_TRANSITION_LINK, 6, &url_row, &visits); | |
| 932 AddNewestVisit(ui::PAGE_TRANSITION_TYPED, 7, &url_row, &visits); | |
| 933 fake_history_backend_->SetVisitsForUrl(url_row, visits); | |
| 934 | |
| 935 // Notify typed url sync service of typed visit. | |
| 936 const auto& changes_multimap = processor().put_multimap(); | |
| 937 ASSERT_EQ(0U, changes_multimap.size()); | |
| 938 ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED; | |
| 939 bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row, | |
| 940 RedirectList(), base::Time::Now()); | |
| 941 | |
| 942 ASSERT_EQ(1U, changes_multimap.size()); | |
| 943 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 944 | |
| 945 EXPECT_TRUE(URLsEqual(url_row, url_specifics)); | |
| 946 EXPECT_EQ(4, url_specifics.visits_size()); | |
| 947 | |
| 948 // Check that each visit has been translated/communicated correctly. | |
| 949 // Note that the specifics record visits in chronological order, and the | |
| 950 // visits from the db are in reverse chronological order. | |
| 951 int r = url_specifics.visits_size() - 1; | |
| 952 for (int i = 0; i < url_specifics.visits_size(); ++i, --r) { | |
| 953 EXPECT_EQ(visits[i].visit_time.ToInternalValue(), url_specifics.visits(r)); | |
| 954 EXPECT_EQ(static_cast<const int>(visits[i].transition), | |
| 955 url_specifics.visit_transitions(r)); | |
| 956 } | |
| 957 } | |
| 958 | |
| 959 // Delete several (but not all) local typed urls. Check that sync receives the | |
| 960 // DELETE changes, and the non-deleted urls remain synced. | |
| 961 TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) { | |
| 962 URLRows url_rows; | |
| 963 std::vector<VisitVector> visit_vectors; | |
| 964 std::vector<std::string> urls; | |
| 965 urls.push_back("http://pie.com/"); | |
| 966 urls.push_back("http://cake.com/"); | |
| 967 urls.push_back("http://google.com/"); | |
| 968 urls.push_back("http://foo.com/"); | |
| 969 urls.push_back("http://bar.com/"); | |
| 970 | |
| 971 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 972 ASSERT_TRUE(BuildAndPushLocalChanges(4, 1, urls, &url_rows, &visit_vectors)); | |
| 973 const auto& changes_multimap = processor().put_multimap(); | |
| 974 ASSERT_EQ(4U, changes_multimap.size()); | |
| 975 | |
| 976 // Simulate visit expiry of typed visit, no syncing is done | |
| 977 // This is to test that sync relies on the in-memory cache to know | |
| 978 // which urls were typed and synced, and should be deleted. | |
| 979 url_rows[0].set_typed_count(0); | |
| 980 VisitVector visits; | |
| 981 fake_history_backend_->SetVisitsForUrl(url_rows[0], visits); | |
| 982 | |
| 983 // Delete some urls from backend and create deleted row vector. | |
| 984 URLRows rows; | |
| 985 std::set<std::string> deleted_storage_keys; | |
| 986 for (size_t i = 0; i < 3u; ++i) { | |
| 987 std::string storage_key = GetStorageKey(url_rows[i].url().spec()); | |
| 988 deleted_storage_keys.insert(storage_key); | |
| 989 fake_history_backend_->DeleteURL(url_rows[i].url()); | |
| 990 rows.push_back(url_rows[i]); | |
| 991 } | |
| 992 | |
| 993 // Notify typed url sync service. | |
| 994 bridge()->OnURLsDeleted(fake_history_backend_.get(), false, false, rows, | |
| 995 std::set<GURL>()); | |
| 996 | |
| 997 const auto& delete_set = processor().delete_set(); | |
| 998 ASSERT_EQ(3U, delete_set.size()); | |
| 999 for (const std::string& storage_key : delete_set) { | |
| 1000 EXPECT_TRUE(deleted_storage_keys.find(storage_key) != | |
| 1001 deleted_storage_keys.end()); | |
| 1002 deleted_storage_keys.erase(storage_key); | |
| 1003 } | |
| 1004 ASSERT_TRUE(deleted_storage_keys.empty()); | |
| 1005 } | |
| 1006 | |
| 1007 // Saturate the visits for a typed url with both TYPED and LINK navigations. | |
| 1008 // Check that no more than kMaxTypedURLVisits are synced, and that LINK visits | |
| 1009 // are dropped rather than TYPED ones. | |
| 1010 TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) { | |
| 1011 URLRows url_rows; | |
| 1012 std::vector<VisitVector> visit_vectors; | |
| 1013 std::vector<std::string> urls; | |
| 1014 urls.push_back(kURL); | |
| 1015 | |
| 1016 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1017 ASSERT_TRUE(BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors)); | |
| 1018 const auto& changes_multimap = processor().put_multimap(); | |
| 1019 ASSERT_EQ(0U, changes_multimap.size()); | |
| 1020 | |
| 1021 URLRow url_row = url_rows.front(); | |
| 1022 VisitVector visits; | |
| 1023 | |
| 1024 // Add |kMaxTypedUrlVisits| + 10 visits to the url. The 10 oldest | |
| 1025 // non-typed visits are expected to be skipped. | |
| 1026 int i = 1; | |
| 1027 for (; i <= kMaxTypedUrlVisits - 20; ++i) | |
| 1028 AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits); | |
| 1029 for (; i <= kMaxTypedUrlVisits; ++i) | |
| 1030 AddNewestVisit(ui::PAGE_TRANSITION_LINK, i, &url_row, &visits); | |
| 1031 for (; i <= kMaxTypedUrlVisits + 10; ++i) | |
| 1032 AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits); | |
| 1033 | |
| 1034 fake_history_backend_->SetVisitsForUrl(url_row, visits); | |
| 1035 | |
| 1036 // Notify typed url sync service of typed visit. | |
| 1037 ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED; | |
| 1038 bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row, | |
| 1039 RedirectList(), base::Time::Now()); | |
| 1040 | |
| 1041 ASSERT_EQ(1U, changes_multimap.size()); | |
| 1042 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 1043 ASSERT_EQ(kMaxTypedUrlVisits, url_specifics.visits_size()); | |
| 1044 | |
| 1045 // Check that each visit has been translated/communicated correctly. | |
| 1046 // Note that the specifics records visits in chronological order, and the | |
| 1047 // visits from the db are in reverse chronological order. | |
| 1048 int num_typed_visits_synced = 0; | |
| 1049 int num_other_visits_synced = 0; | |
| 1050 int r = url_specifics.visits_size() - 1; | |
| 1051 for (int i = 0; i < url_specifics.visits_size(); ++i, --r) { | |
| 1052 if (url_specifics.visit_transitions(i) == | |
| 1053 static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED)) { | |
| 1054 ++num_typed_visits_synced; | |
| 1055 } else { | |
| 1056 ++num_other_visits_synced; | |
| 1057 } | |
| 1058 } | |
| 1059 EXPECT_EQ(kMaxTypedUrlVisits - 10, num_typed_visits_synced); | |
| 1060 EXPECT_EQ(10, num_other_visits_synced); | |
| 1061 } | |
| 1062 | |
| 1063 // Add enough visits to trigger throttling of updates to a typed url. Check that | |
| 1064 // sync does not receive an update until the proper throttle interval has been | |
| 1065 // reached. | |
| 1066 TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) { | |
| 1067 URLRows url_rows; | |
| 1068 std::vector<VisitVector> visit_vectors; | |
| 1069 std::vector<std::string> urls; | |
| 1070 urls.push_back(kURL); | |
| 1071 | |
| 1072 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1073 ASSERT_TRUE(BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors)); | |
| 1074 const auto& changes_multimap = processor().put_multimap(); | |
| 1075 ASSERT_EQ(0U, changes_multimap.size()); | |
| 1076 | |
| 1077 URLRow url_row = url_rows.front(); | |
| 1078 VisitVector visits; | |
| 1079 | |
| 1080 // Add enough visits to the url so that typed count is above the throttle | |
| 1081 // limit, and not right on the interval that gets synced. | |
| 1082 int i = 1; | |
| 1083 for (; i < kVisitThrottleThreshold + kVisitThrottleMultiple / 2; ++i) | |
| 1084 AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits); | |
| 1085 fake_history_backend_->SetVisitsForUrl(url_row, visits); | |
| 1086 | |
| 1087 // Notify typed url sync service of typed visit. | |
| 1088 ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED; | |
| 1089 bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row, | |
| 1090 RedirectList(), base::Time::Now()); | |
| 1091 | |
| 1092 // Should throttle, so sync and local cache should not update. | |
| 1093 ASSERT_EQ(0U, changes_multimap.size()); | |
| 1094 | |
| 1095 visits.clear(); | |
| 1096 for (; i % kVisitThrottleMultiple != 1; ++i) | |
| 1097 AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits); | |
| 1098 --i; // Account for the increment before the condition ends. | |
| 1099 fake_history_backend_->SetVisitsForUrl(url_row, visits); | |
| 1100 | |
| 1101 // Notify typed url sync service of typed visit. | |
| 1102 bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row, | |
| 1103 RedirectList(), base::Time::Now()); | |
| 1104 | |
| 1105 ASSERT_EQ(1U, changes_multimap.size()); | |
| 1106 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 1107 ASSERT_EQ(i, url_specifics.visits_size()); | |
| 1108 } | |
| 1109 | |
| 1110 // Create a remote typed URL and visit, then send to sync bridge after sync | |
| 1111 // has started. Check that local DB is received the new URL and visit. | |
| 1112 TEST_F(TypedURLSyncBridgeTest, AddUrlAndVisits) { | |
| 1113 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1114 VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false, | |
| 1115 EntityChange::ACTION_ADD); | |
| 1116 | |
| 1117 ASSERT_EQ(0U, processor().put_multimap().size()); | |
| 1118 ASSERT_EQ(1U, processor().update_multimap().size()); | |
| 1119 ASSERT_EQ(0U, processor().untrack_set().size()); | |
| 1120 | |
| 1121 // Verify processor receive correct upate storage key. | |
| 1122 const auto& it = processor().update_multimap().begin(); | |
| 1123 EXPECT_EQ(it->first, IntToStroageKey(1)); | |
| 1124 EXPECT_TRUE(it->second->specifics.has_typed_url()); | |
| 1125 EXPECT_EQ(it->second->specifics.typed_url().url(), kURL); | |
| 1126 EXPECT_EQ(it->second->specifics.typed_url().title(), kTitle); | |
| 1127 | |
| 1128 base::Time visit_time = base::Time::FromInternalValue(3); | |
| 1129 VisitVector all_visits; | |
| 1130 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 1131 ASSERT_NE(0, url_id); | |
| 1132 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | |
| 1133 EXPECT_EQ(1U, all_visits.size()); | |
| 1134 EXPECT_EQ(visit_time, all_visits[0].visit_time); | |
| 1135 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | |
| 1136 all_visits[0].transition, visits[0].transition)); | |
| 1137 URLRow url_row; | |
| 1138 EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row)); | |
| 1139 EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title())); | |
| 1140 } | |
| 1141 | |
| 1142 // Create a remote typed URL with expired visit, then send to sync bridge after | |
| 1143 // sync has started. Check that local DB did not receive the expired URL and | |
| 1144 // visit. | |
| 1145 TEST_F(TypedURLSyncBridgeTest, AddExpiredUrlAndVisits) { | |
| 1146 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1147 VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, kExpiredVisit, | |
| 1148 false, EntityChange::ACTION_ADD); | |
| 1149 | |
| 1150 ASSERT_EQ(0U, processor().put_multimap().size()); | |
| 1151 ASSERT_EQ(0U, processor().update_multimap().size()); | |
| 1152 ASSERT_EQ(1U, processor().untrack_set().size()); | |
| 1153 | |
| 1154 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 1155 ASSERT_EQ(0, url_id); | |
| 1156 } | |
| 1157 | |
| 1158 // Update a remote typed URL and create a new visit that is already synced, then | |
| 1159 // send the update to sync bridge. Check that local DB is received an | |
| 1160 // UPDATE for the existing url and new visit. | |
| 1161 TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) { | |
| 1162 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1163 | |
| 1164 VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false, | |
| 1165 EntityChange::ACTION_ADD); | |
| 1166 base::Time visit_time = base::Time::FromInternalValue(3); | |
| 1167 VisitVector all_visits; | |
| 1168 URLRow url_row; | |
| 1169 | |
| 1170 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 1171 ASSERT_NE(0, url_id); | |
| 1172 | |
| 1173 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | |
| 1174 | |
| 1175 EXPECT_EQ(1U, all_visits.size()); | |
| 1176 EXPECT_EQ(visit_time, all_visits[0].visit_time); | |
| 1177 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | |
| 1178 all_visits[0].transition, visits[0].transition)); | |
| 1179 EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row)); | |
| 1180 EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title())); | |
| 1181 | |
| 1182 VisitVector new_visits = ApplyUrlAndVisitsChange(kURL, kTitle2, 2, 6, false, | |
| 1183 EntityChange::ACTION_UPDATE); | |
| 1184 | |
| 1185 base::Time new_visit_time = base::Time::FromInternalValue(6); | |
| 1186 url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 1187 ASSERT_NE(0, url_id); | |
| 1188 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | |
| 1189 | |
| 1190 EXPECT_EQ(2U, all_visits.size()); | |
| 1191 EXPECT_EQ(new_visit_time, all_visits.back().visit_time); | |
| 1192 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | |
| 1193 all_visits.back().transition, new_visits[0].transition)); | |
| 1194 EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row)); | |
| 1195 EXPECT_EQ(kTitle2, base::UTF16ToUTF8(url_row.title())); | |
| 1196 } | |
| 1197 | |
| 1198 // Delete a typed urls which already synced. Check that local DB receives the | |
| 1199 // DELETE changes. | |
| 1200 TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) { | |
| 1201 URLRows url_rows; | |
| 1202 std::vector<VisitVector> visit_vectors; | |
| 1203 std::vector<std::string> urls; | |
| 1204 urls.push_back(kURL); | |
| 1205 | |
| 1206 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1207 ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors)); | |
| 1208 const auto& changes_multimap = processor().put_multimap(); | |
| 1209 ASSERT_EQ(1U, changes_multimap.size()); | |
| 1210 | |
| 1211 base::Time visit_time = base::Time::FromInternalValue(3); | |
| 1212 VisitVector all_visits; | |
| 1213 URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 1214 ASSERT_NE(0, url_id); | |
| 1215 fake_history_backend_->GetVisitsForURL(url_id, &all_visits); | |
| 1216 EXPECT_EQ(1U, all_visits.size()); | |
| 1217 EXPECT_EQ(visit_time, all_visits[0].visit_time); | |
| 1218 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | |
| 1219 all_visits[0].transition, visit_vectors[0][0].transition)); | |
| 1220 URLRow url_row; | |
| 1221 EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row)); | |
| 1222 EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title())); | |
| 1223 | |
| 1224 // Add observer back to check if TypedUrlSyncBridge receive delete | |
| 1225 // changes back from fake_history_backend_. | |
| 1226 AddObserver(); | |
| 1227 | |
| 1228 ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false, | |
| 1229 EntityChange::ACTION_DELETE); | |
| 1230 | |
| 1231 EXPECT_FALSE(fake_history_backend_->GetURL(GURL(kURL), &url_row)); | |
| 1232 url_id = fake_history_backend_->GetIdByUrl(GURL(kURL)); | |
| 1233 ASSERT_EQ(0, url_id); | |
| 1234 | |
| 1235 // Check TypedUrlSyncBridge did not receive update since the update is | |
| 1236 // trigered by it. | |
| 1237 ASSERT_EQ(1U, changes_multimap.size()); | |
| 1238 } | |
| 1239 | |
| 1240 // Create two set of visits for history DB and sync DB, two same set of visits | |
| 1241 // are same. Check DiffVisits will return empty set of diff visits. | |
| 1242 TEST_F(TypedURLSyncBridgeTest, DiffVisitsSame) { | |
| 1243 VisitVector old_visits; | |
| 1244 sync_pb::TypedUrlSpecifics new_url; | |
| 1245 | |
| 1246 const int64_t visits[] = {1024, 2065, 65534, 1237684}; | |
| 1247 | |
| 1248 for (int64_t visit : visits) { | |
| 1249 old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0, | |
| 1250 ui::PAGE_TRANSITION_TYPED, 0)); | |
| 1251 new_url.add_visits(visit); | |
| 1252 new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED); | |
| 1253 } | |
| 1254 | |
| 1255 std::vector<VisitInfo> new_visits; | |
| 1256 VisitVector removed_visits; | |
| 1257 | |
| 1258 DiffVisits(old_visits, new_url, &new_visits, &removed_visits); | |
| 1259 EXPECT_TRUE(new_visits.empty()); | |
| 1260 EXPECT_TRUE(removed_visits.empty()); | |
| 1261 } | |
| 1262 | |
| 1263 // Create two set of visits for history DB and sync DB. Check DiffVisits will | |
| 1264 // return correct set of diff visits. | |
| 1265 TEST_F(TypedURLSyncBridgeTest, DiffVisitsRemove) { | |
| 1266 VisitVector old_visits; | |
| 1267 sync_pb::TypedUrlSpecifics new_url; | |
| 1268 | |
| 1269 const int64_t visits_left[] = {1, 2, 1024, 1500, 2065, | |
| 1270 6000, 65534, 1237684, 2237684}; | |
| 1271 const int64_t visits_right[] = {1024, 2065, 65534, 1237684}; | |
| 1272 | |
| 1273 // DiffVisits will not remove the first visit, because we never delete visits | |
| 1274 // from the start of the array (since those visits can get truncated by the | |
| 1275 // size-limiting code). | |
| 1276 const int64_t visits_removed[] = {1500, 6000, 2237684}; | |
| 1277 | |
| 1278 for (int64_t visit : visits_left) { | |
| 1279 old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0, | |
| 1280 ui::PAGE_TRANSITION_TYPED, 0)); | |
| 1281 } | |
| 1282 | |
| 1283 for (int64_t visit : visits_right) { | |
| 1284 new_url.add_visits(visit); | |
| 1285 new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED); | |
| 1286 } | |
| 1287 | |
| 1288 std::vector<VisitInfo> new_visits; | |
| 1289 VisitVector removed_visits; | |
| 1290 | |
| 1291 DiffVisits(old_visits, new_url, &new_visits, &removed_visits); | |
| 1292 EXPECT_TRUE(new_visits.empty()); | |
| 1293 ASSERT_EQ(removed_visits.size(), arraysize(visits_removed)); | |
| 1294 for (size_t i = 0; i < arraysize(visits_removed); ++i) { | |
| 1295 EXPECT_EQ(removed_visits[i].visit_time.ToInternalValue(), | |
| 1296 visits_removed[i]); | |
| 1297 } | |
| 1298 } | |
| 1299 | |
| 1300 // Create two set of visits for history DB and sync DB. Check DiffVisits will | |
| 1301 // return correct set of diff visits. | |
| 1302 TEST_F(TypedURLSyncBridgeTest, DiffVisitsAdd) { | |
| 1303 VisitVector old_visits; | |
| 1304 sync_pb::TypedUrlSpecifics new_url; | |
| 1305 | |
| 1306 const int64_t visits_left[] = {1024, 2065, 65534, 1237684}; | |
| 1307 const int64_t visits_right[] = {1, 1024, 1500, 2065, | |
| 1308 6000, 65534, 1237684, 2237684}; | |
| 1309 | |
| 1310 const int64_t visits_added[] = {1, 1500, 6000, 2237684}; | |
| 1311 | |
| 1312 for (int64_t visit : visits_left) { | |
| 1313 old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0, | |
| 1314 ui::PAGE_TRANSITION_TYPED, 0)); | |
| 1315 } | |
| 1316 | |
| 1317 for (int64_t visit : visits_right) { | |
| 1318 new_url.add_visits(visit); | |
| 1319 new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED); | |
| 1320 } | |
| 1321 | |
| 1322 std::vector<VisitInfo> new_visits; | |
| 1323 VisitVector removed_visits; | |
| 1324 | |
| 1325 DiffVisits(old_visits, new_url, &new_visits, &removed_visits); | |
| 1326 EXPECT_TRUE(removed_visits.empty()); | |
| 1327 ASSERT_TRUE(new_visits.size() == arraysize(visits_added)); | |
| 1328 for (size_t i = 0; i < arraysize(visits_added); ++i) { | |
| 1329 EXPECT_EQ(new_visits[i].first.ToInternalValue(), visits_added[i]); | |
| 1330 EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( | |
| 1331 new_visits[i].second, ui::PAGE_TRANSITION_TYPED)); | |
| 1332 } | |
| 1333 } | |
| 1334 | |
| 1335 // Create three visits, check RELOAD visit is removed by | |
| 1336 // WriteToTypedUrlSpecifics so it won't apply to sync DB. | |
| 1337 TEST_F(TypedURLSyncBridgeTest, WriteTypedUrlSpecifics) { | |
| 1338 VisitVector visits; | |
| 1339 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, 1)); | |
| 1340 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, 2)); | |
| 1341 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, 3)); | |
| 1342 | |
| 1343 URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, 100, false, &visits)); | |
| 1344 sync_pb::TypedUrlSpecifics typed_url; | |
| 1345 WriteToTypedUrlSpecifics(url, visits, &typed_url); | |
| 1346 // RELOAD visits should be removed. | |
| 1347 EXPECT_EQ(2, typed_url.visits_size()); | |
| 1348 EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size()); | |
| 1349 EXPECT_EQ(1, typed_url.visits(0)); | |
| 1350 EXPECT_EQ(3, typed_url.visits(1)); | |
| 1351 EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED), | |
| 1352 typed_url.visit_transitions(0)); | |
| 1353 EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_LINK), | |
| 1354 typed_url.visit_transitions(1)); | |
| 1355 } | |
| 1356 | |
| 1357 // Create 101 visits, check WriteToTypedUrlSpecifics will only keep 100 visits. | |
| 1358 TEST_F(TypedURLSyncBridgeTest, TooManyVisits) { | |
| 1359 VisitVector visits; | |
| 1360 int64_t timestamp = 1000; | |
| 1361 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++)); | |
| 1362 for (int i = 0; i < 100; ++i) { | |
| 1363 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++)); | |
| 1364 } | |
| 1365 URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, timestamp++, false, &visits)); | |
| 1366 sync_pb::TypedUrlSpecifics typed_url; | |
| 1367 WriteToTypedUrlSpecifics(url, visits, &typed_url); | |
| 1368 // # visits should be capped at 100. | |
| 1369 EXPECT_EQ(100, typed_url.visits_size()); | |
| 1370 EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size()); | |
| 1371 EXPECT_EQ(1000, typed_url.visits(0)); | |
| 1372 // Visit with timestamp of 1001 should be omitted since we should have | |
| 1373 // skipped that visit to stay under the cap. | |
| 1374 EXPECT_EQ(1002, typed_url.visits(1)); | |
| 1375 EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED), | |
| 1376 typed_url.visit_transitions(0)); | |
| 1377 EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_LINK), | |
| 1378 typed_url.visit_transitions(1)); | |
| 1379 } | |
| 1380 | |
| 1381 // Create 306 visits, check WriteToTypedUrlSpecifics will only keep 100 typed | |
| 1382 // visits. | |
| 1383 TEST_F(TypedURLSyncBridgeTest, TooManyTypedVisits) { | |
| 1384 VisitVector visits; | |
| 1385 int64_t timestamp = 1000; | |
| 1386 for (int i = 0; i < 102; ++i) { | |
| 1387 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++)); | |
| 1388 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++)); | |
| 1389 visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, timestamp++)); | |
| 1390 } | |
| 1391 URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, timestamp++, false, &visits)); | |
| 1392 sync_pb::TypedUrlSpecifics typed_url; | |
| 1393 WriteToTypedUrlSpecifics(url, visits, &typed_url); | |
| 1394 // # visits should be capped at 100. | |
| 1395 EXPECT_EQ(100, typed_url.visits_size()); | |
| 1396 EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size()); | |
| 1397 // First two typed visits should be skipped. | |
| 1398 EXPECT_EQ(1006, typed_url.visits(0)); | |
| 1399 | |
| 1400 // Ensure there are no non-typed visits since that's all that should fit. | |
| 1401 for (int i = 0; i < typed_url.visits_size(); ++i) { | |
| 1402 EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED), | |
| 1403 typed_url.visit_transitions(i)); | |
| 1404 } | |
| 1405 } | |
| 1406 | |
| 1407 // Create a typed url without visit, check WriteToTypedUrlSpecifics will return | |
| 1408 // false for it. | |
| 1409 TEST_F(TypedURLSyncBridgeTest, NoTypedVisits) { | |
| 1410 VisitVector visits; | |
| 1411 URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, 1000, false, &visits)); | |
| 1412 sync_pb::TypedUrlSpecifics typed_url; | |
| 1413 EXPECT_FALSE(WriteToTypedUrlSpecifics(url, visits, &typed_url)); | |
| 1414 // URLs with no typed URL visits should not been written to specifics. | |
| 1415 EXPECT_EQ(0, typed_url.visits_size()); | |
| 1416 } | |
| 1417 | |
| 1418 TEST_F(TypedURLSyncBridgeTest, MergeUrls) { | |
| 1419 VisitVector visits1; | |
| 1420 URLRow row1(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits1)); | |
| 1421 sync_pb::TypedUrlSpecifics specs1( | |
| 1422 MakeTypedUrlSpecifics(kURL, kTitle, 3, false)); | |
| 1423 URLRow new_row1((GURL(kURL))); | |
| 1424 std::vector<VisitInfo> new_visits1; | |
| 1425 EXPECT_TRUE(TypedURLSyncBridgeTest::MergeUrls(specs1, row1, &visits1, | |
| 1426 &new_row1, &new_visits1) == | |
| 1427 TypedURLSyncBridgeTest::DIFF_NONE); | |
| 1428 | |
| 1429 VisitVector visits2; | |
| 1430 URLRow row2(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits2)); | |
| 1431 sync_pb::TypedUrlSpecifics specs2( | |
| 1432 MakeTypedUrlSpecifics(kURL, kTitle, 3, true)); | |
| 1433 VisitVector expected_visits2; | |
| 1434 URLRow expected2( | |
| 1435 MakeTypedUrlRow(kURL, kTitle, 2, 3, true, &expected_visits2)); | |
| 1436 URLRow new_row2((GURL(kURL))); | |
| 1437 std::vector<VisitInfo> new_visits2; | |
| 1438 EXPECT_TRUE(TypedURLSyncBridgeTest::MergeUrls(specs2, row2, &visits2, | |
| 1439 &new_row2, &new_visits2) == | |
| 1440 TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED); | |
| 1441 EXPECT_TRUE(URLsEqual(new_row2, expected2)); | |
| 1442 | |
| 1443 VisitVector visits3; | |
| 1444 URLRow row3(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits3)); | |
| 1445 sync_pb::TypedUrlSpecifics specs3( | |
| 1446 MakeTypedUrlSpecifics(kURL, kTitle2, 3, true)); | |
| 1447 VisitVector expected_visits3; | |
| 1448 URLRow expected3( | |
| 1449 MakeTypedUrlRow(kURL, kTitle2, 2, 3, true, &expected_visits3)); | |
| 1450 URLRow new_row3((GURL(kURL))); | |
| 1451 std::vector<VisitInfo> new_visits3; | |
| 1452 EXPECT_EQ(TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED | | |
| 1453 TypedURLSyncBridgeTest::DIFF_NONE, | |
| 1454 TypedURLSyncBridgeTest::MergeUrls(specs3, row3, &visits3, &new_row3, | |
| 1455 &new_visits3)); | |
| 1456 EXPECT_TRUE(URLsEqual(new_row3, expected3)); | |
| 1457 | |
| 1458 // Create one node in history DB with timestamp of 3, and one node in sync | |
| 1459 // DB with timestamp of 4. Result should contain one new item (4). | |
| 1460 VisitVector visits4; | |
| 1461 URLRow row4(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits4)); | |
| 1462 sync_pb::TypedUrlSpecifics specs4( | |
| 1463 MakeTypedUrlSpecifics(kURL, kTitle2, 4, false)); | |
| 1464 VisitVector expected_visits4; | |
| 1465 URLRow expected4( | |
| 1466 MakeTypedUrlRow(kURL, kTitle2, 2, 4, false, &expected_visits4)); | |
| 1467 URLRow new_row4((GURL(kURL))); | |
| 1468 std::vector<VisitInfo> new_visits4; | |
| 1469 EXPECT_EQ(TypedURLSyncBridgeTest::DIFF_UPDATE_NODE | | |
| 1470 TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED | | |
| 1471 TypedURLSyncBridgeTest::DIFF_LOCAL_VISITS_ADDED, | |
| 1472 TypedURLSyncBridgeTest::MergeUrls(specs4, row4, &visits4, &new_row4, | |
| 1473 &new_visits4)); | |
| 1474 EXPECT_EQ(1U, new_visits4.size()); | |
| 1475 EXPECT_EQ(specs4.visits(0), new_visits4[0].first.ToInternalValue()); | |
| 1476 EXPECT_TRUE(URLsEqual(new_row4, expected4)); | |
| 1477 EXPECT_EQ(2U, visits4.size()); | |
| 1478 | |
| 1479 VisitVector visits5; | |
| 1480 URLRow row5(MakeTypedUrlRow(kURL, kTitle, 1, 4, false, &visits5)); | |
| 1481 sync_pb::TypedUrlSpecifics specs5( | |
| 1482 MakeTypedUrlSpecifics(kURL, kTitle, 3, false)); | |
| 1483 VisitVector expected_visits5; | |
| 1484 URLRow expected5( | |
| 1485 MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &expected_visits5)); | |
| 1486 URLRow new_row5((GURL(kURL))); | |
| 1487 std::vector<VisitInfo> new_visits5; | |
| 1488 | |
| 1489 // UPDATE_NODE should be set because row5 has a newer last_visit timestamp. | |
| 1490 EXPECT_EQ(TypedURLSyncBridgeTest::DIFF_UPDATE_NODE | | |
| 1491 TypedURLSyncBridgeTest::DIFF_NONE, | |
| 1492 TypedURLSyncBridgeTest::MergeUrls(specs5, row5, &visits5, &new_row5, | |
| 1493 &new_visits5)); | |
| 1494 EXPECT_TRUE(URLsEqual(new_row5, expected5)); | |
| 1495 EXPECT_EQ(0U, new_visits5.size()); | |
| 1496 } | |
| 1497 | |
| 1498 // Tests to ensure that we don't resurrect expired URLs (URLs that have been | |
| 1499 // deleted from the history DB but still exist in the sync DB). | |
| 1500 TEST_F(TypedURLSyncBridgeTest, MergeUrlsAfterExpiration) { | |
| 1501 // First, create a history row that has two visits, with timestamps 2 and 3. | |
| 1502 VisitVector(history_visits); | |
| 1503 history_visits.push_back(VisitRow(0, base::Time::FromInternalValue(2), 0, | |
| 1504 ui::PAGE_TRANSITION_TYPED, 0)); | |
| 1505 URLRow history_url( | |
| 1506 MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &history_visits)); | |
| 1507 | |
| 1508 // Now, create a sync node with visits at timestamps 1, 2, 3, 4. | |
| 1509 sync_pb::TypedUrlSpecifics node( | |
| 1510 MakeTypedUrlSpecifics(kURL, kTitle, 1, false)); | |
| 1511 node.add_visits(2); | |
| 1512 node.add_visits(3); | |
| 1513 node.add_visits(4); | |
| 1514 node.add_visit_transitions(2); | |
| 1515 node.add_visit_transitions(3); | |
| 1516 node.add_visit_transitions(4); | |
| 1517 URLRow new_history_url(history_url.url()); | |
| 1518 std::vector<VisitInfo> new_visits; | |
| 1519 EXPECT_EQ( | |
| 1520 TypedURLSyncBridgeTest::DIFF_NONE | | |
| 1521 TypedURLSyncBridgeTest::DIFF_LOCAL_VISITS_ADDED, | |
| 1522 TypedURLSyncBridgeTest::MergeUrls(node, history_url, &history_visits, | |
| 1523 &new_history_url, &new_visits)); | |
| 1524 EXPECT_TRUE(URLsEqual(history_url, new_history_url)); | |
| 1525 EXPECT_EQ(1U, new_visits.size()); | |
| 1526 EXPECT_EQ(4U, new_visits[0].first.ToInternalValue()); | |
| 1527 // We should not sync the visit with timestamp #1 since it is earlier than | |
| 1528 // any other visit for this URL in the history DB. But we should sync visit | |
| 1529 // #4. | |
| 1530 EXPECT_EQ(3U, history_visits.size()); | |
| 1531 EXPECT_EQ(2U, history_visits[0].visit_time.ToInternalValue()); | |
| 1532 EXPECT_EQ(3U, history_visits[1].visit_time.ToInternalValue()); | |
| 1533 EXPECT_EQ(4U, history_visits[2].visit_time.ToInternalValue()); | |
| 1534 } | |
| 1535 | |
| 1536 // Create a local typed URL with one expired TYPED visit, | |
| 1537 // MergeSyncData should not pass it to sync. And then add a non | |
| 1538 // expired visit, OnURLsModified should only send the non expired visit to sync. | |
| 1539 TEST_F(TypedURLSyncBridgeTest, LocalExpiredTypedUrlDoNotSync) { | |
| 1540 URLRow row; | |
| 1541 URLRows changed_urls; | |
| 1542 VisitVector visits; | |
| 1543 | |
| 1544 // Add an expired typed URL to local. | |
| 1545 row = MakeTypedUrlRow(kURL, kTitle, 1, kExpiredVisit, false, &visits); | |
| 1546 fake_history_backend_->SetVisitsForUrl(row, visits); | |
| 1547 | |
| 1548 StartSyncing(std::vector<TypedUrlSpecifics>()); | |
| 1549 | |
| 1550 // Check change processor did not receive expired typed URL. | |
| 1551 const auto& changes_multimap = processor().put_multimap(); | |
| 1552 ASSERT_EQ(0U, changes_multimap.size()); | |
| 1553 | |
| 1554 // Add a non expired typed URL to local. | |
| 1555 row = MakeTypedUrlRow(kURL, kTitle, 2, 1, false, &visits); | |
| 1556 fake_history_backend_->SetVisitsForUrl(row, visits); | |
| 1557 | |
| 1558 changed_urls.push_back(row); | |
| 1559 // Notify typed url sync service of the update. | |
| 1560 bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls); | |
| 1561 | |
| 1562 // Check change processor did not receive expired typed URL. | |
| 1563 ASSERT_EQ(1U, changes_multimap.size()); | |
| 1564 | |
| 1565 // Get typed url specifics. Verify only a non-expired visit received. | |
| 1566 sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL); | |
| 1567 | |
| 1568 EXPECT_TRUE(URLsEqual(row, url_specifics)); | |
| 1569 ASSERT_EQ(1, url_specifics.visits_size()); | |
| 1570 ASSERT_EQ(static_cast<const int>(visits.size() - 1), | |
| 1571 url_specifics.visits_size()); | |
| 1572 EXPECT_EQ(visits[1].visit_time.ToInternalValue(), url_specifics.visits(0)); | |
| 1573 EXPECT_EQ(static_cast<const int>(visits[1].transition), | |
| 1574 url_specifics.visit_transitions(0)); | |
| 1575 } | |
| 1576 | |
| 409 } // namespace history | 1577 } // namespace history |
| OLD | NEW |