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

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

Powered by Google App Engine
This is Rietveld 408576698