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.
7 #include "testing/gtest/include/gtest/gtest.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/location.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/history/history_backend.h"
20 #include "chrome/browser/history/history_db_task.h"
21 #include "chrome/browser/history/history_notifications.h"
22 #include "chrome/browser/history/history_service.h"
23 #include "chrome/browser/history/history_service_factory.h"
24 #include "chrome/browser/history/history_types.h"
25 #include "chrome/browser/invalidation/invalidation_service_factory.h"
26 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
27 #include "chrome/browser/signin/fake_profile_oauth2_token_service_wrapper.h"
28 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
29 #include "chrome/browser/signin/signin_manager.h"
30 #include "chrome/browser/signin/signin_manager_factory.h"
31 #include "chrome/browser/sync/abstract_profile_sync_service_test.h"
32 #include "chrome/browser/sync/glue/sync_backend_host.h"
33 #include "chrome/browser/sync/glue/typed_url_change_processor.h"
34 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
35 #include "chrome/browser/sync/glue/typed_url_model_associator.h"
36 #include "chrome/browser/sync/profile_sync_components_factory.h"
37 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
38 #include "chrome/browser/sync/profile_sync_service.h"
39 #include "chrome/browser/sync/profile_sync_service_factory.h"
40 #include "chrome/browser/sync/profile_sync_test_util.h"
41 #include "chrome/browser/sync/test_profile_sync_service.h"
42 #include "chrome/test/base/testing_profile.h"
43 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
44 #include "components/sync_driver/data_type_error_handler_mock.h"
45 #include "content/public/browser/notification_service.h"
46 #include "google_apis/gaia/gaia_constants.h"
47 #include "sync/internal_api/public/read_node.h"
48 #include "sync/internal_api/public/read_transaction.h"
49 #include "sync/internal_api/public/write_node.h"
50 #include "sync/internal_api/public/write_transaction.h"
51 #include "sync/protocol/typed_url_specifics.pb.h"
52 #include "testing/gmock/include/gmock/gmock.h"
57 using browser_sync::TypedUrlChangeProcessor;
58 using browser_sync::TypedUrlDataTypeController;
59 using browser_sync::TypedUrlModelAssociator;
60 using history::HistoryBackend;
62 using history::URLRow;
63 using syncer::syncable::WriteTransaction;
66 using testing::Return;
67 using testing::SetArgumentPointee;
70 // Visits with this timestamp are treated as expired.
71 static const int EXPIRED_VISIT = -1;
73 class HistoryBackendMock : public HistoryBackend {
75 HistoryBackendMock() : HistoryBackend(base::FilePath(), 0, NULL, NULL) {}
76 virtual bool IsExpiredVisitTime(const base::Time& time) OVERRIDE {
77 return time.ToInternalValue() == EXPIRED_VISIT;
79 MOCK_METHOD1(GetAllTypedURLs, bool(history::URLRows* entries));
80 MOCK_METHOD3(GetMostRecentVisitsForURL, bool(history::URLID id,
82 history::VisitVector* visits));
83 MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
84 MOCK_METHOD3(AddVisits, bool(const GURL& url,
85 const std::vector<history::VisitInfo>& visits,
86 history::VisitSource visit_source));
87 MOCK_METHOD1(RemoveVisits, bool(const history::VisitVector& visits));
88 MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
89 MOCK_METHOD2(SetPageTitle, void(const GURL& url,
90 const base::string16& title));
91 MOCK_METHOD1(DeleteURL, void(const GURL& url));
94 virtual ~HistoryBackendMock() {}
97 class HistoryServiceMock : public HistoryService {
99 explicit HistoryServiceMock(Profile* profile) : HistoryService(profile) {}
100 MOCK_METHOD2(ScheduleDBTask, void(history::HistoryDBTask*,
101 CancelableRequestConsumerBase*));
102 MOCK_METHOD0(Shutdown, void());
104 void ShutdownBaseService() {
105 HistoryService::Shutdown();
109 virtual ~HistoryServiceMock() {}
112 BrowserContextKeyedService* BuildHistoryService(
113 content::BrowserContext* profile) {
114 return new HistoryServiceMock(static_cast<Profile*>(profile));
117 class TestTypedUrlModelAssociator : public TypedUrlModelAssociator {
119 TestTypedUrlModelAssociator(
120 ProfileSyncService* sync_service,
121 history::HistoryBackend* history_backend,
122 browser_sync::DataTypeErrorHandler* error_handler) :
123 TypedUrlModelAssociator(sync_service, history_backend, error_handler) {}
126 // Don't clear error stats - that way we can verify their values in our
128 virtual void ClearErrorStats() OVERRIDE {}
131 void RunOnDBThreadCallback(HistoryBackend* backend,
132 history::HistoryDBTask* task) {
133 task->RunOnDBThread(backend, NULL);
136 ACTION_P2(RunTaskOnDBThread, thread, backend) {
137 // ScheduleDBTask takes ownership of its task argument, so we
139 scoped_refptr<history::HistoryDBTask> task(arg0);
140 thread->message_loop()->PostTask(
141 FROM_HERE, base::Bind(&RunOnDBThreadCallback, base::Unretained(backend),
145 ACTION_P2(ShutdownHistoryService, thread, service) {
146 service->ShutdownBaseService();
150 ACTION_P6(MakeTypedUrlSyncComponents,
158 new TestTypedUrlModelAssociator(service, hb, error_handler);
159 TypedUrlChangeProcessor* change_processor =
160 new TypedUrlChangeProcessor(profile, *model_associator, hb, dtc);
161 return ProfileSyncComponentsFactory::SyncComponents(*model_associator,
165 class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
167 void AddTypedUrlSyncNode(const history::URLRow& url,
168 const history::VisitVector& visits) {
169 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
170 syncer::ReadNode typed_url_root(&trans);
171 ASSERT_EQ(syncer::BaseNode::INIT_OK,
172 typed_url_root.InitByTagLookup(browser_sync::kTypedUrlTag));
174 syncer::WriteNode node(&trans);
175 std::string tag = url.url().spec();
176 syncer::WriteNode::InitUniqueByCreationResult result =
177 node.InitUniqueByCreation(syncer::TYPED_URLS, typed_url_root, tag);
178 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
179 TypedUrlModelAssociator::WriteToSyncNode(url, visits, &node);
183 ProfileSyncServiceTypedUrlTest() {
184 history_thread_.reset(new Thread("history"));
187 virtual void SetUp() {
188 AbstractProfileSyncServiceTest::SetUp();
189 TestingProfile::Builder builder;
190 builder.AddTestingFactory(
191 ProfileOAuth2TokenServiceFactory::GetInstance(),
192 FakeProfileOAuth2TokenServiceWrapper::BuildAutoIssuingTokenService);
193 profile_ = builder.Build().Pass();
194 invalidation::InvalidationServiceFactory::GetInstance()->
195 SetBuildOnlyFakeInvalidatorsForTest(true);
196 history_backend_ = new HistoryBackendMock();
197 history_service_ = static_cast<HistoryServiceMock*>(
198 HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
199 profile_.get(), BuildHistoryService));
200 EXPECT_CALL((*history_service_), ScheduleDBTask(_, _))
201 .WillRepeatedly(RunTaskOnDBThread(history_thread_.get(),
202 history_backend_.get()));
203 history_thread_->Start();
206 virtual void TearDown() {
207 EXPECT_CALL((*history_service_), Shutdown())
208 .WillOnce(ShutdownHistoryService(history_thread_.release(),
211 AbstractProfileSyncServiceTest::TearDown();
214 TypedUrlModelAssociator* StartSyncService(const base::Closure& callback) {
215 TypedUrlModelAssociator* model_associator = NULL;
216 if (!sync_service_) {
217 SigninManagerBase* signin =
218 SigninManagerFactory::GetForProfile(profile_.get());
219 signin->SetAuthenticatedUsername("test");
220 sync_service_ = TestProfileSyncService::BuildAutoStartAsyncInit(
221 profile_.get(), callback);
222 ProfileSyncComponentsFactoryMock* components =
223 sync_service_->components_factory_mock();
224 TypedUrlDataTypeController* data_type_controller =
225 new TypedUrlDataTypeController(components,
229 EXPECT_CALL(*components, CreateTypedUrlSyncComponents(_, _, _)).
230 WillOnce(MakeTypedUrlSyncComponents(profile_.get(),
232 history_backend_.get(),
233 data_type_controller,
236 EXPECT_CALL(*components, CreateDataTypeManager(_, _, _, _, _, _)).
237 WillOnce(ReturnNewDataTypeManager());
239 ProfileOAuth2TokenService* oauth2_token_service =
240 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
241 oauth2_token_service->UpdateCredentials("test", "oauth2_login_token");
243 sync_service_->RegisterDataTypeController(data_type_controller);
245 sync_service_->Initialize();
246 base::MessageLoop::current()->Run();
248 return model_associator;
251 void GetTypedUrlsFromSyncDB(history::URLRows* urls) {
253 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
254 syncer::ReadNode typed_url_root(&trans);
255 if (typed_url_root.InitByTagLookup(browser_sync::kTypedUrlTag) !=
256 syncer::BaseNode::INIT_OK)
259 int64 child_id = typed_url_root.GetFirstChildId();
260 while (child_id != syncer::kInvalidId) {
261 syncer::ReadNode child_node(&trans);
262 if (child_node.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK)
265 const sync_pb::TypedUrlSpecifics& typed_url(
266 child_node.GetTypedUrlSpecifics());
267 history::URLRow new_url(GURL(typed_url.url()));
269 new_url.set_title(base::UTF8ToUTF16(typed_url.title()));
270 DCHECK(typed_url.visits_size());
271 DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size());
272 new_url.set_last_visit(base::Time::FromInternalValue(
273 typed_url.visits(typed_url.visits_size() - 1)));
274 new_url.set_hidden(typed_url.hidden());
276 urls->push_back(new_url);
277 child_id = child_node.GetSuccessorId();
281 void SetIdleChangeProcessorExpectations() {
282 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).Times(0);
283 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).Times(0);
284 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).Times(0);
285 EXPECT_CALL((*history_backend_.get()), DeleteURL(_)).Times(0);
288 static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
289 // Only verify the fields we explicitly sync (i.e. don't verify typed_count
290 // or visit_count because we rely on the history DB to manage those values
291 // and they are left unchanged by HistoryBackendMock).
292 return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
293 (lhs.title().compare(rhs.title()) == 0) &&
294 (lhs.last_visit() == rhs.last_visit()) &&
295 (lhs.hidden() == rhs.hidden());
298 static history::URLRow MakeTypedUrlEntry(const char* url,
303 history::VisitVector* visits) {
304 // Give each URL a unique ID, to mimic the behavior of the real database.
305 static int unique_url_id = 0;
307 URLRow history_url(gurl, ++unique_url_id);
308 history_url.set_title(base::UTF8ToUTF16(title));
309 history_url.set_typed_count(typed_count);
310 history_url.set_last_visit(
311 base::Time::FromInternalValue(last_visit));
312 history_url.set_hidden(hidden);
313 visits->push_back(history::VisitRow(
314 history_url.id(), history_url.last_visit(), 0,
315 content::PAGE_TRANSITION_TYPED, 0));
316 history_url.set_visit_count(visits->size());
320 scoped_ptr<Thread> history_thread_;
322 scoped_ptr<TestingProfile> profile_;
323 scoped_refptr<HistoryBackendMock> history_backend_;
324 HistoryServiceMock* history_service_;
325 browser_sync::DataTypeErrorHandlerMock error_handler_;
328 void AddTypedUrlEntries(ProfileSyncServiceTypedUrlTest* test,
329 const history::URLRows& entries) {
330 test->CreateRoot(syncer::TYPED_URLS);
331 for (size_t i = 0; i < entries.size(); ++i) {
332 history::VisitVector visits;
333 visits.push_back(history::VisitRow(
334 entries[i].id(), entries[i].last_visit(), 0,
335 content::PageTransitionFromInt(0), 0));
336 test->AddTypedUrlSyncNode(entries[i], visits);
342 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
343 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
344 WillOnce(Return(true));
345 SetIdleChangeProcessorExpectations();
346 CreateRootHelper create_root(this, syncer::TYPED_URLS);
347 TypedUrlModelAssociator* associator =
348 StartSyncService(create_root.callback());
349 history::URLRows sync_entries;
350 GetTypedUrlsFromSyncDB(&sync_entries);
351 EXPECT_EQ(0U, sync_entries.size());
352 ASSERT_EQ(0, associator->GetErrorPercentage());
355 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
356 history::URLRows entries;
357 history::VisitVector visits;
358 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
359 2, 15, false, &visits));
361 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
362 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
363 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
364 WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
365 SetIdleChangeProcessorExpectations();
366 CreateRootHelper create_root(this, syncer::TYPED_URLS);
367 TypedUrlModelAssociator* associator =
368 StartSyncService(create_root.callback());
369 history::URLRows sync_entries;
370 GetTypedUrlsFromSyncDB(&sync_entries);
371 ASSERT_EQ(1U, sync_entries.size());
372 EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0]));
373 ASSERT_EQ(0, associator->GetErrorPercentage());
376 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeErrorReadingVisits) {
377 history::URLRows entries;
378 history::VisitVector visits;
379 history::URLRow native_entry1(MakeTypedUrlEntry("http://foo.com", "bar",
380 2, 15, false, &visits));
381 history::URLRow native_entry2(MakeTypedUrlEntry("http://foo2.com", "bar",
382 3, 15, false, &visits));
383 entries.push_back(native_entry1);
384 entries.push_back(native_entry2);
385 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
386 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
387 // Return an error from GetMostRecentVisitsForURL() for the second URL.
388 EXPECT_CALL((*history_backend_.get()),
389 GetMostRecentVisitsForURL(native_entry1.id(), _, _)).
390 WillRepeatedly(Return(true));
391 EXPECT_CALL((*history_backend_.get()),
392 GetMostRecentVisitsForURL(native_entry2.id(), _, _)).
393 WillRepeatedly(Return(false));
394 SetIdleChangeProcessorExpectations();
395 CreateRootHelper create_root(this, syncer::TYPED_URLS);
396 StartSyncService(create_root.callback());
397 history::URLRows sync_entries;
398 GetTypedUrlsFromSyncDB(&sync_entries);
399 ASSERT_EQ(1U, sync_entries.size());
400 EXPECT_TRUE(URLsEqual(native_entry1, sync_entries[0]));
403 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithBlankEmptySync) {
404 std::vector<history::URLRow> entries;
405 history::VisitVector visits;
407 entries.push_back(MakeTypedUrlEntry("", "bar",
408 2, 15, false, &visits));
409 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
410 2, 15, false, &visits));
411 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
412 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
413 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
414 WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
415 SetIdleChangeProcessorExpectations();
416 CreateRootHelper create_root(this, syncer::TYPED_URLS);
417 StartSyncService(create_root.callback());
418 std::vector<history::URLRow> sync_entries;
419 GetTypedUrlsFromSyncDB(&sync_entries);
420 // The empty URL should be ignored.
421 ASSERT_EQ(1U, sync_entries.size());
422 EXPECT_TRUE(URLsEqual(entries[1], sync_entries[0]));
425 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
426 history::VisitVector native_visits;
427 history::VisitVector sync_visits;
428 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
429 2, 15, false, &native_visits));
430 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
431 3, 16, false, &sync_visits));
433 history::URLRows native_entries;
434 native_entries.push_back(native_entry);
435 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
436 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
437 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
438 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
439 EXPECT_CALL((*history_backend_.get()),
440 AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(true));
442 history::URLRows sync_entries;
443 sync_entries.push_back(sync_entry);
445 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
446 WillRepeatedly(Return(true));
447 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
449 std::map<std::string, history::URLRow> expected;
450 expected[native_entry.url().spec()] = native_entry;
451 expected[sync_entry.url().spec()] = sync_entry;
453 history::URLRows new_sync_entries;
454 GetTypedUrlsFromSyncDB(&new_sync_entries);
456 EXPECT_TRUE(new_sync_entries.size() == expected.size());
457 for (history::URLRows::iterator entry = new_sync_entries.begin();
458 entry != new_sync_entries.end(); ++entry) {
459 EXPECT_TRUE(URLsEqual(expected[entry->url().spec()], *entry));
463 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeExpiredSync) {
464 history::VisitVector sync_visits;
465 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
466 3, EXPIRED_VISIT, false,
468 history::URLRows sync_entries;
469 sync_entries.push_back(sync_entry);
471 // Since all our URLs are expired, no backend calls to add new URLs will be
473 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
474 WillOnce(Return(true));
475 SetIdleChangeProcessorExpectations();
477 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
480 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
481 history::VisitVector native_visits;
482 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
483 2, 15, false, &native_visits));
484 history::VisitVector sync_visits;
485 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name",
486 1, 17, false, &sync_visits));
487 history::VisitVector merged_visits;
488 merged_visits.push_back(history::VisitRow(
489 sync_entry.id(), base::Time::FromInternalValue(15), 0,
490 content::PageTransitionFromInt(0), 0));
492 history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name",
493 2, 17, false, &merged_visits));
495 history::URLRows native_entries;
496 native_entries.push_back(native_entry);
497 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
498 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
499 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
500 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
501 EXPECT_CALL((*history_backend_.get()),
502 AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
504 history::URLRows sync_entries;
505 sync_entries.push_back(sync_entry);
507 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
508 WillRepeatedly(Return(true));
509 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
510 WillRepeatedly(Return());
511 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
513 history::URLRows new_sync_entries;
514 GetTypedUrlsFromSyncDB(&new_sync_entries);
515 ASSERT_EQ(1U, new_sync_entries.size());
516 EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0]));
519 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithErrorHasSyncMerge) {
520 history::VisitVector native_visits;
521 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "native",
522 2, 15, false, &native_visits));
523 history::VisitVector sync_visits;
524 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "sync",
525 1, 17, false, &sync_visits));
527 history::URLRows native_entries;
528 native_entries.push_back(native_entry);
529 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
530 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
531 // Return an error getting the visits for the native URL.
532 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
533 WillRepeatedly(Return(false));
534 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).
535 WillRepeatedly(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
536 EXPECT_CALL((*history_backend_.get()),
537 AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
539 history::URLRows sync_entries;
540 sync_entries.push_back(sync_entry);
542 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
543 WillRepeatedly(Return(true));
544 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
545 WillRepeatedly(Return());
546 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
548 history::URLRows new_sync_entries;
549 GetTypedUrlsFromSyncDB(&new_sync_entries);
550 ASSERT_EQ(1U, new_sync_entries.size());
551 EXPECT_TRUE(URLsEqual(sync_entry, new_sync_entries[0]));
554 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
555 history::VisitVector added_visits;
556 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
557 2, 15, false, &added_visits));
559 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
560 WillOnce(Return(true));
561 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
562 WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
564 SetIdleChangeProcessorExpectations();
565 CreateRootHelper create_root(this, syncer::TYPED_URLS);
566 StartSyncService(create_root.callback());
568 history::URLsModifiedDetails details;
569 details.changed_urls.push_back(added_entry);
570 scoped_refptr<ThreadNotifier> notifier(
571 new ThreadNotifier(history_thread_.get()));
572 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
573 content::Source<Profile>(profile_.get()),
574 content::Details<history::URLsModifiedDetails>(&details));
576 history::URLRows new_sync_entries;
577 GetTypedUrlsFromSyncDB(&new_sync_entries);
578 ASSERT_EQ(1U, new_sync_entries.size());
579 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
582 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddWithBlank) {
583 history::VisitVector added_visits;
584 history::URLRow empty_entry(MakeTypedUrlEntry("", "entry",
585 2, 15, false, &added_visits));
586 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
587 2, 15, false, &added_visits));
589 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
590 WillOnce(Return(true));
591 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
592 WillRepeatedly(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
594 SetIdleChangeProcessorExpectations();
595 CreateRootHelper create_root(this, syncer::TYPED_URLS);
596 StartSyncService(create_root.callback());
598 history::URLsModifiedDetails details;
599 details.changed_urls.push_back(empty_entry);
600 details.changed_urls.push_back(added_entry);
601 scoped_refptr<ThreadNotifier> notifier(
602 new ThreadNotifier(history_thread_.get()));
603 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
604 content::Source<Profile>(profile_.get()),
605 content::Details<history::URLsModifiedDetails>(&details));
607 std::vector<history::URLRow> new_sync_entries;
608 GetTypedUrlsFromSyncDB(&new_sync_entries);
609 ASSERT_EQ(1U, new_sync_entries.size());
610 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
613 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
614 history::VisitVector original_visits;
615 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
618 history::URLRows original_entries;
619 original_entries.push_back(original_entry);
621 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
622 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
623 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
624 WillOnce(DoAll(SetArgumentPointee<2>(original_visits),
626 CreateRootHelper create_root(this, syncer::TYPED_URLS);
627 StartSyncService(create_root.callback());
629 history::VisitVector updated_visits;
630 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
633 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
634 WillOnce(DoAll(SetArgumentPointee<2>(updated_visits),
637 history::URLsModifiedDetails details;
638 details.changed_urls.push_back(updated_entry);
639 scoped_refptr<ThreadNotifier> notifier(
640 new ThreadNotifier(history_thread_.get()));
641 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
642 content::Source<Profile>(profile_.get()),
643 content::Details<history::URLsModifiedDetails>(&details));
645 history::URLRows new_sync_entries;
646 GetTypedUrlsFromSyncDB(&new_sync_entries);
647 ASSERT_EQ(1U, new_sync_entries.size());
648 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
651 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddFromVisit) {
652 history::VisitVector added_visits;
653 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
654 2, 15, false, &added_visits));
656 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
657 WillOnce(Return(true));
658 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
659 WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
661 SetIdleChangeProcessorExpectations();
662 CreateRootHelper create_root(this, syncer::TYPED_URLS);
663 StartSyncService(create_root.callback());
665 history::URLVisitedDetails details;
666 details.row = added_entry;
667 details.transition = content::PAGE_TRANSITION_TYPED;
668 scoped_refptr<ThreadNotifier> notifier(
669 new ThreadNotifier(history_thread_.get()));
670 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
671 content::Source<Profile>(profile_.get()),
672 content::Details<history::URLVisitedDetails>(&details));
674 history::URLRows new_sync_entries;
675 GetTypedUrlsFromSyncDB(&new_sync_entries);
676 ASSERT_EQ(1U, new_sync_entries.size());
677 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
680 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdateFromVisit) {
681 history::VisitVector original_visits;
682 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
685 history::URLRows original_entries;
686 original_entries.push_back(original_entry);
688 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
689 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
690 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
691 WillOnce(DoAll(SetArgumentPointee<2>(original_visits),
693 CreateRootHelper create_root(this, syncer::TYPED_URLS);
694 StartSyncService(create_root.callback());
696 history::VisitVector updated_visits;
697 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
700 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
701 WillOnce(DoAll(SetArgumentPointee<2>(updated_visits),
704 history::URLVisitedDetails details;
705 details.row = updated_entry;
706 details.transition = content::PAGE_TRANSITION_TYPED;
707 scoped_refptr<ThreadNotifier> notifier(
708 new ThreadNotifier(history_thread_.get()));
709 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
710 content::Source<Profile>(profile_.get()),
711 content::Details<history::URLVisitedDetails>(&details));
713 history::URLRows new_sync_entries;
714 GetTypedUrlsFromSyncDB(&new_sync_entries);
715 ASSERT_EQ(1U, new_sync_entries.size());
716 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
719 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserIgnoreChangeUpdateFromVisit) {
720 history::VisitVector original_visits;
721 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
724 history::URLRows original_entries;
725 original_entries.push_back(original_entry);
727 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
728 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
729 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
730 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
732 CreateRootHelper create_root(this, syncer::TYPED_URLS);
733 StartSyncService(create_root.callback());
734 history::URLRows new_sync_entries;
735 GetTypedUrlsFromSyncDB(&new_sync_entries);
736 ASSERT_EQ(1U, new_sync_entries.size());
737 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
739 history::VisitVector updated_visits;
740 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
743 history::URLVisitedDetails details;
744 details.row = updated_entry;
746 // Should ignore this change because it's not TYPED.
747 details.transition = content::PAGE_TRANSITION_RELOAD;
748 scoped_refptr<ThreadNotifier> notifier(
749 new ThreadNotifier(history_thread_.get()));
750 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
751 content::Source<Profile>(profile_.get()),
752 content::Details<history::URLVisitedDetails>(&details));
754 GetTypedUrlsFromSyncDB(&new_sync_entries);
756 // Should be no changes to the sync DB from this notification.
757 ASSERT_EQ(1U, new_sync_entries.size());
758 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
760 // Now, try updating it with a large number of visits not divisible by 10
761 // (should ignore this visit).
762 history::URLRow twelve_visits(MakeTypedUrlEntry("http://mine.com", "entry",
765 details.row = twelve_visits;
766 details.transition = content::PAGE_TRANSITION_TYPED;
767 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
768 content::Source<Profile>(profile_.get()),
769 content::Details<history::URLVisitedDetails>(&details));
770 GetTypedUrlsFromSyncDB(&new_sync_entries);
771 // Should be no changes to the sync DB from this notification.
772 ASSERT_EQ(1U, new_sync_entries.size());
773 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
775 // Now, try updating it with a large number of visits that is divisible by 10
776 // (should *not* be ignored).
777 history::URLRow twenty_visits(MakeTypedUrlEntry("http://mine.com", "entry",
780 details.row = twenty_visits;
781 details.transition = content::PAGE_TRANSITION_TYPED;
782 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
783 content::Source<Profile>(profile_.get()),
784 content::Details<history::URLVisitedDetails>(&details));
785 GetTypedUrlsFromSyncDB(&new_sync_entries);
786 ASSERT_EQ(1U, new_sync_entries.size());
787 EXPECT_TRUE(URLsEqual(twenty_visits, new_sync_entries[0]));
790 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
791 history::VisitVector original_visits1;
792 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
795 history::VisitVector original_visits2;
796 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
800 history::URLRows original_entries;
801 original_entries.push_back(original_entry1);
802 original_entries.push_back(original_entry2);
804 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
805 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
806 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
807 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
809 CreateRootHelper create_root(this, syncer::TYPED_URLS);
810 StartSyncService(create_root.callback());
812 history::URLsDeletedDetails changes;
813 changes.all_history = false;
814 changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
815 scoped_refptr<ThreadNotifier> notifier(
816 new ThreadNotifier(history_thread_.get()));
817 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
818 content::Source<Profile>(profile_.get()),
819 content::Details<history::URLsDeletedDetails>(&changes));
821 history::URLRows new_sync_entries;
822 GetTypedUrlsFromSyncDB(&new_sync_entries);
823 ASSERT_EQ(1U, new_sync_entries.size());
824 EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0]));
827 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveArchive) {
828 history::VisitVector original_visits1;
829 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
832 history::VisitVector original_visits2;
833 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
837 history::URLRows original_entries;
838 original_entries.push_back(original_entry1);
839 original_entries.push_back(original_entry2);
841 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
842 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
843 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
844 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
846 CreateRootHelper create_root(this, syncer::TYPED_URLS);
847 StartSyncService(create_root.callback());
849 history::URLsDeletedDetails changes;
850 changes.all_history = false;
851 // Setting archived=true should cause the sync code to ignore this deletion.
852 changes.archived = true;
853 changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
854 scoped_refptr<ThreadNotifier> notifier(
855 new ThreadNotifier(history_thread_.get()));
856 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
857 content::Source<Profile>(profile_.get()),
858 content::Details<history::URLsDeletedDetails>(&changes));
860 history::URLRows new_sync_entries;
861 GetTypedUrlsFromSyncDB(&new_sync_entries);
862 // Both URLs should still be there.
863 ASSERT_EQ(2U, new_sync_entries.size());
866 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
867 history::VisitVector original_visits1;
868 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
871 history::VisitVector original_visits2;
872 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
876 history::URLRows original_entries;
877 original_entries.push_back(original_entry1);
878 original_entries.push_back(original_entry2);
880 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
881 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
882 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
883 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
885 CreateRootHelper create_root(this, syncer::TYPED_URLS);
886 StartSyncService(create_root.callback());
888 history::URLRows new_sync_entries;
889 GetTypedUrlsFromSyncDB(&new_sync_entries);
890 ASSERT_EQ(2U, new_sync_entries.size());
892 history::URLsDeletedDetails changes;
893 changes.all_history = true;
894 scoped_refptr<ThreadNotifier> notifier(
895 new ThreadNotifier(history_thread_.get()));
896 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
897 content::Source<Profile>(profile_.get()),
898 content::Details<history::URLsDeletedDetails>(&changes));
900 GetTypedUrlsFromSyncDB(&new_sync_entries);
901 ASSERT_EQ(0U, new_sync_entries.size());
904 TEST_F(ProfileSyncServiceTypedUrlTest, FailWriteToHistoryBackend) {
905 history::VisitVector native_visits;
906 history::VisitVector sync_visits;
907 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
908 2, 15, false, &native_visits));
909 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
910 3, 16, false, &sync_visits));
912 history::URLRows native_entries;
913 native_entries.push_back(native_entry);
914 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
915 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
916 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).
917 WillOnce(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
918 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
919 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
920 EXPECT_CALL((*history_backend_.get()),
921 AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(false));
923 history::URLRows sync_entries;
924 sync_entries.push_back(sync_entry);
926 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
927 WillRepeatedly(Return(false));
928 TypedUrlModelAssociator* associator =
929 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
930 // Errors writing to the DB should be recorded, but should not cause an
931 // unrecoverable error.
933 sync_service_->failed_data_types_handler().GetFailedTypes().Has(
934 syncer::TYPED_URLS));
935 // Some calls should have succeeded, so the error percentage should be
936 // somewhere > 0 and < 100.
937 ASSERT_NE(0, associator->GetErrorPercentage());
938 ASSERT_NE(100, associator->GetErrorPercentage());
941 TEST_F(ProfileSyncServiceTypedUrlTest, FailToGetTypedURLs) {
942 history::VisitVector native_visits;
943 history::VisitVector sync_visits;
944 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
945 2, 15, false, &native_visits));
946 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
947 3, 16, false, &sync_visits));
949 history::URLRows native_entries;
950 native_entries.push_back(native_entry);
951 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
952 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(false)));
954 history::URLRows sync_entries;
955 sync_entries.push_back(sync_entry);
957 EXPECT_CALL(error_handler_, CreateAndUploadError(_, _, _)).
958 WillOnce(Return(syncer::SyncError(
960 syncer::SyncError::DATATYPE_ERROR,
962 syncer::TYPED_URLS)));
963 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
964 // Errors getting typed URLs will cause an unrecoverable error (since we can
965 // do *nothing* in that case).
967 sync_service_->failed_data_types_handler().GetFailedTypes().Has(
968 syncer::TYPED_URLS));
970 1u, sync_service_->failed_data_types_handler().GetFailedTypes().Size());
971 // Can't check GetErrorPercentage(), because generating an unrecoverable
972 // error will free the model associator.
975 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalFileURL) {
976 history::VisitVector original_visits;
977 // Create http and file url.
978 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
979 "yey", 12, 15, false,
981 history::URLRow file_entry(MakeTypedUrlEntry("file:///kitty.jpg",
982 "kitteh", 12, 15, false,
985 history::URLRows original_entries;
986 original_entries.push_back(url_entry);
987 original_entries.push_back(file_entry);
989 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
990 WillRepeatedly(DoAll(SetArgumentPointee<0>(original_entries),
992 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
993 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
995 CreateRootHelper create_root(this, syncer::TYPED_URLS);
996 StartSyncService(create_root.callback());
998 history::VisitVector updated_visits;
999 // Create updates for the previous urls + a new file one.
1000 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1001 "yey", 20, 15, false,
1003 history::URLRow updated_file_entry(MakeTypedUrlEntry("file:///cat.jpg",
1004 "cat", 20, 15, false,
1006 history::URLRow new_file_entry(MakeTypedUrlEntry("file:///dog.jpg",
1007 "dog", 20, 15, false,
1009 history::URLsModifiedDetails details;
1010 details.changed_urls.push_back(updated_url_entry);
1011 details.changed_urls.push_back(updated_file_entry);
1012 details.changed_urls.push_back(new_file_entry);
1013 scoped_refptr<ThreadNotifier> notifier(
1014 new ThreadNotifier(history_thread_.get()));
1015 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1016 content::Source<Profile>(profile_.get()),
1017 content::Details<history::URLsModifiedDetails>(&details));
1019 history::URLRows new_sync_entries;
1020 GetTypedUrlsFromSyncDB(&new_sync_entries);
1022 // We should ignore the local file urls (existing and updated),
1023 // and only be left with the updated http url.
1024 ASSERT_EQ(1U, new_sync_entries.size());
1025 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
1028 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalhostURL) {
1029 history::VisitVector original_visits;
1030 // Create http and localhost url.
1031 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
1032 "yey", 12, 15, false,
1034 history::URLRow localhost_entry(MakeTypedUrlEntry("http://localhost",
1035 "localhost", 12, 15, false,
1038 history::URLRows original_entries;
1039 original_entries.push_back(url_entry);
1040 original_entries.push_back(localhost_entry);
1042 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
1043 WillRepeatedly(DoAll(SetArgumentPointee<0>(original_entries),
1045 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
1046 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
1048 CreateRootHelper create_root(this, syncer::TYPED_URLS);
1049 StartSyncService(create_root.callback());
1051 history::VisitVector updated_visits;
1052 // Update the previous entries and add a new localhost.
1053 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1054 "yey", 20, 15, false,
1056 history::URLRow updated_localhost_entry(MakeTypedUrlEntry(
1057 "http://localhost:80",
1058 "localhost", 20, 15, false,
1060 history::URLRow localhost_ip_entry(MakeTypedUrlEntry("http://127.0.0.1",
1061 "localhost", 12, 15, false,
1063 history::URLsModifiedDetails details;
1064 details.changed_urls.push_back(updated_url_entry);
1065 details.changed_urls.push_back(updated_localhost_entry);
1066 details.changed_urls.push_back(localhost_ip_entry);
1067 scoped_refptr<ThreadNotifier> notifier(
1068 new ThreadNotifier(history_thread_.get()));
1069 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1070 content::Source<Profile>(profile_.get()),
1071 content::Details<history::URLsModifiedDetails>(&details));
1073 history::URLRows new_sync_entries;
1074 GetTypedUrlsFromSyncDB(&new_sync_entries);
1076 // We should ignore the localhost urls and left only with http url.
1077 ASSERT_EQ(1U, new_sync_entries.size());
1078 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));