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.
9 #include "testing/gtest/include/gtest/gtest.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread.h"
19 #include "base/time/time.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/history/history_backend.h"
22 #include "chrome/browser/history/history_db_task.h"
23 #include "chrome/browser/history/history_notifications.h"
24 #include "chrome/browser/history/history_service.h"
25 #include "chrome/browser/history/history_service_factory.h"
26 #include "chrome/browser/invalidation/fake_invalidation_service.h"
27 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
28 #include "chrome/browser/prefs/pref_service_syncable.h"
29 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
30 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
31 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
32 #include "chrome/browser/signin/signin_manager_factory.h"
33 #include "chrome/browser/sync/abstract_profile_sync_service_test.h"
34 #include "chrome/browser/sync/glue/sync_backend_host.h"
35 #include "chrome/browser/sync/glue/typed_url_change_processor.h"
36 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
37 #include "chrome/browser/sync/glue/typed_url_model_associator.h"
38 #include "chrome/browser/sync/profile_sync_components_factory.h"
39 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
40 #include "chrome/browser/sync/profile_sync_service.h"
41 #include "chrome/browser/sync/profile_sync_service_factory.h"
42 #include "chrome/browser/sync/profile_sync_test_util.h"
43 #include "chrome/browser/sync/test_profile_sync_service.h"
44 #include "chrome/test/base/testing_browser_process.h"
45 #include "chrome/test/base/testing_profile.h"
46 #include "chrome/test/base/testing_profile_manager.h"
47 #include "components/history/core/browser/history_types.h"
48 #include "components/invalidation/invalidation_service.h"
49 #include "components/invalidation/profile_invalidation_provider.h"
50 #include "components/keyed_service/core/refcounted_keyed_service.h"
51 #include "components/signin/core/browser/signin_manager.h"
52 #include "components/sync_driver/data_type_error_handler_mock.h"
53 #include "content/public/browser/notification_service.h"
54 #include "google_apis/gaia/gaia_constants.h"
55 #include "sync/internal_api/public/read_node.h"
56 #include "sync/internal_api/public/read_transaction.h"
57 #include "sync/internal_api/public/write_node.h"
58 #include "sync/internal_api/public/write_transaction.h"
59 #include "sync/protocol/typed_url_specifics.pb.h"
60 #include "testing/gmock/include/gmock/gmock.h"
65 using browser_sync::TypedUrlChangeProcessor;
66 using browser_sync::TypedUrlDataTypeController;
67 using browser_sync::TypedUrlModelAssociator;
68 using history::HistoryBackend;
70 using history::URLRow;
71 using syncer::syncable::WriteTransaction;
73 using testing::Return;
74 using testing::SetArgumentPointee;
83 const char kTestProfileName[] = "test-profile";
85 // Visits with this timestamp are treated as expired.
86 static const int EXPIRED_VISIT = -1;
88 class HistoryBackendMock : public HistoryBackend {
90 HistoryBackendMock() : HistoryBackend(base::FilePath(), NULL, NULL) {}
91 virtual bool IsExpiredVisitTime(const base::Time& time) override {
92 return time.ToInternalValue() == EXPIRED_VISIT;
94 MOCK_METHOD1(GetAllTypedURLs, bool(history::URLRows* entries));
95 MOCK_METHOD3(GetMostRecentVisitsForURL, bool(history::URLID id,
97 history::VisitVector* visits));
98 MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
99 MOCK_METHOD3(AddVisits, bool(const GURL& url,
100 const std::vector<history::VisitInfo>& visits,
101 history::VisitSource visit_source));
102 MOCK_METHOD1(RemoveVisits, bool(const history::VisitVector& visits));
103 MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
104 MOCK_METHOD2(SetPageTitle, void(const GURL& url,
105 const base::string16& title));
106 MOCK_METHOD1(DeleteURL, void(const GURL& url));
109 friend class ProfileSyncServiceTypedUrlTest;
111 virtual ~HistoryBackendMock() {}
114 class HistoryServiceMock : public HistoryService {
116 HistoryServiceMock(history::HistoryClient* client, Profile* profile)
117 : HistoryService(client, profile), backend_(NULL) {}
119 virtual void ScheduleDBTask(scoped_ptr<history::HistoryDBTask> task,
120 base::CancelableTaskTracker* tracker) override {
121 history::HistoryDBTask* task_raw = task.get();
122 task_runner_->PostTaskAndReply(
124 base::Bind(&HistoryServiceMock::RunTaskOnDBThread,
125 base::Unretained(this), task_raw),
126 base::Bind(&base::DeletePointer<history::HistoryDBTask>,
130 MOCK_METHOD0(Shutdown, void());
132 void ShutdownBaseService() {
133 HistoryService::Shutdown();
136 void set_task_runner(
137 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
138 DCHECK(task_runner.get());
139 task_runner_ = task_runner;
142 void set_backend(scoped_refptr<history::HistoryBackend> backend) {
147 virtual ~HistoryServiceMock() {}
149 void RunTaskOnDBThread(history::HistoryDBTask* task) {
150 EXPECT_TRUE(task->RunOnDBThread(backend_.get(), NULL));
153 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
154 scoped_refptr<history::HistoryBackend> backend_;
157 KeyedService* BuildFakeProfileInvalidationProvider(
158 content::BrowserContext* context) {
159 return new invalidation::ProfileInvalidationProvider(
160 scoped_ptr<invalidation::InvalidationService>(
161 new invalidation::FakeInvalidationService));
164 KeyedService* BuildHistoryService(content::BrowserContext* profile) {
165 return new HistoryServiceMock(NULL, static_cast<Profile*>(profile));
168 class TestTypedUrlModelAssociator : public TypedUrlModelAssociator {
170 TestTypedUrlModelAssociator(
171 ProfileSyncService* sync_service,
172 history::HistoryBackend* history_backend,
173 sync_driver::DataTypeErrorHandler* error_handler) :
174 TypedUrlModelAssociator(sync_service, history_backend, error_handler) {}
177 // Don't clear error stats - that way we can verify their values in our
179 void ClearErrorStats() override {}
182 ACTION_P2(ShutdownHistoryService, thread, service) {
183 service->ShutdownBaseService();
187 ACTION_P6(MakeTypedUrlSyncComponents,
195 new TestTypedUrlModelAssociator(service, hb, error_handler);
196 TypedUrlChangeProcessor* change_processor =
197 new TypedUrlChangeProcessor(profile, *model_associator, hb, dtc);
198 return ProfileSyncComponentsFactory::SyncComponents(*model_associator,
202 class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
204 void AddTypedUrlSyncNode(const history::URLRow& url,
205 const history::VisitVector& visits) {
206 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
207 syncer::ReadNode typed_url_root(&trans);
208 ASSERT_EQ(syncer::BaseNode::INIT_OK,
209 typed_url_root.InitTypeRoot(syncer::TYPED_URLS));
211 syncer::WriteNode node(&trans);
212 std::string tag = url.url().spec();
213 syncer::WriteNode::InitUniqueByCreationResult result =
214 node.InitUniqueByCreation(syncer::TYPED_URLS, typed_url_root, tag);
215 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
216 TypedUrlModelAssociator::WriteToSyncNode(url, visits, &node);
220 ProfileSyncServiceTypedUrlTest()
221 : profile_manager_(TestingBrowserProcess::GetGlobal()) {
222 history_thread_.reset(new Thread("history"));
225 void SetUp() override {
226 AbstractProfileSyncServiceTest::SetUp();
227 ASSERT_TRUE(profile_manager_.SetUp());
228 TestingProfile::TestingFactories testing_factories;
229 testing_factories.push_back(std::make_pair(
230 ProfileOAuth2TokenServiceFactory::GetInstance(),
231 BuildAutoIssuingFakeProfileOAuth2TokenService));
232 profile_ = profile_manager_.CreateTestingProfile(
234 scoped_ptr<PrefServiceSyncable>(),
235 base::UTF8ToUTF16(kTestProfileName),
239 invalidation::ProfileInvalidationProviderFactory::GetInstance()->
240 SetTestingFactory(profile_, BuildFakeProfileInvalidationProvider);
241 history_thread_->Start();
242 history_backend_ = new HistoryBackendMock();
243 history_service_ = static_cast<HistoryServiceMock*>(
244 HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
245 profile_, BuildHistoryService));
246 history_service_->set_task_runner(history_thread_->task_runner());
247 history_service_->set_backend(history_backend_);
250 void TearDown() override {
251 EXPECT_CALL((*history_service_), Shutdown())
252 .WillOnce(ShutdownHistoryService(history_thread_.release(),
255 profile_manager_.DeleteTestingProfile(kTestProfileName);
256 AbstractProfileSyncServiceTest::TearDown();
259 TypedUrlModelAssociator* StartSyncService(const base::Closure& callback) {
260 TypedUrlModelAssociator* model_associator = NULL;
261 if (!sync_service_) {
262 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
263 signin->SetAuthenticatedUsername("test");
264 sync_service_ = TestProfileSyncService::BuildAutoStartAsyncInit(profile_,
266 ProfileSyncComponentsFactoryMock* components =
267 sync_service_->components_factory_mock();
268 TypedUrlDataTypeController* data_type_controller =
269 new TypedUrlDataTypeController(components, profile_, sync_service_);
271 EXPECT_CALL(*components, CreateTypedUrlSyncComponents(_, _, _)).
272 WillOnce(MakeTypedUrlSyncComponents(profile_,
274 history_backend_.get(),
275 data_type_controller,
278 EXPECT_CALL(*components, CreateDataTypeManager(_, _, _, _, _)).
279 WillOnce(ReturnNewDataTypeManager());
281 ProfileOAuth2TokenService* oauth2_token_service =
282 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
283 oauth2_token_service->UpdateCredentials("test", "oauth2_login_token");
285 sync_service_->RegisterDataTypeController(data_type_controller);
287 sync_service_->Initialize();
288 base::MessageLoop::current()->Run();
290 return model_associator;
293 void GetTypedUrlsFromSyncDB(history::URLRows* urls) {
295 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
296 syncer::ReadNode typed_url_root(&trans);
297 if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
298 syncer::BaseNode::INIT_OK)
301 int64 child_id = typed_url_root.GetFirstChildId();
302 while (child_id != syncer::kInvalidId) {
303 syncer::ReadNode child_node(&trans);
304 if (child_node.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK)
307 const sync_pb::TypedUrlSpecifics& typed_url(
308 child_node.GetTypedUrlSpecifics());
309 history::URLRow new_url(GURL(typed_url.url()));
311 new_url.set_title(base::UTF8ToUTF16(typed_url.title()));
312 DCHECK(typed_url.visits_size());
313 DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size());
314 new_url.set_last_visit(base::Time::FromInternalValue(
315 typed_url.visits(typed_url.visits_size() - 1)));
316 new_url.set_hidden(typed_url.hidden());
318 urls->push_back(new_url);
319 child_id = child_node.GetSuccessorId();
323 void SetIdleChangeProcessorExpectations() {
324 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).Times(0);
325 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).Times(0);
326 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).Times(0);
327 EXPECT_CALL((*history_backend_.get()), DeleteURL(_)).Times(0);
330 void SendNotification(const base::Closure& task) {
331 history_thread_->task_runner()->PostTaskAndReply(
334 base::Bind(&base::MessageLoop::QuitNow,
335 base::Unretained(base::MessageLoop::current())));
336 base::MessageLoop::current()->Run();
339 void SendNotificationURLVisited(ui::PageTransition transition,
340 const history::URLRow& row) {
341 base::Time visit_time;
342 history::RedirectList redirects;
344 base::Bind(&HistoryBackendMock::NotifyURLVisited,
345 base::Unretained(history_backend_.get()),
352 static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
353 // Only verify the fields we explicitly sync (i.e. don't verify typed_count
354 // or visit_count because we rely on the history DB to manage those values
355 // and they are left unchanged by HistoryBackendMock).
356 return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
357 (lhs.title().compare(rhs.title()) == 0) &&
358 (lhs.last_visit() == rhs.last_visit()) &&
359 (lhs.hidden() == rhs.hidden());
362 static history::URLRow MakeTypedUrlEntry(const char* url,
367 history::VisitVector* visits) {
368 // Give each URL a unique ID, to mimic the behavior of the real database.
369 static int unique_url_id = 0;
371 URLRow history_url(gurl, ++unique_url_id);
372 history_url.set_title(base::UTF8ToUTF16(title));
373 history_url.set_typed_count(typed_count);
374 history_url.set_last_visit(
375 base::Time::FromInternalValue(last_visit));
376 history_url.set_hidden(hidden);
377 visits->push_back(history::VisitRow(
378 history_url.id(), history_url.last_visit(), 0,
379 ui::PAGE_TRANSITION_TYPED, 0));
380 history_url.set_visit_count(visits->size());
384 scoped_ptr<Thread> history_thread_;
385 TestingProfileManager profile_manager_;
386 TestingProfile* profile_;
387 scoped_refptr<HistoryBackendMock> history_backend_;
388 HistoryServiceMock* history_service_;
389 sync_driver::DataTypeErrorHandlerMock error_handler_;
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);
406 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
407 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
408 WillOnce(Return(true));
409 SetIdleChangeProcessorExpectations();
410 CreateRootHelper create_root(this, syncer::TYPED_URLS);
411 TypedUrlModelAssociator* associator =
412 StartSyncService(create_root.callback());
413 history::URLRows sync_entries;
414 GetTypedUrlsFromSyncDB(&sync_entries);
415 EXPECT_EQ(0U, sync_entries.size());
416 ASSERT_EQ(0, associator->GetErrorPercentage());
419 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
420 history::URLRows entries;
421 history::VisitVector visits;
422 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
423 2, 15, false, &visits));
425 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
426 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
427 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
428 WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
429 SetIdleChangeProcessorExpectations();
430 CreateRootHelper create_root(this, syncer::TYPED_URLS);
431 TypedUrlModelAssociator* associator =
432 StartSyncService(create_root.callback());
433 history::URLRows sync_entries;
434 GetTypedUrlsFromSyncDB(&sync_entries);
435 ASSERT_EQ(1U, sync_entries.size());
436 EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0]));
437 ASSERT_EQ(0, associator->GetErrorPercentage());
440 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeErrorReadingVisits) {
441 history::URLRows entries;
442 history::VisitVector visits;
443 history::URLRow native_entry1(MakeTypedUrlEntry("http://foo.com", "bar",
444 2, 15, false, &visits));
445 history::URLRow native_entry2(MakeTypedUrlEntry("http://foo2.com", "bar",
446 3, 15, false, &visits));
447 entries.push_back(native_entry1);
448 entries.push_back(native_entry2);
449 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
450 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
451 // Return an error from GetMostRecentVisitsForURL() for the second URL.
452 EXPECT_CALL((*history_backend_.get()),
453 GetMostRecentVisitsForURL(native_entry1.id(), _, _)).
454 WillRepeatedly(Return(true));
455 EXPECT_CALL((*history_backend_.get()),
456 GetMostRecentVisitsForURL(native_entry2.id(), _, _)).
457 WillRepeatedly(Return(false));
458 SetIdleChangeProcessorExpectations();
459 CreateRootHelper create_root(this, syncer::TYPED_URLS);
460 StartSyncService(create_root.callback());
461 history::URLRows sync_entries;
462 GetTypedUrlsFromSyncDB(&sync_entries);
463 ASSERT_EQ(1U, sync_entries.size());
464 EXPECT_TRUE(URLsEqual(native_entry1, sync_entries[0]));
467 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithBlankEmptySync) {
468 std::vector<history::URLRow> entries;
469 history::VisitVector visits;
471 entries.push_back(MakeTypedUrlEntry("", "bar",
472 2, 15, false, &visits));
473 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
474 2, 15, false, &visits));
475 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
476 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
477 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
478 WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
479 SetIdleChangeProcessorExpectations();
480 CreateRootHelper create_root(this, syncer::TYPED_URLS);
481 StartSyncService(create_root.callback());
482 std::vector<history::URLRow> sync_entries;
483 GetTypedUrlsFromSyncDB(&sync_entries);
484 // The empty URL should be ignored.
485 ASSERT_EQ(1U, sync_entries.size());
486 EXPECT_TRUE(URLsEqual(entries[1], sync_entries[0]));
489 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
490 history::VisitVector native_visits;
491 history::VisitVector sync_visits;
492 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
493 2, 15, false, &native_visits));
494 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
495 3, 16, false, &sync_visits));
497 history::URLRows native_entries;
498 native_entries.push_back(native_entry);
499 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
500 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
501 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
502 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
503 EXPECT_CALL((*history_backend_.get()),
504 AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(true));
506 history::URLRows sync_entries;
507 sync_entries.push_back(sync_entry);
509 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
510 WillRepeatedly(Return(true));
511 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
513 std::map<std::string, history::URLRow> expected;
514 expected[native_entry.url().spec()] = native_entry;
515 expected[sync_entry.url().spec()] = sync_entry;
517 history::URLRows new_sync_entries;
518 GetTypedUrlsFromSyncDB(&new_sync_entries);
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));
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,
532 history::URLRows sync_entries;
533 sync_entries.push_back(sync_entry);
535 // Since all our URLs are expired, no backend calls to add new URLs will be
537 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
538 WillOnce(Return(true));
539 SetIdleChangeProcessorExpectations();
541 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
544 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
545 history::VisitVector native_visits;
546 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
547 2, 15, false, &native_visits));
548 history::VisitVector sync_visits;
549 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name",
550 1, 17, false, &sync_visits));
551 history::VisitVector merged_visits;
552 merged_visits.push_back(history::VisitRow(
553 sync_entry.id(), base::Time::FromInternalValue(15), 0,
554 ui::PageTransitionFromInt(0), 0));
556 history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name",
557 2, 17, false, &merged_visits));
559 history::URLRows native_entries;
560 native_entries.push_back(native_entry);
561 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
562 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
563 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
564 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
565 EXPECT_CALL((*history_backend_.get()),
566 AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
568 history::URLRows sync_entries;
569 sync_entries.push_back(sync_entry);
571 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
572 WillRepeatedly(Return(true));
573 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
574 WillRepeatedly(Return());
575 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
577 history::URLRows new_sync_entries;
578 GetTypedUrlsFromSyncDB(&new_sync_entries);
579 ASSERT_EQ(1U, new_sync_entries.size());
580 EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0]));
583 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithErrorHasSyncMerge) {
584 history::VisitVector native_visits;
585 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "native",
586 2, 15, false, &native_visits));
587 history::VisitVector sync_visits;
588 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "sync",
589 1, 17, false, &sync_visits));
591 history::URLRows native_entries;
592 native_entries.push_back(native_entry);
593 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
594 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
595 // Return an error getting the visits for the native URL.
596 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
597 WillRepeatedly(Return(false));
598 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).
599 WillRepeatedly(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
600 EXPECT_CALL((*history_backend_.get()),
601 AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
603 history::URLRows sync_entries;
604 sync_entries.push_back(sync_entry);
606 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
607 WillRepeatedly(Return(true));
608 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
609 WillRepeatedly(Return());
610 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
612 history::URLRows new_sync_entries;
613 GetTypedUrlsFromSyncDB(&new_sync_entries);
614 ASSERT_EQ(1U, new_sync_entries.size());
615 EXPECT_TRUE(URLsEqual(sync_entry, new_sync_entries[0]));
618 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
619 history::VisitVector added_visits;
620 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
621 2, 15, false, &added_visits));
623 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
624 WillOnce(Return(true));
625 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
626 WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
628 SetIdleChangeProcessorExpectations();
629 CreateRootHelper create_root(this, syncer::TYPED_URLS);
630 StartSyncService(create_root.callback());
632 history::URLsModifiedDetails details;
633 details.changed_urls.push_back(added_entry);
634 scoped_refptr<ThreadNotifier> notifier(
635 new ThreadNotifier(history_thread_.get()));
636 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
637 content::Source<Profile>(profile_),
638 content::Details<history::URLsModifiedDetails>(&details));
640 history::URLRows new_sync_entries;
641 GetTypedUrlsFromSyncDB(&new_sync_entries);
642 ASSERT_EQ(1U, new_sync_entries.size());
643 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
646 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddWithBlank) {
647 history::VisitVector added_visits;
648 history::URLRow empty_entry(MakeTypedUrlEntry("", "entry",
649 2, 15, false, &added_visits));
650 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
651 2, 15, false, &added_visits));
653 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
654 WillOnce(Return(true));
655 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
656 WillRepeatedly(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
658 SetIdleChangeProcessorExpectations();
659 CreateRootHelper create_root(this, syncer::TYPED_URLS);
660 StartSyncService(create_root.callback());
662 history::URLsModifiedDetails details;
663 details.changed_urls.push_back(empty_entry);
664 details.changed_urls.push_back(added_entry);
665 scoped_refptr<ThreadNotifier> notifier(
666 new ThreadNotifier(history_thread_.get()));
667 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
668 content::Source<Profile>(profile_),
669 content::Details<history::URLsModifiedDetails>(&details));
671 std::vector<history::URLRow> new_sync_entries;
672 GetTypedUrlsFromSyncDB(&new_sync_entries);
673 ASSERT_EQ(1U, new_sync_entries.size());
674 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
677 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
678 history::VisitVector original_visits;
679 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
682 history::URLRows original_entries;
683 original_entries.push_back(original_entry);
685 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
686 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
687 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
688 WillOnce(DoAll(SetArgumentPointee<2>(original_visits),
690 CreateRootHelper create_root(this, syncer::TYPED_URLS);
691 StartSyncService(create_root.callback());
693 history::VisitVector updated_visits;
694 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
697 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
698 WillOnce(DoAll(SetArgumentPointee<2>(updated_visits),
701 history::URLsModifiedDetails details;
702 details.changed_urls.push_back(updated_entry);
703 scoped_refptr<ThreadNotifier> notifier(
704 new ThreadNotifier(history_thread_.get()));
705 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
706 content::Source<Profile>(profile_),
707 content::Details<history::URLsModifiedDetails>(&details));
709 history::URLRows new_sync_entries;
710 GetTypedUrlsFromSyncDB(&new_sync_entries);
711 ASSERT_EQ(1U, new_sync_entries.size());
712 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
715 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddFromVisit) {
716 history::VisitVector added_visits;
717 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
718 2, 15, false, &added_visits));
720 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
721 WillOnce(Return(true));
722 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
723 WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
725 SetIdleChangeProcessorExpectations();
726 CreateRootHelper create_root(this, syncer::TYPED_URLS);
727 StartSyncService(create_root.callback());
729 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, added_entry);
731 history::URLRows new_sync_entries;
732 GetTypedUrlsFromSyncDB(&new_sync_entries);
733 ASSERT_EQ(1U, new_sync_entries.size());
734 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
737 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdateFromVisit) {
738 history::VisitVector original_visits;
739 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
742 history::URLRows original_entries;
743 original_entries.push_back(original_entry);
745 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
746 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
747 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
748 WillOnce(DoAll(SetArgumentPointee<2>(original_visits),
750 CreateRootHelper create_root(this, syncer::TYPED_URLS);
751 StartSyncService(create_root.callback());
753 history::VisitVector updated_visits;
754 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
757 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
758 WillOnce(DoAll(SetArgumentPointee<2>(updated_visits),
761 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, updated_entry);
763 history::URLRows new_sync_entries;
764 GetTypedUrlsFromSyncDB(&new_sync_entries);
765 ASSERT_EQ(1U, new_sync_entries.size());
766 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
769 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserIgnoreChangeUpdateFromVisit) {
770 history::VisitVector original_visits;
771 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
774 history::URLRows original_entries;
775 original_entries.push_back(original_entry);
777 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
778 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
779 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
780 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
782 CreateRootHelper create_root(this, syncer::TYPED_URLS);
783 StartSyncService(create_root.callback());
784 history::URLRows new_sync_entries;
785 GetTypedUrlsFromSyncDB(&new_sync_entries);
786 ASSERT_EQ(1U, new_sync_entries.size());
787 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
789 history::VisitVector updated_visits;
790 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
794 // Should ignore this change because it's not TYPED.
795 SendNotificationURLVisited(ui::PAGE_TRANSITION_RELOAD, updated_entry);
796 GetTypedUrlsFromSyncDB(&new_sync_entries);
798 // Should be no changes to the sync DB from this notification.
799 ASSERT_EQ(1U, new_sync_entries.size());
800 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
802 // Now, try updating it with a large number of visits not divisible by 10
803 // (should ignore this visit).
804 history::URLRow twelve_visits(MakeTypedUrlEntry("http://mine.com", "entry",
807 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twelve_visits);
808 GetTypedUrlsFromSyncDB(&new_sync_entries);
810 // Should be no changes to the sync DB from this notification.
811 ASSERT_EQ(1U, new_sync_entries.size());
812 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
814 // Now, try updating it with a large number of visits that is divisible by 10
815 // (should *not* be ignored).
816 history::URLRow twenty_visits(MakeTypedUrlEntry("http://mine.com", "entry",
819 SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twenty_visits);
820 GetTypedUrlsFromSyncDB(&new_sync_entries);
822 ASSERT_EQ(1U, new_sync_entries.size());
823 EXPECT_TRUE(URLsEqual(twenty_visits, new_sync_entries[0]));
826 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
827 history::VisitVector original_visits1;
828 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
831 history::VisitVector original_visits2;
832 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
836 history::URLRows original_entries;
837 original_entries.push_back(original_entry1);
838 original_entries.push_back(original_entry2);
840 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
841 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
842 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
843 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
845 CreateRootHelper create_root(this, syncer::TYPED_URLS);
846 StartSyncService(create_root.callback());
848 history::URLsDeletedDetails changes;
849 changes.all_history = false;
850 changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
851 scoped_refptr<ThreadNotifier> notifier(
852 new ThreadNotifier(history_thread_.get()));
853 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
854 content::Source<Profile>(profile_),
855 content::Details<history::URLsDeletedDetails>(&changes));
857 history::URLRows new_sync_entries;
858 GetTypedUrlsFromSyncDB(&new_sync_entries);
859 ASSERT_EQ(1U, new_sync_entries.size());
860 EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0]));
863 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveExpired) {
864 history::VisitVector original_visits1;
865 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
868 history::VisitVector original_visits2;
869 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
873 history::URLRows original_entries;
874 original_entries.push_back(original_entry1);
875 original_entries.push_back(original_entry2);
877 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
878 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
879 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
880 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
882 CreateRootHelper create_root(this, syncer::TYPED_URLS);
883 StartSyncService(create_root.callback());
885 history::URLsDeletedDetails changes;
886 changes.all_history = false;
887 // Setting expired=true should cause the sync code to ignore this deletion.
888 changes.expired = true;
889 changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
890 scoped_refptr<ThreadNotifier> notifier(
891 new ThreadNotifier(history_thread_.get()));
892 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
893 content::Source<Profile>(profile_),
894 content::Details<history::URLsDeletedDetails>(&changes));
896 history::URLRows new_sync_entries;
897 GetTypedUrlsFromSyncDB(&new_sync_entries);
898 // Both URLs should still be there.
899 ASSERT_EQ(2U, new_sync_entries.size());
902 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
903 history::VisitVector original_visits1;
904 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
907 history::VisitVector original_visits2;
908 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
912 history::URLRows original_entries;
913 original_entries.push_back(original_entry1);
914 original_entries.push_back(original_entry2);
916 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
917 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
918 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
919 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
921 CreateRootHelper create_root(this, syncer::TYPED_URLS);
922 StartSyncService(create_root.callback());
924 history::URLRows new_sync_entries;
925 GetTypedUrlsFromSyncDB(&new_sync_entries);
926 ASSERT_EQ(2U, new_sync_entries.size());
928 history::URLsDeletedDetails changes;
929 changes.all_history = true;
930 scoped_refptr<ThreadNotifier> notifier(
931 new ThreadNotifier(history_thread_.get()));
932 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
933 content::Source<Profile>(profile_),
934 content::Details<history::URLsDeletedDetails>(&changes));
936 GetTypedUrlsFromSyncDB(&new_sync_entries);
937 ASSERT_EQ(0U, new_sync_entries.size());
940 TEST_F(ProfileSyncServiceTypedUrlTest, FailWriteToHistoryBackend) {
941 history::VisitVector native_visits;
942 history::VisitVector sync_visits;
943 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
944 2, 15, false, &native_visits));
945 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
946 3, 16, false, &sync_visits));
948 history::URLRows native_entries;
949 native_entries.push_back(native_entry);
950 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
951 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
952 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).
953 WillOnce(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
954 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
955 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
956 EXPECT_CALL((*history_backend_.get()),
957 AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(false));
959 history::URLRows sync_entries;
960 sync_entries.push_back(sync_entry);
962 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
963 WillRepeatedly(Return(false));
964 TypedUrlModelAssociator* associator =
965 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
966 // Errors writing to the DB should be recorded, but should not cause an
967 // unrecoverable error.
969 sync_service_->data_type_status_table().GetFailedTypes().Has(
970 syncer::TYPED_URLS));
971 // Some calls should have succeeded, so the error percentage should be
972 // somewhere > 0 and < 100.
973 ASSERT_NE(0, associator->GetErrorPercentage());
974 ASSERT_NE(100, associator->GetErrorPercentage());
977 TEST_F(ProfileSyncServiceTypedUrlTest, FailToGetTypedURLs) {
978 history::VisitVector native_visits;
979 history::VisitVector sync_visits;
980 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
981 2, 15, false, &native_visits));
982 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
983 3, 16, false, &sync_visits));
985 history::URLRows native_entries;
986 native_entries.push_back(native_entry);
987 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
988 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(false)));
990 history::URLRows sync_entries;
991 sync_entries.push_back(sync_entry);
993 EXPECT_CALL(error_handler_, CreateAndUploadError(_, _, _)).
994 WillOnce(Return(syncer::SyncError(
996 syncer::SyncError::DATATYPE_ERROR,
998 syncer::TYPED_URLS)));
999 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
1000 // Errors getting typed URLs will cause an unrecoverable error (since we can
1001 // do *nothing* in that case).
1003 sync_service_->data_type_status_table().GetFailedTypes().Has(
1004 syncer::TYPED_URLS));
1006 1u, sync_service_->data_type_status_table().GetFailedTypes().Size());
1007 // Can't check GetErrorPercentage(), because generating an unrecoverable
1008 // error will free the model associator.
1011 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalFileURL) {
1012 history::VisitVector original_visits;
1013 // Create http and file url.
1014 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
1015 "yey", 12, 15, false,
1017 history::URLRow file_entry(MakeTypedUrlEntry("file:///kitty.jpg",
1018 "kitteh", 12, 15, false,
1021 history::URLRows original_entries;
1022 original_entries.push_back(url_entry);
1023 original_entries.push_back(file_entry);
1025 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
1026 WillRepeatedly(DoAll(SetArgumentPointee<0>(original_entries),
1028 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
1029 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
1031 CreateRootHelper create_root(this, syncer::TYPED_URLS);
1032 StartSyncService(create_root.callback());
1034 history::VisitVector updated_visits;
1035 // Create updates for the previous urls + a new file one.
1036 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1037 "yey", 20, 15, false,
1039 history::URLRow updated_file_entry(MakeTypedUrlEntry("file:///cat.jpg",
1040 "cat", 20, 15, false,
1042 history::URLRow new_file_entry(MakeTypedUrlEntry("file:///dog.jpg",
1043 "dog", 20, 15, false,
1045 history::URLsModifiedDetails details;
1046 details.changed_urls.push_back(updated_url_entry);
1047 details.changed_urls.push_back(updated_file_entry);
1048 details.changed_urls.push_back(new_file_entry);
1049 scoped_refptr<ThreadNotifier> notifier(
1050 new ThreadNotifier(history_thread_.get()));
1051 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1052 content::Source<Profile>(profile_),
1053 content::Details<history::URLsModifiedDetails>(&details));
1055 history::URLRows new_sync_entries;
1056 GetTypedUrlsFromSyncDB(&new_sync_entries);
1058 // We should ignore the local file urls (existing and updated),
1059 // and only be left with the updated http url.
1060 ASSERT_EQ(1U, new_sync_entries.size());
1061 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
1064 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalhostURL) {
1065 history::VisitVector original_visits;
1066 // Create http and localhost url.
1067 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
1068 "yey", 12, 15, false,
1070 history::URLRow localhost_entry(MakeTypedUrlEntry("http://localhost",
1071 "localhost", 12, 15, false,
1074 history::URLRows original_entries;
1075 original_entries.push_back(url_entry);
1076 original_entries.push_back(localhost_entry);
1078 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
1079 WillRepeatedly(DoAll(SetArgumentPointee<0>(original_entries),
1081 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
1082 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
1084 CreateRootHelper create_root(this, syncer::TYPED_URLS);
1085 StartSyncService(create_root.callback());
1087 history::VisitVector updated_visits;
1088 // Update the previous entries and add a new localhost.
1089 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1090 "yey", 20, 15, false,
1092 history::URLRow updated_localhost_entry(MakeTypedUrlEntry(
1093 "http://localhost:80",
1094 "localhost", 20, 15, false,
1096 history::URLRow localhost_ip_entry(MakeTypedUrlEntry("http://127.0.0.1",
1097 "localhost", 12, 15, false,
1099 history::URLsModifiedDetails details;
1100 details.changed_urls.push_back(updated_url_entry);
1101 details.changed_urls.push_back(updated_localhost_entry);
1102 details.changed_urls.push_back(localhost_ip_entry);
1103 scoped_refptr<ThreadNotifier> notifier(
1104 new ThreadNotifier(history_thread_.get()));
1105 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1106 content::Source<Profile>(profile_),
1107 content::Details<history::URLsModifiedDetails>(&details));
1109 history::URLRows new_sync_entries;
1110 GetTypedUrlsFromSyncDB(&new_sync_entries);
1112 // We should ignore the localhost urls and left only with http url.
1113 ASSERT_EQ(1U, new_sync_entries.size());
1114 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
1117 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreModificationWithoutValidVisit) {
1118 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
1119 WillRepeatedly(Return(true));
1120 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
1121 WillRepeatedly(Return(true));
1123 CreateRootHelper create_root(this, syncer::TYPED_URLS);
1124 StartSyncService(create_root.callback());
1126 history::VisitVector updated_visits;
1127 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1128 "yey", 20, 0, false,
1130 history::URLsModifiedDetails details;
1131 details.changed_urls.push_back(updated_url_entry);
1132 scoped_refptr<ThreadNotifier> notifier(
1133 new ThreadNotifier(history_thread_.get()));
1134 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1135 content::Source<Profile>(profile_),
1136 content::Details<history::URLsModifiedDetails>(&details));
1138 history::URLRows new_sync_entries;
1139 GetTypedUrlsFromSyncDB(&new_sync_entries);
1141 // The change should be ignored.
1142 ASSERT_EQ(0U, new_sync_entries.size());