OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <stddef.h> | |
6 #include <stdint.h> | |
7 | |
8 #include <memory> | |
9 #include <string> | |
10 #include <utility> | |
11 #include <vector> | |
12 | |
13 #include "base/bind.h" | |
14 #include "base/bind_helpers.h" | |
15 #include "base/callback.h" | |
16 #include "base/location.h" | |
17 #include "base/macros.h" | |
18 #include "base/memory/ptr_util.h" | |
19 #include "base/memory/ref_counted.h" | |
20 #include "base/run_loop.h" | |
21 #include "base/strings/string16.h" | |
22 #include "base/strings/utf_string_conversions.h" | |
23 #include "base/threading/thread.h" | |
24 #include "base/threading/thread_task_runner_handle.h" | |
25 #include "base/time/time.h" | |
26 #include "components/browser_sync/browser/abstract_profile_sync_service_test.h" | |
27 #include "components/browser_sync/browser/test_profile_sync_service.h" | |
28 #include "components/history/core/browser/history_backend.h" | |
29 #include "components/history/core/browser/history_backend_client.h" | |
30 #include "components/history/core/browser/history_backend_notifier.h" | |
31 #include "components/history/core/browser/history_db_task.h" | |
32 #include "components/history/core/browser/history_service.h" | |
33 #include "components/history/core/browser/typed_url_data_type_controller.h" | |
34 #include "components/signin/core/browser/signin_manager.h" | |
35 #include "components/sync/api/data_type_error_handler_mock.h" | |
36 #include "components/sync/core/read_node.h" | |
37 #include "components/sync/core/read_transaction.h" | |
38 #include "components/sync/core/write_node.h" | |
39 #include "components/sync/core/write_transaction.h" | |
40 #include "components/sync/driver/data_type_manager_impl.h" | |
41 #include "components/sync/protocol/typed_url_specifics.pb.h" | |
42 #include "testing/gmock/include/gmock/gmock.h" | |
43 #include "testing/gtest/include/gtest/gtest.h" | |
44 #include "url/gurl.h" | |
45 | |
46 using browser_sync::TypedUrlDataTypeController; | |
47 using history::HistoryBackend; | |
48 using history::HistoryBackendNotifier; | |
49 using history::TypedUrlSyncableService; | |
50 using testing::DoAll; | |
51 using testing::Return; | |
52 using testing::SetArgumentPointee; | |
53 using testing::_; | |
54 | |
55 namespace { | |
56 | |
57 const char kDummySavingBrowserHistoryDisabled[] = "dummyPref"; | |
58 | |
59 // Visits with this timestamp are treated as expired. | |
60 static const int EXPIRED_VISIT = -1; | |
61 | |
62 ACTION(ReturnNewDataTypeManager) { | |
63 return new sync_driver::DataTypeManagerImpl(arg0, arg1, arg2, arg3, arg4); | |
64 } | |
65 | |
66 class HistoryBackendMock : public HistoryBackend { | |
67 public: | |
68 HistoryBackendMock() | |
69 : HistoryBackend(nullptr, nullptr, base::ThreadTaskRunnerHandle::Get()) {} | |
70 bool IsExpiredVisitTime(const base::Time& time) override { | |
71 return time.ToInternalValue() == EXPIRED_VISIT; | |
72 } | |
73 MOCK_METHOD1(GetAllTypedURLs, bool(history::URLRows* entries)); | |
74 MOCK_METHOD3(GetMostRecentVisitsForURL, bool(history::URLID id, | |
75 int max_visits, | |
76 history::VisitVector* visits)); | |
77 MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url)); | |
78 MOCK_METHOD3(AddVisits, bool(const GURL& url, | |
79 const std::vector<history::VisitInfo>& visits, | |
80 history::VisitSource visit_source)); | |
81 MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row)); | |
82 MOCK_METHOD2(SetPageTitle, void(const GURL& url, | |
83 const base::string16& title)); | |
84 MOCK_METHOD1(DeleteURL, void(const GURL& url)); | |
85 | |
86 private: | |
87 friend class ProfileSyncServiceTypedUrlTest; | |
88 | |
89 virtual ~HistoryBackendMock() {} | |
90 }; | |
91 | |
92 class HistoryServiceMock : public history::HistoryService { | |
93 public: | |
94 HistoryServiceMock() : history::HistoryService(), backend_(nullptr) {} | |
95 | |
96 base::CancelableTaskTracker::TaskId ScheduleDBTask( | |
97 std::unique_ptr<history::HistoryDBTask> task, | |
98 base::CancelableTaskTracker* tracker) override { | |
99 // Explicitly copy out the raw pointer -- compilers might decide to | |
100 // evaluate task.release() before the arguments for the first Bind(). | |
101 history::HistoryDBTask* task_raw = task.get(); | |
102 task_runner_->PostTaskAndReply( | |
103 FROM_HERE, | |
104 base::Bind(&HistoryServiceMock::RunTaskOnDBThread, | |
105 base::Unretained(this), task_raw), | |
106 base::Bind(&base::DeletePointer<history::HistoryDBTask>, | |
107 task.release())); | |
108 return base::CancelableTaskTracker::kBadTaskId; // unused | |
109 } | |
110 | |
111 ~HistoryServiceMock() override {} | |
112 | |
113 void set_task_runner( | |
114 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { | |
115 DCHECK(task_runner.get()); | |
116 task_runner_ = task_runner; | |
117 } | |
118 | |
119 void set_backend(scoped_refptr<history::HistoryBackend> backend) { | |
120 backend_ = backend; | |
121 } | |
122 | |
123 private: | |
124 void RunTaskOnDBThread(history::HistoryDBTask* task) { | |
125 EXPECT_TRUE(task->RunOnDBThread(backend_.get(), NULL)); | |
126 } | |
127 | |
128 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
129 scoped_refptr<history::HistoryBackend> backend_; | |
130 }; | |
131 | |
132 class TestTypedUrlSyncableService : public TypedUrlSyncableService { | |
133 // TODO(gangwu): remove TestProfileSyncService or even remove whole test | |
134 // suite, and make sure typed_url_syncable_service_unittest.cc and the various | |
135 // typed url integration tests. | |
136 public: | |
137 explicit TestTypedUrlSyncableService(history::HistoryBackend* history_backend) | |
138 : TypedUrlSyncableService(history_backend) {} | |
139 | |
140 static void WriteToSyncNode(const history::URLRow& url, | |
141 const history::VisitVector& visits, | |
142 syncer::WriteNode* node) { | |
143 sync_pb::TypedUrlSpecifics typed_url; | |
144 WriteToTypedUrlSpecifics(url, visits, &typed_url); | |
145 node->SetTypedUrlSpecifics(typed_url); | |
146 } | |
147 | |
148 protected: | |
149 // Don't clear error stats - that way we can verify their values in our | |
150 // tests. | |
151 void ClearErrorStats() override {} | |
152 }; | |
153 | |
154 class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest { | |
155 public: | |
156 void AddTypedUrlSyncNode(const history::URLRow& url, | |
157 const history::VisitVector& visits) { | |
158 syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare()); | |
159 | |
160 syncer::WriteNode node(&trans); | |
161 std::string tag = url.url().spec(); | |
162 syncer::WriteNode::InitUniqueByCreationResult result = | |
163 node.InitUniqueByCreation(syncer::TYPED_URLS, tag); | |
164 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result); | |
165 TestTypedUrlSyncableService::WriteToSyncNode(url, visits, &node); | |
166 } | |
167 | |
168 protected: | |
169 ProfileSyncServiceTypedUrlTest() { | |
170 profile_sync_service_bundle() | |
171 ->pref_service() | |
172 ->registry() | |
173 ->RegisterBooleanPref(kDummySavingBrowserHistoryDisabled, false); | |
174 | |
175 data_type_thread()->Start(); | |
176 base::RunLoop run_loop; | |
177 data_type_thread()->task_runner()->PostTaskAndReply( | |
178 FROM_HERE, | |
179 base::Bind(&ProfileSyncServiceTypedUrlTest::CreateHistoryService, | |
180 base::Unretained(this)), | |
181 run_loop.QuitClosure()); | |
182 run_loop.Run(); | |
183 history_service_ = base::WrapUnique(new HistoryServiceMock); | |
184 history_service_->set_task_runner(data_type_thread()->task_runner()); | |
185 history_service_->set_backend(history_backend_); | |
186 | |
187 browser_sync::ProfileSyncServiceBundle::SyncClientBuilder builder( | |
188 profile_sync_service_bundle()); | |
189 builder.SetHistoryService(history_service_.get()); | |
190 builder.SetSyncServiceCallback(GetSyncServiceCallback()); | |
191 builder.SetSyncableServiceCallback( | |
192 base::Bind(&ProfileSyncServiceTypedUrlTest::GetSyncableServiceForType, | |
193 base::Unretained(this))); | |
194 builder.set_activate_model_creation(); | |
195 sync_client_ = builder.Build(); | |
196 } | |
197 | |
198 void CreateHistoryService() { | |
199 history_backend_ = new HistoryBackendMock(); | |
200 syncable_service_ = | |
201 base::MakeUnique<TestTypedUrlSyncableService>(history_backend_.get()); | |
202 } | |
203 | |
204 void DeleteSyncableService() { | |
205 syncable_service_.reset(); | |
206 history_backend_ = nullptr; | |
207 } | |
208 | |
209 ~ProfileSyncServiceTypedUrlTest() override { | |
210 history_service_->Shutdown(); | |
211 | |
212 // Request stop to get deletion tasks related to the HistoryService posted | |
213 // on the Sync thread. It is important to not Shutdown at this moment, | |
214 // because after shutdown the Sync thread is not returned to the sync | |
215 // service, so we could not get the thread's message loop to wait for the | |
216 // deletions to be finished. | |
217 sync_service()->RequestStop(sync_driver::SyncService::CLEAR_DATA); | |
218 // Spin the sync thread. | |
219 { | |
220 base::RunLoop run_loop; | |
221 sync_service()->GetSyncLoopForTest()->task_runner()->PostTaskAndReply( | |
222 FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure()); | |
223 run_loop.Run(); | |
224 } | |
225 | |
226 // Spin the loop again for deletion tasks posted from the Sync thread. | |
227 base::RunLoop().RunUntilIdle(); | |
228 | |
229 { | |
230 base::RunLoop run_loop; | |
231 data_type_thread()->task_runner()->PostTaskAndReply( | |
232 FROM_HERE, | |
233 base::Bind(&ProfileSyncServiceTypedUrlTest::DeleteSyncableService, | |
234 base::Unretained(this)), | |
235 run_loop.QuitClosure()); | |
236 run_loop.Run(); | |
237 } | |
238 } | |
239 | |
240 TypedUrlSyncableService* StartSyncService(const base::Closure& callback) { | |
241 if (!sync_service()) { | |
242 std::string account_id = | |
243 profile_sync_service_bundle()->account_tracker()->SeedAccountInfo( | |
244 "gaia_id", "test"); | |
245 SigninManagerBase* signin = | |
246 profile_sync_service_bundle()->signin_manager(); | |
247 signin->SetAuthenticatedAccountInfo("gaia_id", "test"); | |
248 CreateSyncService(std::move(sync_client_), callback); | |
249 EXPECT_CALL(*profile_sync_service_bundle()->component_factory(), | |
250 CreateDataTypeManager(_, _, _, _, _)) | |
251 .WillOnce(ReturnNewDataTypeManager()); | |
252 | |
253 profile_sync_service_bundle()->auth_service()->UpdateCredentials( | |
254 account_id, "oauth2_login_token"); | |
255 | |
256 sync_service()->RegisterDataTypeController( | |
257 base::MakeUnique<TypedUrlDataTypeController>( | |
258 base::Bind(&base::DoNothing), sync_service()->GetSyncClient(), | |
259 kDummySavingBrowserHistoryDisabled)); | |
260 | |
261 sync_service()->Initialize(); | |
262 base::RunLoop().Run(); | |
263 } | |
264 return syncable_service_.get(); | |
265 } | |
266 | |
267 void GetTypedUrlsFromSyncDB(history::URLRows* urls) { | |
268 urls->clear(); | |
269 syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare()); | |
270 syncer::ReadNode typed_url_root(&trans); | |
271 if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) != | |
272 syncer::BaseNode::INIT_OK) | |
273 return; | |
274 | |
275 int64_t child_id = typed_url_root.GetFirstChildId(); | |
276 while (child_id != syncer::kInvalidId) { | |
277 syncer::ReadNode child_node(&trans); | |
278 if (child_node.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK) | |
279 return; | |
280 | |
281 const sync_pb::TypedUrlSpecifics& typed_url( | |
282 child_node.GetTypedUrlSpecifics()); | |
283 history::URLRow new_url(GURL(typed_url.url())); | |
284 | |
285 new_url.set_title(base::UTF8ToUTF16(typed_url.title())); | |
286 DCHECK(typed_url.visits_size()); | |
287 DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size()); | |
288 new_url.set_last_visit(base::Time::FromInternalValue( | |
289 typed_url.visits(typed_url.visits_size() - 1))); | |
290 new_url.set_hidden(typed_url.hidden()); | |
291 | |
292 urls->push_back(new_url); | |
293 child_id = child_node.GetSuccessorId(); | |
294 } | |
295 } | |
296 | |
297 void SetIdleChangeProcessorExpectations() { | |
298 EXPECT_CALL((history_backend()), SetPageTitle(_, _)).Times(0); | |
299 EXPECT_CALL((history_backend()), UpdateURL(_, _)).Times(0); | |
300 EXPECT_CALL((history_backend()), GetURL(_, _)).Times(0); | |
301 EXPECT_CALL((history_backend()), DeleteURL(_)).Times(0); | |
302 } | |
303 | |
304 void SendNotification(const base::Closure& task) { | |
305 data_type_thread()->task_runner()->PostTaskAndReply( | |
306 FROM_HERE, task, | |
307 base::Bind(&base::MessageLoop::QuitNow, | |
308 base::Unretained(base::MessageLoop::current()))); | |
309 base::RunLoop().Run(); | |
310 } | |
311 | |
312 void SendNotificationURLVisited(ui::PageTransition transition, | |
313 const history::URLRow& row) { | |
314 base::Time visit_time; | |
315 history::RedirectList redirects; | |
316 SendNotification( | |
317 base::Bind(&HistoryBackendNotifier::NotifyURLVisited, | |
318 base::Unretained(history_backend_.get()), | |
319 transition, | |
320 row, | |
321 redirects, | |
322 visit_time)); | |
323 } | |
324 | |
325 void SendNotificationURLsModified(const history::URLRows& rows) { | |
326 SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLsModified, | |
327 base::Unretained(history_backend_.get()), | |
328 rows)); | |
329 } | |
330 | |
331 void SendNotificationURLsDeleted(bool all_history, | |
332 bool expired, | |
333 const history::URLRows& deleted_rows, | |
334 const std::set<GURL>& favicon_urls) { | |
335 SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLsDeleted, | |
336 base::Unretained(history_backend_.get()), | |
337 all_history, expired, deleted_rows, | |
338 favicon_urls)); | |
339 } | |
340 | |
341 static bool URLsEqual(const history::URLRow& lhs, | |
342 const history::URLRow& rhs) { | |
343 // Only verify the fields we explicitly sync (i.e. don't verify typed_count | |
344 // or visit_count because we rely on the history DB to manage those values | |
345 // and they are left unchanged by HistoryBackendMock). | |
346 return (lhs.url().spec().compare(rhs.url().spec()) == 0) && | |
347 (lhs.title().compare(rhs.title()) == 0) && | |
348 (lhs.last_visit() == rhs.last_visit()) && | |
349 (lhs.hidden() == rhs.hidden()); | |
350 } | |
351 | |
352 static history::URLRow MakeTypedUrlEntry(const char* url, | |
353 const char* title, | |
354 int typed_count, | |
355 int64_t last_visit, | |
356 bool hidden, | |
357 history::VisitVector* visits) { | |
358 // Give each URL a unique ID, to mimic the behavior of the real database. | |
359 static int unique_url_id = 0; | |
360 GURL gurl(url); | |
361 history::URLRow history_url(gurl, ++unique_url_id); | |
362 history_url.set_title(base::UTF8ToUTF16(title)); | |
363 history_url.set_typed_count(typed_count); | |
364 history_url.set_last_visit( | |
365 base::Time::FromInternalValue(last_visit)); | |
366 history_url.set_hidden(hidden); | |
367 visits->push_back(history::VisitRow( | |
368 history_url.id(), history_url.last_visit(), 0, | |
369 ui::PAGE_TRANSITION_TYPED, 0)); | |
370 history_url.set_visit_count(visits->size()); | |
371 return history_url; | |
372 } | |
373 | |
374 base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( | |
375 syncer::ModelType type) { | |
376 DCHECK_EQ(syncer::TYPED_URLS, type); | |
377 return syncable_service_->AsWeakPtr(); | |
378 } | |
379 | |
380 HistoryBackendMock& history_backend() { return *history_backend_.get(); } | |
381 | |
382 private: | |
383 scoped_refptr<HistoryBackendMock> history_backend_; | |
384 std::unique_ptr<HistoryServiceMock> history_service_; | |
385 syncer::DataTypeErrorHandlerMock error_handler_; | |
386 std::unique_ptr<TestTypedUrlSyncableService> syncable_service_; | |
387 std::unique_ptr<sync_driver::FakeSyncClient> sync_client_; | |
388 | |
389 DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceTypedUrlTest); | |
390 }; | |
391 | |
392 void AddTypedUrlEntries(ProfileSyncServiceTypedUrlTest* test, | |
393 const history::URLRows& entries) { | |
394 test->CreateRoot(syncer::TYPED_URLS); | |
395 for (size_t i = 0; i < entries.size(); ++i) { | |
396 history::VisitVector visits; | |
397 visits.push_back(history::VisitRow( | |
398 entries[i].id(), entries[i].last_visit(), 0, | |
399 ui::PageTransitionFromInt(0), 0)); | |
400 test->AddTypedUrlSyncNode(entries[i], visits); | |
401 } | |
402 } | |
403 | |
404 } // namespace | |
405 | |
406 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) { | |
407 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true)); | |
408 SetIdleChangeProcessorExpectations(); | |
409 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
410 TypedUrlSyncableService* syncable_service = | |
411 StartSyncService(create_root.callback()); | |
412 history::URLRows sync_entries; | |
413 GetTypedUrlsFromSyncDB(&sync_entries); | |
414 EXPECT_EQ(0U, sync_entries.size()); | |
415 ASSERT_EQ(0, syncable_service->GetErrorPercentage()); | |
416 } | |
417 | |
418 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) { | |
419 history::URLRows entries; | |
420 history::VisitVector visits; | |
421 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar", | |
422 2, 15, false, &visits)); | |
423 | |
424 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
425 .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true))); | |
426 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
427 .WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true))); | |
428 SetIdleChangeProcessorExpectations(); | |
429 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
430 TypedUrlSyncableService* syncable_service = | |
431 StartSyncService(create_root.callback()); | |
432 history::URLRows sync_entries; | |
433 GetTypedUrlsFromSyncDB(&sync_entries); | |
434 ASSERT_EQ(1U, sync_entries.size()); | |
435 EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0])); | |
436 ASSERT_EQ(0, syncable_service->GetErrorPercentage()); | |
437 } | |
438 | |
439 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeErrorReadingVisits) { | |
440 history::URLRows entries; | |
441 history::VisitVector visits; | |
442 history::URLRow native_entry1(MakeTypedUrlEntry("http://foo.com", "bar", | |
443 2, 15, false, &visits)); | |
444 history::URLRow native_entry2(MakeTypedUrlEntry("http://foo2.com", "bar", | |
445 3, 15, false, &visits)); | |
446 entries.push_back(native_entry1); | |
447 entries.push_back(native_entry2); | |
448 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
449 .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true))); | |
450 // Return an error from GetMostRecentVisitsForURL() for the second URL. | |
451 EXPECT_CALL((history_backend()), | |
452 GetMostRecentVisitsForURL(native_entry1.id(), _, _)) | |
453 .WillRepeatedly(Return(true)); | |
454 EXPECT_CALL((history_backend()), | |
455 GetMostRecentVisitsForURL(native_entry2.id(), _, _)) | |
456 .WillRepeatedly(Return(false)); | |
457 SetIdleChangeProcessorExpectations(); | |
458 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
459 StartSyncService(create_root.callback()); | |
460 history::URLRows sync_entries; | |
461 GetTypedUrlsFromSyncDB(&sync_entries); | |
462 ASSERT_EQ(1U, sync_entries.size()); | |
463 EXPECT_TRUE(URLsEqual(native_entry1, sync_entries[0])); | |
464 } | |
465 | |
466 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithBlankEmptySync) { | |
467 std::vector<history::URLRow> entries; | |
468 history::VisitVector visits; | |
469 // Add an empty URL. | |
470 entries.push_back(MakeTypedUrlEntry("", "bar", | |
471 2, 15, false, &visits)); | |
472 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar", | |
473 2, 15, false, &visits)); | |
474 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
475 .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true))); | |
476 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
477 .WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true))); | |
478 SetIdleChangeProcessorExpectations(); | |
479 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
480 StartSyncService(create_root.callback()); | |
481 std::vector<history::URLRow> sync_entries; | |
482 GetTypedUrlsFromSyncDB(&sync_entries); | |
483 // The empty URL should be ignored. | |
484 ASSERT_EQ(1U, sync_entries.size()); | |
485 EXPECT_TRUE(URLsEqual(entries[1], sync_entries[0])); | |
486 } | |
487 | |
488 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) { | |
489 history::VisitVector native_visits; | |
490 history::VisitVector sync_visits; | |
491 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry", | |
492 2, 15, false, &native_visits)); | |
493 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", | |
494 3, 16, false, &sync_visits)); | |
495 | |
496 history::URLRows native_entries; | |
497 native_entries.push_back(native_entry); | |
498 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
499 .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true))); | |
500 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
501 .WillRepeatedly( | |
502 DoAll(SetArgumentPointee<2>(native_visits), Return(true))); | |
503 EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED)) | |
504 .WillRepeatedly(Return(true)); | |
505 | |
506 history::URLRows sync_entries; | |
507 sync_entries.push_back(sync_entry); | |
508 | |
509 EXPECT_CALL((history_backend()), UpdateURL(_, _)) | |
510 .WillRepeatedly(Return(true)); | |
511 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries)); | |
512 | |
513 std::map<std::string, history::URLRow> expected; | |
514 expected[native_entry.url().spec()] = native_entry; | |
515 expected[sync_entry.url().spec()] = sync_entry; | |
516 | |
517 history::URLRows new_sync_entries; | |
518 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
519 | |
520 EXPECT_TRUE(new_sync_entries.size() == expected.size()); | |
521 for (history::URLRows::iterator entry = new_sync_entries.begin(); | |
522 entry != new_sync_entries.end(); ++entry) { | |
523 EXPECT_TRUE(URLsEqual(expected[entry->url().spec()], *entry)); | |
524 } | |
525 } | |
526 | |
527 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeExpiredSync) { | |
528 history::VisitVector sync_visits; | |
529 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", | |
530 3, EXPIRED_VISIT, false, | |
531 &sync_visits)); | |
532 history::URLRows sync_entries; | |
533 sync_entries.push_back(sync_entry); | |
534 | |
535 // Since all our URLs are expired, no backend calls to add new URLs will be | |
536 // made. | |
537 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true)); | |
538 SetIdleChangeProcessorExpectations(); | |
539 | |
540 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries)); | |
541 } | |
542 | |
543 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) { | |
544 history::VisitVector native_visits; | |
545 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry", | |
546 2, 15, false, &native_visits)); | |
547 history::VisitVector sync_visits; | |
548 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name", | |
549 1, 17, false, &sync_visits)); | |
550 history::VisitVector merged_visits; | |
551 merged_visits.push_back(history::VisitRow( | |
552 sync_entry.id(), base::Time::FromInternalValue(15), 0, | |
553 ui::PageTransitionFromInt(0), 0)); | |
554 | |
555 history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name", | |
556 2, 17, false, &merged_visits)); | |
557 | |
558 history::URLRows native_entries; | |
559 native_entries.push_back(native_entry); | |
560 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
561 .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true))); | |
562 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
563 .WillRepeatedly( | |
564 DoAll(SetArgumentPointee<2>(native_visits), Return(true))); | |
565 EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED)) | |
566 .WillRepeatedly(Return(true)); | |
567 | |
568 history::URLRows sync_entries; | |
569 sync_entries.push_back(sync_entry); | |
570 | |
571 EXPECT_CALL((history_backend()), UpdateURL(_, _)) | |
572 .WillRepeatedly(Return(true)); | |
573 EXPECT_CALL((history_backend()), SetPageTitle(_, _)).WillRepeatedly(Return()); | |
574 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries)); | |
575 | |
576 history::URLRows new_sync_entries; | |
577 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
578 ASSERT_EQ(1U, new_sync_entries.size()); | |
579 EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0])); | |
580 } | |
581 | |
582 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithErrorHasSyncMerge) { | |
583 history::VisitVector native_visits; | |
584 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "native", | |
585 2, 15, false, &native_visits)); | |
586 history::VisitVector sync_visits; | |
587 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "sync", | |
588 1, 17, false, &sync_visits)); | |
589 | |
590 history::URLRows native_entries; | |
591 native_entries.push_back(native_entry); | |
592 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
593 .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true))); | |
594 // Return an error getting the visits for the native URL. | |
595 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
596 .WillRepeatedly(Return(false)); | |
597 EXPECT_CALL((history_backend()), GetURL(_, _)) | |
598 .WillRepeatedly(DoAll(SetArgumentPointee<1>(native_entry), Return(true))); | |
599 EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED)) | |
600 .WillRepeatedly(Return(true)); | |
601 | |
602 history::URLRows sync_entries; | |
603 sync_entries.push_back(sync_entry); | |
604 | |
605 EXPECT_CALL((history_backend()), UpdateURL(_, _)) | |
606 .WillRepeatedly(Return(true)); | |
607 EXPECT_CALL((history_backend()), SetPageTitle(_, _)).WillRepeatedly(Return()); | |
608 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries)); | |
609 | |
610 history::URLRows new_sync_entries; | |
611 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
612 ASSERT_EQ(1U, new_sync_entries.size()); | |
613 EXPECT_TRUE(URLsEqual(sync_entry, new_sync_entries[0])); | |
614 } | |
615 | |
616 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) { | |
617 history::VisitVector added_visits; | |
618 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry", | |
619 2, 15, false, &added_visits)); | |
620 | |
621 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true)); | |
622 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
623 .WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true))); | |
624 | |
625 SetIdleChangeProcessorExpectations(); | |
626 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
627 StartSyncService(create_root.callback()); | |
628 | |
629 history::URLRows changed_urls; | |
630 changed_urls.push_back(added_entry); | |
631 SendNotificationURLsModified(changed_urls); | |
632 | |
633 history::URLRows new_sync_entries; | |
634 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
635 ASSERT_EQ(1U, new_sync_entries.size()); | |
636 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0])); | |
637 } | |
638 | |
639 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddWithBlank) { | |
640 history::VisitVector added_visits; | |
641 history::URLRow empty_entry(MakeTypedUrlEntry("", "entry", | |
642 2, 15, false, &added_visits)); | |
643 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry", | |
644 2, 15, false, &added_visits)); | |
645 | |
646 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true)); | |
647 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
648 .WillRepeatedly(DoAll(SetArgumentPointee<2>(added_visits), Return(true))); | |
649 | |
650 SetIdleChangeProcessorExpectations(); | |
651 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
652 StartSyncService(create_root.callback()); | |
653 | |
654 history::URLRows changed_urls; | |
655 changed_urls.push_back(empty_entry); | |
656 changed_urls.push_back(added_entry); | |
657 SendNotificationURLsModified(changed_urls); | |
658 | |
659 std::vector<history::URLRow> new_sync_entries; | |
660 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
661 ASSERT_EQ(1U, new_sync_entries.size()); | |
662 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0])); | |
663 } | |
664 | |
665 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) { | |
666 history::VisitVector original_visits; | |
667 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry", | |
668 2, 15, false, | |
669 &original_visits)); | |
670 history::URLRows original_entries; | |
671 original_entries.push_back(original_entry); | |
672 | |
673 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
674 .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
675 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
676 .WillOnce(DoAll(SetArgumentPointee<2>(original_visits), Return(true))); | |
677 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
678 StartSyncService(create_root.callback()); | |
679 | |
680 history::VisitVector updated_visits; | |
681 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry", | |
682 7, 17, false, | |
683 &updated_visits)); | |
684 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
685 .WillOnce(DoAll(SetArgumentPointee<2>(updated_visits), Return(true))); | |
686 | |
687 history::URLRows changed_urls; | |
688 changed_urls.push_back(updated_entry); | |
689 SendNotificationURLsModified(changed_urls); | |
690 | |
691 history::URLRows new_sync_entries; | |
692 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
693 ASSERT_EQ(1U, new_sync_entries.size()); | |
694 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0])); | |
695 } | |
696 | |
697 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddFromVisit) { | |
698 history::VisitVector added_visits; | |
699 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry", | |
700 2, 15, false, &added_visits)); | |
701 | |
702 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true)); | |
703 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
704 .WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true))); | |
705 | |
706 SetIdleChangeProcessorExpectations(); | |
707 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
708 StartSyncService(create_root.callback()); | |
709 | |
710 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, added_entry); | |
711 | |
712 history::URLRows new_sync_entries; | |
713 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
714 ASSERT_EQ(1U, new_sync_entries.size()); | |
715 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0])); | |
716 } | |
717 | |
718 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdateFromVisit) { | |
719 history::VisitVector original_visits; | |
720 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry", | |
721 2, 15, false, | |
722 &original_visits)); | |
723 history::URLRows original_entries; | |
724 original_entries.push_back(original_entry); | |
725 | |
726 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
727 .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
728 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
729 .WillOnce(DoAll(SetArgumentPointee<2>(original_visits), Return(true))); | |
730 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
731 StartSyncService(create_root.callback()); | |
732 | |
733 history::VisitVector updated_visits; | |
734 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry", | |
735 7, 17, false, | |
736 &updated_visits)); | |
737 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
738 .WillOnce(DoAll(SetArgumentPointee<2>(updated_visits), Return(true))); | |
739 | |
740 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, updated_entry); | |
741 | |
742 history::URLRows new_sync_entries; | |
743 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
744 ASSERT_EQ(1U, new_sync_entries.size()); | |
745 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0])); | |
746 } | |
747 | |
748 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserIgnoreChangeUpdateFromVisit) { | |
749 history::VisitVector original_visits; | |
750 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry", | |
751 2, 15, false, | |
752 &original_visits)); | |
753 history::URLRows original_entries; | |
754 original_entries.push_back(original_entry); | |
755 | |
756 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
757 .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
758 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
759 .WillRepeatedly( | |
760 DoAll(SetArgumentPointee<2>(original_visits), Return(true))); | |
761 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
762 StartSyncService(create_root.callback()); | |
763 history::URLRows new_sync_entries; | |
764 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
765 ASSERT_EQ(1U, new_sync_entries.size()); | |
766 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0])); | |
767 | |
768 history::VisitVector updated_visits; | |
769 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry", | |
770 7, 15, false, | |
771 &updated_visits)); | |
772 | |
773 // Should ignore this change because it's not TYPED. | |
774 SendNotificationURLVisited(ui::PAGE_TRANSITION_RELOAD, updated_entry); | |
775 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
776 | |
777 // Should be no changes to the sync DB from this notification. | |
778 ASSERT_EQ(1U, new_sync_entries.size()); | |
779 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0])); | |
780 | |
781 // Now, try updating it with a large number of visits not divisible by 10 | |
782 // (should ignore this visit). | |
783 history::URLRow twelve_visits(MakeTypedUrlEntry("http://mine.com", "entry", | |
784 12, 15, false, | |
785 &updated_visits)); | |
786 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twelve_visits); | |
787 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
788 | |
789 // Should be no changes to the sync DB from this notification. | |
790 ASSERT_EQ(1U, new_sync_entries.size()); | |
791 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0])); | |
792 | |
793 // Now, try updating it with a large number of visits that is divisible by 10 | |
794 // (should *not* be ignored). | |
795 history::URLRow twenty_visits(MakeTypedUrlEntry("http://mine.com", "entry", | |
796 20, 15, false, | |
797 &updated_visits)); | |
798 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twenty_visits); | |
799 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
800 | |
801 ASSERT_EQ(1U, new_sync_entries.size()); | |
802 EXPECT_TRUE(URLsEqual(twenty_visits, new_sync_entries[0])); | |
803 } | |
804 | |
805 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) { | |
806 history::VisitVector original_visits1; | |
807 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry", | |
808 2, 15, false, | |
809 &original_visits1)); | |
810 history::VisitVector original_visits2; | |
811 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com", | |
812 "entry2", | |
813 3, 15, false, | |
814 &original_visits2)); | |
815 history::URLRows original_entries; | |
816 original_entries.push_back(original_entry1); | |
817 original_entries.push_back(original_entry2); | |
818 | |
819 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
820 .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
821 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
822 .WillRepeatedly( | |
823 DoAll(SetArgumentPointee<2>(original_visits1), Return(true))); | |
824 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
825 StartSyncService(create_root.callback()); | |
826 | |
827 history::URLRows rows; | |
828 rows.push_back(history::URLRow(GURL("http://mine.com"))); | |
829 SendNotificationURLsDeleted(false, false, rows, std::set<GURL>()); | |
830 history::URLRows new_sync_entries; | |
831 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
832 ASSERT_EQ(1U, new_sync_entries.size()); | |
833 EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0])); | |
834 } | |
835 | |
836 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveExpired) { | |
837 history::VisitVector original_visits1; | |
838 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry", | |
839 2, 15, false, | |
840 &original_visits1)); | |
841 history::VisitVector original_visits2; | |
842 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com", | |
843 "entry2", | |
844 3, 15, false, | |
845 &original_visits2)); | |
846 history::URLRows original_entries; | |
847 original_entries.push_back(original_entry1); | |
848 original_entries.push_back(original_entry2); | |
849 | |
850 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
851 .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
852 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
853 .WillRepeatedly( | |
854 DoAll(SetArgumentPointee<2>(original_visits1), Return(true))); | |
855 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
856 StartSyncService(create_root.callback()); | |
857 | |
858 // Setting expired=true should cause the sync code to ignore this deletion. | |
859 history::URLRows rows; | |
860 rows.push_back(history::URLRow(GURL("http://mine.com"))); | |
861 SendNotificationURLsDeleted(false, true, rows, std::set<GURL>()); | |
862 history::URLRows new_sync_entries; | |
863 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
864 // Both URLs should still be there. | |
865 ASSERT_EQ(2U, new_sync_entries.size()); | |
866 } | |
867 | |
868 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) { | |
869 history::VisitVector original_visits1; | |
870 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry", | |
871 2, 15, false, | |
872 &original_visits1)); | |
873 history::VisitVector original_visits2; | |
874 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com", | |
875 "entry2", | |
876 3, 15, false, | |
877 &original_visits2)); | |
878 history::URLRows original_entries; | |
879 original_entries.push_back(original_entry1); | |
880 original_entries.push_back(original_entry2); | |
881 | |
882 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
883 .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
884 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
885 .WillRepeatedly( | |
886 DoAll(SetArgumentPointee<2>(original_visits1), Return(true))); | |
887 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
888 StartSyncService(create_root.callback()); | |
889 | |
890 history::URLRows new_sync_entries; | |
891 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
892 ASSERT_EQ(2U, new_sync_entries.size()); | |
893 | |
894 SendNotificationURLsDeleted(true, false, history::URLRows(), | |
895 std::set<GURL>()); | |
896 | |
897 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
898 ASSERT_EQ(0U, new_sync_entries.size()); | |
899 } | |
900 | |
901 TEST_F(ProfileSyncServiceTypedUrlTest, FailWriteToHistoryBackend) { | |
902 history::VisitVector native_visits; | |
903 history::VisitVector sync_visits; | |
904 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry", | |
905 2, 15, false, &native_visits)); | |
906 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", | |
907 3, 16, false, &sync_visits)); | |
908 | |
909 history::URLRows native_entries; | |
910 native_entries.push_back(native_entry); | |
911 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
912 .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true))); | |
913 EXPECT_CALL((history_backend()), GetURL(_, _)) | |
914 .WillOnce(DoAll(SetArgumentPointee<1>(native_entry), Return(false))); | |
915 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
916 .WillRepeatedly( | |
917 DoAll(SetArgumentPointee<2>(native_visits), Return(true))); | |
918 EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED)) | |
919 .WillRepeatedly(Return(false)); | |
920 | |
921 history::URLRows sync_entries; | |
922 sync_entries.push_back(sync_entry); | |
923 | |
924 EXPECT_CALL((history_backend()), UpdateURL(_, _)) | |
925 .WillRepeatedly(Return(false)); | |
926 TypedUrlSyncableService* syncable_service = | |
927 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries)); | |
928 // Errors writing to the DB should be recorded, but should not cause an | |
929 // unrecoverable error. | |
930 ASSERT_FALSE(sync_service()->data_type_status_table().GetFailedTypes().Has( | |
931 syncer::TYPED_URLS)); | |
932 // Some calls should have succeeded, so the error percentage should be | |
933 // somewhere > 0 and < 100. | |
934 ASSERT_NE(0, syncable_service->GetErrorPercentage()); | |
935 ASSERT_NE(100, syncable_service->GetErrorPercentage()); | |
936 } | |
937 | |
938 TEST_F(ProfileSyncServiceTypedUrlTest, FailToGetTypedURLs) { | |
939 history::VisitVector native_visits; | |
940 history::VisitVector sync_visits; | |
941 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry", | |
942 2, 15, false, &native_visits)); | |
943 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", | |
944 3, 16, false, &sync_visits)); | |
945 | |
946 history::URLRows native_entries; | |
947 native_entries.push_back(native_entry); | |
948 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
949 .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(false))); | |
950 | |
951 history::URLRows sync_entries; | |
952 sync_entries.push_back(sync_entry); | |
953 | |
954 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries)); | |
955 // Errors getting typed URLs will cause an unrecoverable error (since we can | |
956 // do *nothing* in that case). | |
957 ASSERT_TRUE(sync_service()->data_type_status_table().GetFailedTypes().Has( | |
958 syncer::TYPED_URLS)); | |
959 ASSERT_EQ(1u, | |
960 sync_service()->data_type_status_table().GetFailedTypes().Size()); | |
961 // Can't check GetErrorPercentage(), because generating an unrecoverable | |
962 // error will free the model associator. | |
963 } | |
964 | |
965 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalFileURL) { | |
966 history::VisitVector original_visits; | |
967 // Create http and file url. | |
968 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com", | |
969 "yey", 12, 15, false, | |
970 &original_visits)); | |
971 history::URLRow file_entry(MakeTypedUrlEntry("file:///kitty.jpg", | |
972 "kitteh", 12, 15, false, | |
973 &original_visits)); | |
974 | |
975 history::URLRows original_entries; | |
976 original_entries.push_back(url_entry); | |
977 original_entries.push_back(file_entry); | |
978 | |
979 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
980 .WillRepeatedly( | |
981 DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
982 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
983 .WillRepeatedly( | |
984 DoAll(SetArgumentPointee<2>(original_visits), Return(true))); | |
985 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
986 StartSyncService(create_root.callback()); | |
987 | |
988 history::VisitVector updated_visits; | |
989 // Create updates for the previous urls + a new file one. | |
990 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com", | |
991 "yey", 20, 15, false, | |
992 &updated_visits)); | |
993 history::URLRow updated_file_entry(MakeTypedUrlEntry("file:///cat.jpg", | |
994 "cat", 20, 15, false, | |
995 &updated_visits)); | |
996 history::URLRow new_file_entry(MakeTypedUrlEntry("file:///dog.jpg", | |
997 "dog", 20, 15, false, | |
998 &updated_visits)); | |
999 | |
1000 history::URLRows changed_urls; | |
1001 changed_urls.push_back(updated_url_entry); | |
1002 changed_urls.push_back(updated_file_entry); | |
1003 changed_urls.push_back(new_file_entry); | |
1004 SendNotificationURLsModified(changed_urls); | |
1005 | |
1006 history::URLRows new_sync_entries; | |
1007 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
1008 | |
1009 // We should ignore the local file urls (existing and updated), | |
1010 // and only be left with the updated http url. | |
1011 ASSERT_EQ(1U, new_sync_entries.size()); | |
1012 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0])); | |
1013 } | |
1014 | |
1015 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalhostURL) { | |
1016 history::VisitVector original_visits; | |
1017 // Create http and localhost url. | |
1018 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com", | |
1019 "yey", 12, 15, false, | |
1020 &original_visits)); | |
1021 history::URLRow localhost_entry(MakeTypedUrlEntry("http://localhost", | |
1022 "localhost", 12, 15, false, | |
1023 &original_visits)); | |
1024 | |
1025 history::URLRows original_entries; | |
1026 original_entries.push_back(url_entry); | |
1027 original_entries.push_back(localhost_entry); | |
1028 | |
1029 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
1030 .WillRepeatedly( | |
1031 DoAll(SetArgumentPointee<0>(original_entries), Return(true))); | |
1032 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
1033 .WillRepeatedly( | |
1034 DoAll(SetArgumentPointee<2>(original_visits), Return(true))); | |
1035 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
1036 StartSyncService(create_root.callback()); | |
1037 | |
1038 history::VisitVector updated_visits; | |
1039 // Update the previous entries and add a new localhost. | |
1040 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com", | |
1041 "yey", 20, 15, false, | |
1042 &updated_visits)); | |
1043 history::URLRow updated_localhost_entry(MakeTypedUrlEntry( | |
1044 "http://localhost:80", | |
1045 "localhost", 20, 15, false, | |
1046 &original_visits)); | |
1047 history::URLRow localhost_ip_entry(MakeTypedUrlEntry("http://127.0.0.1", | |
1048 "localhost", 12, 15, false, | |
1049 &original_visits)); | |
1050 | |
1051 history::URLRows changed_urls; | |
1052 changed_urls.push_back(updated_url_entry); | |
1053 changed_urls.push_back(updated_localhost_entry); | |
1054 changed_urls.push_back(localhost_ip_entry); | |
1055 SendNotificationURLsModified(changed_urls); | |
1056 | |
1057 history::URLRows new_sync_entries; | |
1058 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
1059 | |
1060 // We should ignore the localhost urls and left only with http url. | |
1061 ASSERT_EQ(1U, new_sync_entries.size()); | |
1062 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0])); | |
1063 } | |
1064 | |
1065 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreModificationWithoutValidVisit) { | |
1066 EXPECT_CALL((history_backend()), GetAllTypedURLs(_)) | |
1067 .WillRepeatedly(Return(true)); | |
1068 EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _)) | |
1069 .WillRepeatedly(Return(true)); | |
1070 | |
1071 CreateRootHelper create_root(this, syncer::TYPED_URLS); | |
1072 StartSyncService(create_root.callback()); | |
1073 | |
1074 history::VisitVector updated_visits; | |
1075 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com", | |
1076 "yey", 20, 0, false, | |
1077 &updated_visits)); | |
1078 | |
1079 history::URLRows changed_urls; | |
1080 changed_urls.push_back(updated_url_entry); | |
1081 SendNotificationURLsModified(changed_urls); | |
1082 | |
1083 history::URLRows new_sync_entries; | |
1084 GetTypedUrlsFromSyncDB(&new_sync_entries); | |
1085 | |
1086 // The change should be ignored. | |
1087 ASSERT_EQ(0U, new_sync_entries.size()); | |
1088 } | |
OLD | NEW |