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