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