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/history/history_types.h"
27 #include "chrome/browser/invalidation/fake_invalidation_service.h"
28 #include "chrome/browser/invalidation/invalidation_service_factory.h"
29 #include "chrome/browser/prefs/pref_service_syncable.h"
30 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
31 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
32 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
33 #include "chrome/browser/signin/signin_manager_factory.h"
34 #include "chrome/browser/sync/abstract_profile_sync_service_test.h"
35 #include "chrome/browser/sync/glue/sync_backend_host.h"
36 #include "chrome/browser/sync/glue/typed_url_change_processor.h"
37 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
38 #include "chrome/browser/sync/glue/typed_url_model_associator.h"
39 #include "chrome/browser/sync/profile_sync_components_factory.h"
40 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
41 #include "chrome/browser/sync/profile_sync_service.h"
42 #include "chrome/browser/sync/profile_sync_service_factory.h"
43 #include "chrome/browser/sync/profile_sync_test_util.h"
44 #include "chrome/browser/sync/test_profile_sync_service.h"
45 #include "chrome/test/base/testing_browser_process.h"
46 #include "chrome/test/base/testing_profile.h"
47 #include "chrome/test/base/testing_profile_manager.h"
48 #include "components/keyed_service/content/refcounted_browser_context_keyed_service.h"
49 #include "components/signin/core/browser/signin_manager.h"
50 #include "components/sync_driver/data_type_error_handler_mock.h"
51 #include "content/public/browser/notification_service.h"
52 #include "google_apis/gaia/gaia_constants.h"
53 #include "sync/internal_api/public/read_node.h"
54 #include "sync/internal_api/public/read_transaction.h"
55 #include "sync/internal_api/public/write_node.h"
56 #include "sync/internal_api/public/write_transaction.h"
57 #include "sync/protocol/typed_url_specifics.pb.h"
58 #include "testing/gmock/include/gmock/gmock.h"
63 using browser_sync::TypedUrlChangeProcessor;
64 using browser_sync::TypedUrlDataTypeController;
65 using browser_sync::TypedUrlModelAssociator;
66 using history::HistoryBackend;
68 using history::URLRow;
69 using syncer::syncable::WriteTransaction;
71 using testing::Return;
72 using testing::SetArgumentPointee;
77 const char kTestProfileName[] = "test-profile";
79 // Visits with this timestamp are treated as expired.
80 static const int EXPIRED_VISIT = -1;
82 class HistoryBackendMock : public HistoryBackend {
84 HistoryBackendMock() : HistoryBackend(base::FilePath(), NULL, NULL) {}
85 virtual bool IsExpiredVisitTime(const base::Time& time) OVERRIDE {
86 return time.ToInternalValue() == EXPIRED_VISIT;
88 MOCK_METHOD1(GetAllTypedURLs, bool(history::URLRows* entries));
89 MOCK_METHOD3(GetMostRecentVisitsForURL, bool(history::URLID id,
91 history::VisitVector* visits));
92 MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
93 MOCK_METHOD3(AddVisits, bool(const GURL& url,
94 const std::vector<history::VisitInfo>& visits,
95 history::VisitSource visit_source));
96 MOCK_METHOD1(RemoveVisits, bool(const history::VisitVector& visits));
97 MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
98 MOCK_METHOD2(SetPageTitle, void(const GURL& url,
99 const base::string16& title));
100 MOCK_METHOD1(DeleteURL, void(const GURL& url));
103 virtual ~HistoryBackendMock() {}
106 class HistoryServiceMock : public HistoryService {
108 explicit HistoryServiceMock(Profile* profile) : HistoryService(profile) {}
109 MOCK_METHOD2(ScheduleDBTask, void(history::HistoryDBTask*,
110 CancelableRequestConsumerBase*));
111 MOCK_METHOD0(Shutdown, void());
113 void ShutdownBaseService() {
114 HistoryService::Shutdown();
118 virtual ~HistoryServiceMock() {}
121 KeyedService* BuildHistoryService(content::BrowserContext* profile) {
122 return new HistoryServiceMock(static_cast<Profile*>(profile));
125 class TestTypedUrlModelAssociator : public TypedUrlModelAssociator {
127 TestTypedUrlModelAssociator(
128 ProfileSyncService* sync_service,
129 history::HistoryBackend* history_backend,
130 browser_sync::DataTypeErrorHandler* error_handler) :
131 TypedUrlModelAssociator(sync_service, history_backend, error_handler) {}
134 // Don't clear error stats - that way we can verify their values in our
136 virtual void ClearErrorStats() OVERRIDE {}
139 void RunOnDBThreadCallback(HistoryBackend* backend,
140 history::HistoryDBTask* task) {
141 task->RunOnDBThread(backend, NULL);
144 ACTION_P2(RunTaskOnDBThread, thread, backend) {
145 // ScheduleDBTask takes ownership of its task argument, so we
147 scoped_refptr<history::HistoryDBTask> task(arg0);
148 thread->message_loop()->PostTask(
149 FROM_HERE, base::Bind(&RunOnDBThreadCallback, base::Unretained(backend),
153 ACTION_P2(ShutdownHistoryService, thread, service) {
154 service->ShutdownBaseService();
158 ACTION_P6(MakeTypedUrlSyncComponents,
166 new TestTypedUrlModelAssociator(service, hb, error_handler);
167 TypedUrlChangeProcessor* change_processor =
168 new TypedUrlChangeProcessor(profile, *model_associator, hb, dtc);
169 return ProfileSyncComponentsFactory::SyncComponents(*model_associator,
173 class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
175 void AddTypedUrlSyncNode(const history::URLRow& url,
176 const history::VisitVector& visits) {
177 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
178 syncer::ReadNode typed_url_root(&trans);
179 ASSERT_EQ(syncer::BaseNode::INIT_OK,
180 typed_url_root.InitByTagLookup(browser_sync::kTypedUrlTag));
182 syncer::WriteNode node(&trans);
183 std::string tag = url.url().spec();
184 syncer::WriteNode::InitUniqueByCreationResult result =
185 node.InitUniqueByCreation(syncer::TYPED_URLS, typed_url_root, tag);
186 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
187 TypedUrlModelAssociator::WriteToSyncNode(url, visits, &node);
191 ProfileSyncServiceTypedUrlTest()
192 : profile_manager_(TestingBrowserProcess::GetGlobal()) {
193 history_thread_.reset(new Thread("history"));
196 virtual void SetUp() {
197 AbstractProfileSyncServiceTest::SetUp();
198 ASSERT_TRUE(profile_manager_.SetUp());
199 TestingProfile::TestingFactories testing_factories;
200 testing_factories.push_back(std::make_pair(
201 ProfileOAuth2TokenServiceFactory::GetInstance(),
202 BuildAutoIssuingFakeProfileOAuth2TokenService));
203 profile_ = profile_manager_.CreateTestingProfile(
205 scoped_ptr<PrefServiceSyncable>(),
206 base::UTF8ToUTF16(kTestProfileName),
210 invalidation::InvalidationServiceFactory::GetInstance()->SetTestingFactory(
211 profile_, invalidation::FakeInvalidationService::Build);
212 history_backend_ = new HistoryBackendMock();
213 history_service_ = static_cast<HistoryServiceMock*>(
214 HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
215 profile_, BuildHistoryService));
216 EXPECT_CALL((*history_service_), ScheduleDBTask(_, _))
217 .WillRepeatedly(RunTaskOnDBThread(history_thread_.get(),
218 history_backend_.get()));
219 history_thread_->Start();
222 virtual void TearDown() {
223 EXPECT_CALL((*history_service_), Shutdown())
224 .WillOnce(ShutdownHistoryService(history_thread_.release(),
227 profile_manager_.DeleteTestingProfile(kTestProfileName);
228 AbstractProfileSyncServiceTest::TearDown();
231 TypedUrlModelAssociator* StartSyncService(const base::Closure& callback) {
232 TypedUrlModelAssociator* model_associator = NULL;
233 if (!sync_service_) {
234 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
235 signin->SetAuthenticatedUsername("test");
236 sync_service_ = TestProfileSyncService::BuildAutoStartAsyncInit(profile_,
238 ProfileSyncComponentsFactoryMock* components =
239 sync_service_->components_factory_mock();
240 TypedUrlDataTypeController* data_type_controller =
241 new TypedUrlDataTypeController(components, profile_, sync_service_);
243 EXPECT_CALL(*components, CreateTypedUrlSyncComponents(_, _, _)).
244 WillOnce(MakeTypedUrlSyncComponents(profile_,
246 history_backend_.get(),
247 data_type_controller,
250 EXPECT_CALL(*components, CreateDataTypeManager(_, _, _, _, _, _)).
251 WillOnce(ReturnNewDataTypeManager());
253 ProfileOAuth2TokenService* oauth2_token_service =
254 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
255 oauth2_token_service->UpdateCredentials("test", "oauth2_login_token");
257 sync_service_->RegisterDataTypeController(data_type_controller);
259 sync_service_->Initialize();
260 base::MessageLoop::current()->Run();
262 return model_associator;
265 void GetTypedUrlsFromSyncDB(history::URLRows* urls) {
267 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
268 syncer::ReadNode typed_url_root(&trans);
269 if (typed_url_root.InitByTagLookup(browser_sync::kTypedUrlTag) !=
270 syncer::BaseNode::INIT_OK)
273 int64 child_id = typed_url_root.GetFirstChildId();
274 while (child_id != syncer::kInvalidId) {
275 syncer::ReadNode child_node(&trans);
276 if (child_node.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK)
279 const sync_pb::TypedUrlSpecifics& typed_url(
280 child_node.GetTypedUrlSpecifics());
281 history::URLRow new_url(GURL(typed_url.url()));
283 new_url.set_title(base::UTF8ToUTF16(typed_url.title()));
284 DCHECK(typed_url.visits_size());
285 DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size());
286 new_url.set_last_visit(base::Time::FromInternalValue(
287 typed_url.visits(typed_url.visits_size() - 1)));
288 new_url.set_hidden(typed_url.hidden());
290 urls->push_back(new_url);
291 child_id = child_node.GetSuccessorId();
295 void SetIdleChangeProcessorExpectations() {
296 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).Times(0);
297 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).Times(0);
298 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).Times(0);
299 EXPECT_CALL((*history_backend_.get()), DeleteURL(_)).Times(0);
302 static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
303 // Only verify the fields we explicitly sync (i.e. don't verify typed_count
304 // or visit_count because we rely on the history DB to manage those values
305 // and they are left unchanged by HistoryBackendMock).
306 return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
307 (lhs.title().compare(rhs.title()) == 0) &&
308 (lhs.last_visit() == rhs.last_visit()) &&
309 (lhs.hidden() == rhs.hidden());
312 static history::URLRow MakeTypedUrlEntry(const char* url,
317 history::VisitVector* visits) {
318 // Give each URL a unique ID, to mimic the behavior of the real database.
319 static int unique_url_id = 0;
321 URLRow history_url(gurl, ++unique_url_id);
322 history_url.set_title(base::UTF8ToUTF16(title));
323 history_url.set_typed_count(typed_count);
324 history_url.set_last_visit(
325 base::Time::FromInternalValue(last_visit));
326 history_url.set_hidden(hidden);
327 visits->push_back(history::VisitRow(
328 history_url.id(), history_url.last_visit(), 0,
329 content::PAGE_TRANSITION_TYPED, 0));
330 history_url.set_visit_count(visits->size());
334 scoped_ptr<Thread> history_thread_;
335 TestingProfileManager profile_manager_;
336 TestingProfile* profile_;
337 scoped_refptr<HistoryBackendMock> history_backend_;
338 HistoryServiceMock* history_service_;
339 browser_sync::DataTypeErrorHandlerMock error_handler_;
342 void AddTypedUrlEntries(ProfileSyncServiceTypedUrlTest* test,
343 const history::URLRows& entries) {
344 test->CreateRoot(syncer::TYPED_URLS);
345 for (size_t i = 0; i < entries.size(); ++i) {
346 history::VisitVector visits;
347 visits.push_back(history::VisitRow(
348 entries[i].id(), entries[i].last_visit(), 0,
349 content::PageTransitionFromInt(0), 0));
350 test->AddTypedUrlSyncNode(entries[i], visits);
356 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
357 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
358 WillOnce(Return(true));
359 SetIdleChangeProcessorExpectations();
360 CreateRootHelper create_root(this, syncer::TYPED_URLS);
361 TypedUrlModelAssociator* associator =
362 StartSyncService(create_root.callback());
363 history::URLRows sync_entries;
364 GetTypedUrlsFromSyncDB(&sync_entries);
365 EXPECT_EQ(0U, sync_entries.size());
366 ASSERT_EQ(0, associator->GetErrorPercentage());
369 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
370 history::URLRows entries;
371 history::VisitVector visits;
372 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
373 2, 15, false, &visits));
375 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
376 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
377 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
378 WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
379 SetIdleChangeProcessorExpectations();
380 CreateRootHelper create_root(this, syncer::TYPED_URLS);
381 TypedUrlModelAssociator* associator =
382 StartSyncService(create_root.callback());
383 history::URLRows sync_entries;
384 GetTypedUrlsFromSyncDB(&sync_entries);
385 ASSERT_EQ(1U, sync_entries.size());
386 EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0]));
387 ASSERT_EQ(0, associator->GetErrorPercentage());
390 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeErrorReadingVisits) {
391 history::URLRows entries;
392 history::VisitVector visits;
393 history::URLRow native_entry1(MakeTypedUrlEntry("http://foo.com", "bar",
394 2, 15, false, &visits));
395 history::URLRow native_entry2(MakeTypedUrlEntry("http://foo2.com", "bar",
396 3, 15, false, &visits));
397 entries.push_back(native_entry1);
398 entries.push_back(native_entry2);
399 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
400 WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
401 // Return an error from GetMostRecentVisitsForURL() for the second URL.
402 EXPECT_CALL((*history_backend_.get()),
403 GetMostRecentVisitsForURL(native_entry1.id(), _, _)).
404 WillRepeatedly(Return(true));
405 EXPECT_CALL((*history_backend_.get()),
406 GetMostRecentVisitsForURL(native_entry2.id(), _, _)).
407 WillRepeatedly(Return(false));
408 SetIdleChangeProcessorExpectations();
409 CreateRootHelper create_root(this, syncer::TYPED_URLS);
410 StartSyncService(create_root.callback());
411 history::URLRows sync_entries;
412 GetTypedUrlsFromSyncDB(&sync_entries);
413 ASSERT_EQ(1U, sync_entries.size());
414 EXPECT_TRUE(URLsEqual(native_entry1, sync_entries[0]));
417 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithBlankEmptySync) {
418 std::vector<history::URLRow> entries;
419 history::VisitVector visits;
421 entries.push_back(MakeTypedUrlEntry("", "bar",
422 2, 15, false, &visits));
423 entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
424 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 StartSyncService(create_root.callback());
432 std::vector<history::URLRow> sync_entries;
433 GetTypedUrlsFromSyncDB(&sync_entries);
434 // The empty URL should be ignored.
435 ASSERT_EQ(1U, sync_entries.size());
436 EXPECT_TRUE(URLsEqual(entries[1], sync_entries[0]));
439 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
440 history::VisitVector native_visits;
441 history::VisitVector sync_visits;
442 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
443 2, 15, false, &native_visits));
444 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
445 3, 16, false, &sync_visits));
447 history::URLRows native_entries;
448 native_entries.push_back(native_entry);
449 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
450 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
451 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
452 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
453 EXPECT_CALL((*history_backend_.get()),
454 AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(true));
456 history::URLRows sync_entries;
457 sync_entries.push_back(sync_entry);
459 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
460 WillRepeatedly(Return(true));
461 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
463 std::map<std::string, history::URLRow> expected;
464 expected[native_entry.url().spec()] = native_entry;
465 expected[sync_entry.url().spec()] = sync_entry;
467 history::URLRows new_sync_entries;
468 GetTypedUrlsFromSyncDB(&new_sync_entries);
470 EXPECT_TRUE(new_sync_entries.size() == expected.size());
471 for (history::URLRows::iterator entry = new_sync_entries.begin();
472 entry != new_sync_entries.end(); ++entry) {
473 EXPECT_TRUE(URLsEqual(expected[entry->url().spec()], *entry));
477 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeExpiredSync) {
478 history::VisitVector sync_visits;
479 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
480 3, EXPIRED_VISIT, false,
482 history::URLRows sync_entries;
483 sync_entries.push_back(sync_entry);
485 // Since all our URLs are expired, no backend calls to add new URLs will be
487 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
488 WillOnce(Return(true));
489 SetIdleChangeProcessorExpectations();
491 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
494 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
495 history::VisitVector native_visits;
496 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
497 2, 15, false, &native_visits));
498 history::VisitVector sync_visits;
499 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name",
500 1, 17, false, &sync_visits));
501 history::VisitVector merged_visits;
502 merged_visits.push_back(history::VisitRow(
503 sync_entry.id(), base::Time::FromInternalValue(15), 0,
504 content::PageTransitionFromInt(0), 0));
506 history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name",
507 2, 17, false, &merged_visits));
509 history::URLRows native_entries;
510 native_entries.push_back(native_entry);
511 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
512 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
513 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
514 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
515 EXPECT_CALL((*history_backend_.get()),
516 AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
518 history::URLRows sync_entries;
519 sync_entries.push_back(sync_entry);
521 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
522 WillRepeatedly(Return(true));
523 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
524 WillRepeatedly(Return());
525 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
527 history::URLRows new_sync_entries;
528 GetTypedUrlsFromSyncDB(&new_sync_entries);
529 ASSERT_EQ(1U, new_sync_entries.size());
530 EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0]));
533 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithErrorHasSyncMerge) {
534 history::VisitVector native_visits;
535 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "native",
536 2, 15, false, &native_visits));
537 history::VisitVector sync_visits;
538 history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "sync",
539 1, 17, false, &sync_visits));
541 history::URLRows native_entries;
542 native_entries.push_back(native_entry);
543 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
544 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
545 // Return an error getting the visits for the native URL.
546 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
547 WillRepeatedly(Return(false));
548 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).
549 WillRepeatedly(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
550 EXPECT_CALL((*history_backend_.get()),
551 AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
553 history::URLRows sync_entries;
554 sync_entries.push_back(sync_entry);
556 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
557 WillRepeatedly(Return(true));
558 EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
559 WillRepeatedly(Return());
560 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
562 history::URLRows new_sync_entries;
563 GetTypedUrlsFromSyncDB(&new_sync_entries);
564 ASSERT_EQ(1U, new_sync_entries.size());
565 EXPECT_TRUE(URLsEqual(sync_entry, new_sync_entries[0]));
568 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
569 history::VisitVector added_visits;
570 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
571 2, 15, false, &added_visits));
573 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
574 WillOnce(Return(true));
575 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
576 WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
578 SetIdleChangeProcessorExpectations();
579 CreateRootHelper create_root(this, syncer::TYPED_URLS);
580 StartSyncService(create_root.callback());
582 history::URLsModifiedDetails details;
583 details.changed_urls.push_back(added_entry);
584 scoped_refptr<ThreadNotifier> notifier(
585 new ThreadNotifier(history_thread_.get()));
586 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
587 content::Source<Profile>(profile_),
588 content::Details<history::URLsModifiedDetails>(&details));
590 history::URLRows new_sync_entries;
591 GetTypedUrlsFromSyncDB(&new_sync_entries);
592 ASSERT_EQ(1U, new_sync_entries.size());
593 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
596 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddWithBlank) {
597 history::VisitVector added_visits;
598 history::URLRow empty_entry(MakeTypedUrlEntry("", "entry",
599 2, 15, false, &added_visits));
600 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
601 2, 15, false, &added_visits));
603 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
604 WillOnce(Return(true));
605 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
606 WillRepeatedly(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
608 SetIdleChangeProcessorExpectations();
609 CreateRootHelper create_root(this, syncer::TYPED_URLS);
610 StartSyncService(create_root.callback());
612 history::URLsModifiedDetails details;
613 details.changed_urls.push_back(empty_entry);
614 details.changed_urls.push_back(added_entry);
615 scoped_refptr<ThreadNotifier> notifier(
616 new ThreadNotifier(history_thread_.get()));
617 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
618 content::Source<Profile>(profile_),
619 content::Details<history::URLsModifiedDetails>(&details));
621 std::vector<history::URLRow> new_sync_entries;
622 GetTypedUrlsFromSyncDB(&new_sync_entries);
623 ASSERT_EQ(1U, new_sync_entries.size());
624 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
627 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
628 history::VisitVector original_visits;
629 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
632 history::URLRows original_entries;
633 original_entries.push_back(original_entry);
635 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
636 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
637 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
638 WillOnce(DoAll(SetArgumentPointee<2>(original_visits),
640 CreateRootHelper create_root(this, syncer::TYPED_URLS);
641 StartSyncService(create_root.callback());
643 history::VisitVector updated_visits;
644 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
647 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
648 WillOnce(DoAll(SetArgumentPointee<2>(updated_visits),
651 history::URLsModifiedDetails details;
652 details.changed_urls.push_back(updated_entry);
653 scoped_refptr<ThreadNotifier> notifier(
654 new ThreadNotifier(history_thread_.get()));
655 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
656 content::Source<Profile>(profile_),
657 content::Details<history::URLsModifiedDetails>(&details));
659 history::URLRows new_sync_entries;
660 GetTypedUrlsFromSyncDB(&new_sync_entries);
661 ASSERT_EQ(1U, new_sync_entries.size());
662 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
665 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddFromVisit) {
666 history::VisitVector added_visits;
667 history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
668 2, 15, false, &added_visits));
670 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
671 WillOnce(Return(true));
672 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
673 WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
675 SetIdleChangeProcessorExpectations();
676 CreateRootHelper create_root(this, syncer::TYPED_URLS);
677 StartSyncService(create_root.callback());
679 history::URLVisitedDetails details;
680 details.row = added_entry;
681 details.transition = content::PAGE_TRANSITION_TYPED;
682 scoped_refptr<ThreadNotifier> notifier(
683 new ThreadNotifier(history_thread_.get()));
684 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
685 content::Source<Profile>(profile_),
686 content::Details<history::URLVisitedDetails>(&details));
688 history::URLRows new_sync_entries;
689 GetTypedUrlsFromSyncDB(&new_sync_entries);
690 ASSERT_EQ(1U, new_sync_entries.size());
691 EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
694 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdateFromVisit) {
695 history::VisitVector original_visits;
696 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
699 history::URLRows original_entries;
700 original_entries.push_back(original_entry);
702 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
703 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
704 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
705 WillOnce(DoAll(SetArgumentPointee<2>(original_visits),
707 CreateRootHelper create_root(this, syncer::TYPED_URLS);
708 StartSyncService(create_root.callback());
710 history::VisitVector updated_visits;
711 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
714 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
715 WillOnce(DoAll(SetArgumentPointee<2>(updated_visits),
718 history::URLVisitedDetails details;
719 details.row = updated_entry;
720 details.transition = content::PAGE_TRANSITION_TYPED;
721 scoped_refptr<ThreadNotifier> notifier(
722 new ThreadNotifier(history_thread_.get()));
723 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
724 content::Source<Profile>(profile_),
725 content::Details<history::URLVisitedDetails>(&details));
727 history::URLRows new_sync_entries;
728 GetTypedUrlsFromSyncDB(&new_sync_entries);
729 ASSERT_EQ(1U, new_sync_entries.size());
730 EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
733 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserIgnoreChangeUpdateFromVisit) {
734 history::VisitVector original_visits;
735 history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
738 history::URLRows original_entries;
739 original_entries.push_back(original_entry);
741 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
742 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
743 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
744 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
746 CreateRootHelper create_root(this, syncer::TYPED_URLS);
747 StartSyncService(create_root.callback());
748 history::URLRows new_sync_entries;
749 GetTypedUrlsFromSyncDB(&new_sync_entries);
750 ASSERT_EQ(1U, new_sync_entries.size());
751 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
753 history::VisitVector updated_visits;
754 history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
757 history::URLVisitedDetails details;
758 details.row = updated_entry;
760 // Should ignore this change because it's not TYPED.
761 details.transition = content::PAGE_TRANSITION_RELOAD;
762 scoped_refptr<ThreadNotifier> notifier(
763 new ThreadNotifier(history_thread_.get()));
764 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
765 content::Source<Profile>(profile_),
766 content::Details<history::URLVisitedDetails>(&details));
768 GetTypedUrlsFromSyncDB(&new_sync_entries);
770 // Should be no changes to the sync DB from this notification.
771 ASSERT_EQ(1U, new_sync_entries.size());
772 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
774 // Now, try updating it with a large number of visits not divisible by 10
775 // (should ignore this visit).
776 history::URLRow twelve_visits(MakeTypedUrlEntry("http://mine.com", "entry",
779 details.row = twelve_visits;
780 details.transition = content::PAGE_TRANSITION_TYPED;
781 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
782 content::Source<Profile>(profile_),
783 content::Details<history::URLVisitedDetails>(&details));
784 GetTypedUrlsFromSyncDB(&new_sync_entries);
785 // Should be no changes to the sync DB from this notification.
786 ASSERT_EQ(1U, new_sync_entries.size());
787 EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
789 // Now, try updating it with a large number of visits that is divisible by 10
790 // (should *not* be ignored).
791 history::URLRow twenty_visits(MakeTypedUrlEntry("http://mine.com", "entry",
794 details.row = twenty_visits;
795 details.transition = content::PAGE_TRANSITION_TYPED;
796 notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
797 content::Source<Profile>(profile_),
798 content::Details<history::URLVisitedDetails>(&details));
799 GetTypedUrlsFromSyncDB(&new_sync_entries);
800 ASSERT_EQ(1U, new_sync_entries.size());
801 EXPECT_TRUE(URLsEqual(twenty_visits, new_sync_entries[0]));
804 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
805 history::VisitVector original_visits1;
806 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
809 history::VisitVector original_visits2;
810 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
814 history::URLRows original_entries;
815 original_entries.push_back(original_entry1);
816 original_entries.push_back(original_entry2);
818 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
819 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
820 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
821 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
823 CreateRootHelper create_root(this, syncer::TYPED_URLS);
824 StartSyncService(create_root.callback());
826 history::URLsDeletedDetails changes;
827 changes.all_history = false;
828 changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
829 scoped_refptr<ThreadNotifier> notifier(
830 new ThreadNotifier(history_thread_.get()));
831 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
832 content::Source<Profile>(profile_),
833 content::Details<history::URLsDeletedDetails>(&changes));
835 history::URLRows new_sync_entries;
836 GetTypedUrlsFromSyncDB(&new_sync_entries);
837 ASSERT_EQ(1U, new_sync_entries.size());
838 EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0]));
841 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveArchive) {
842 history::VisitVector original_visits1;
843 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
846 history::VisitVector original_visits2;
847 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
851 history::URLRows original_entries;
852 original_entries.push_back(original_entry1);
853 original_entries.push_back(original_entry2);
855 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
856 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
857 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
858 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
860 CreateRootHelper create_root(this, syncer::TYPED_URLS);
861 StartSyncService(create_root.callback());
863 history::URLsDeletedDetails changes;
864 changes.all_history = false;
865 // Setting archived=true should cause the sync code to ignore this deletion.
866 changes.archived = true;
867 changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
868 scoped_refptr<ThreadNotifier> notifier(
869 new ThreadNotifier(history_thread_.get()));
870 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
871 content::Source<Profile>(profile_),
872 content::Details<history::URLsDeletedDetails>(&changes));
874 history::URLRows new_sync_entries;
875 GetTypedUrlsFromSyncDB(&new_sync_entries);
876 // Both URLs should still be there.
877 ASSERT_EQ(2U, new_sync_entries.size());
880 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
881 history::VisitVector original_visits1;
882 history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
885 history::VisitVector original_visits2;
886 history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
890 history::URLRows original_entries;
891 original_entries.push_back(original_entry1);
892 original_entries.push_back(original_entry2);
894 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
895 WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
896 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
897 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits1),
899 CreateRootHelper create_root(this, syncer::TYPED_URLS);
900 StartSyncService(create_root.callback());
902 history::URLRows new_sync_entries;
903 GetTypedUrlsFromSyncDB(&new_sync_entries);
904 ASSERT_EQ(2U, new_sync_entries.size());
906 history::URLsDeletedDetails changes;
907 changes.all_history = true;
908 scoped_refptr<ThreadNotifier> notifier(
909 new ThreadNotifier(history_thread_.get()));
910 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
911 content::Source<Profile>(profile_),
912 content::Details<history::URLsDeletedDetails>(&changes));
914 GetTypedUrlsFromSyncDB(&new_sync_entries);
915 ASSERT_EQ(0U, new_sync_entries.size());
918 TEST_F(ProfileSyncServiceTypedUrlTest, FailWriteToHistoryBackend) {
919 history::VisitVector native_visits;
920 history::VisitVector sync_visits;
921 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
922 2, 15, false, &native_visits));
923 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
924 3, 16, false, &sync_visits));
926 history::URLRows native_entries;
927 native_entries.push_back(native_entry);
928 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
929 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
930 EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).
931 WillOnce(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
932 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
933 WillRepeatedly(DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
934 EXPECT_CALL((*history_backend_.get()),
935 AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(false));
937 history::URLRows sync_entries;
938 sync_entries.push_back(sync_entry);
940 EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
941 WillRepeatedly(Return(false));
942 TypedUrlModelAssociator* associator =
943 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
944 // Errors writing to the DB should be recorded, but should not cause an
945 // unrecoverable error.
947 sync_service_->failed_data_types_handler().GetFailedTypes().Has(
948 syncer::TYPED_URLS));
949 // Some calls should have succeeded, so the error percentage should be
950 // somewhere > 0 and < 100.
951 ASSERT_NE(0, associator->GetErrorPercentage());
952 ASSERT_NE(100, associator->GetErrorPercentage());
955 TEST_F(ProfileSyncServiceTypedUrlTest, FailToGetTypedURLs) {
956 history::VisitVector native_visits;
957 history::VisitVector sync_visits;
958 history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
959 2, 15, false, &native_visits));
960 history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
961 3, 16, false, &sync_visits));
963 history::URLRows native_entries;
964 native_entries.push_back(native_entry);
965 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
966 WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(false)));
968 history::URLRows sync_entries;
969 sync_entries.push_back(sync_entry);
971 EXPECT_CALL(error_handler_, CreateAndUploadError(_, _, _)).
972 WillOnce(Return(syncer::SyncError(
974 syncer::SyncError::DATATYPE_ERROR,
976 syncer::TYPED_URLS)));
977 StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
978 // Errors getting typed URLs will cause an unrecoverable error (since we can
979 // do *nothing* in that case).
981 sync_service_->failed_data_types_handler().GetFailedTypes().Has(
982 syncer::TYPED_URLS));
984 1u, sync_service_->failed_data_types_handler().GetFailedTypes().Size());
985 // Can't check GetErrorPercentage(), because generating an unrecoverable
986 // error will free the model associator.
989 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalFileURL) {
990 history::VisitVector original_visits;
991 // Create http and file url.
992 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
993 "yey", 12, 15, false,
995 history::URLRow file_entry(MakeTypedUrlEntry("file:///kitty.jpg",
996 "kitteh", 12, 15, false,
999 history::URLRows original_entries;
1000 original_entries.push_back(url_entry);
1001 original_entries.push_back(file_entry);
1003 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
1004 WillRepeatedly(DoAll(SetArgumentPointee<0>(original_entries),
1006 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
1007 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
1009 CreateRootHelper create_root(this, syncer::TYPED_URLS);
1010 StartSyncService(create_root.callback());
1012 history::VisitVector updated_visits;
1013 // Create updates for the previous urls + a new file one.
1014 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1015 "yey", 20, 15, false,
1017 history::URLRow updated_file_entry(MakeTypedUrlEntry("file:///cat.jpg",
1018 "cat", 20, 15, false,
1020 history::URLRow new_file_entry(MakeTypedUrlEntry("file:///dog.jpg",
1021 "dog", 20, 15, false,
1023 history::URLsModifiedDetails details;
1024 details.changed_urls.push_back(updated_url_entry);
1025 details.changed_urls.push_back(updated_file_entry);
1026 details.changed_urls.push_back(new_file_entry);
1027 scoped_refptr<ThreadNotifier> notifier(
1028 new ThreadNotifier(history_thread_.get()));
1029 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1030 content::Source<Profile>(profile_),
1031 content::Details<history::URLsModifiedDetails>(&details));
1033 history::URLRows new_sync_entries;
1034 GetTypedUrlsFromSyncDB(&new_sync_entries);
1036 // We should ignore the local file urls (existing and updated),
1037 // and only be left with the updated http url.
1038 ASSERT_EQ(1U, new_sync_entries.size());
1039 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
1042 TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalhostURL) {
1043 history::VisitVector original_visits;
1044 // Create http and localhost url.
1045 history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
1046 "yey", 12, 15, false,
1048 history::URLRow localhost_entry(MakeTypedUrlEntry("http://localhost",
1049 "localhost", 12, 15, false,
1052 history::URLRows original_entries;
1053 original_entries.push_back(url_entry);
1054 original_entries.push_back(localhost_entry);
1056 EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
1057 WillRepeatedly(DoAll(SetArgumentPointee<0>(original_entries),
1059 EXPECT_CALL((*history_backend_.get()), GetMostRecentVisitsForURL(_, _, _)).
1060 WillRepeatedly(DoAll(SetArgumentPointee<2>(original_visits),
1062 CreateRootHelper create_root(this, syncer::TYPED_URLS);
1063 StartSyncService(create_root.callback());
1065 history::VisitVector updated_visits;
1066 // Update the previous entries and add a new localhost.
1067 history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
1068 "yey", 20, 15, false,
1070 history::URLRow updated_localhost_entry(MakeTypedUrlEntry(
1071 "http://localhost:80",
1072 "localhost", 20, 15, false,
1074 history::URLRow localhost_ip_entry(MakeTypedUrlEntry("http://127.0.0.1",
1075 "localhost", 12, 15, false,
1077 history::URLsModifiedDetails details;
1078 details.changed_urls.push_back(updated_url_entry);
1079 details.changed_urls.push_back(updated_localhost_entry);
1080 details.changed_urls.push_back(localhost_ip_entry);
1081 scoped_refptr<ThreadNotifier> notifier(
1082 new ThreadNotifier(history_thread_.get()));
1083 notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
1084 content::Source<Profile>(profile_),
1085 content::Details<history::URLsModifiedDetails>(&details));
1087 history::URLRows new_sync_entries;
1088 GetTypedUrlsFromSyncDB(&new_sync_entries);
1090 // We should ignore the localhost urls and left only with http url.
1091 ASSERT_EQ(1U, new_sync_entries.size());
1092 EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));