Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(331)

Side by Side Diff: components/history/core/browser/typed_url_sync_bridge_unittest.cc

Issue 2961723003: [USS] Implement ApplySyncChanges and OnURLVisited/Modified/Deleted. (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698