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

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

Powered by Google App Engine
This is Rietveld 408576698