Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <vector>
      6 
      7 #include "testing/gtest/include/gtest/gtest.h"
      8 
      9 #include "base/memory/ref_counted.h"
     10 #include "base/string16.h"
     11 #include "base/threading/thread.h"
     12 #include "base/time.h"
     13 #include "chrome/browser/history/history_backend.h"
     14 #include "chrome/browser/history/history_notifications.h"
     15 #include "chrome/browser/history/history_types.h"
     16 #include "chrome/browser/sync/abstract_profile_sync_service_test.h"
     17 #include "chrome/browser/sync/engine/syncapi.h"
     18 #include "chrome/browser/sync/glue/sync_backend_host.h"
     19 #include "chrome/browser/sync/glue/sync_backend_host_mock.h"
     20 #include "chrome/browser/sync/glue/typed_url_change_processor.h"
     21 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
     22 #include "chrome/browser/sync/glue/typed_url_model_associator.h"
     23 #include "chrome/browser/sync/profile_sync_factory.h"
     24 #include "chrome/browser/sync/profile_sync_factory_mock.h"
     25 #include "chrome/browser/sync/profile_sync_service.h"
     26 #include "chrome/browser/sync/profile_sync_test_util.h"
     27 #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
     28 #include "chrome/browser/sync/syncable/directory_manager.h"
     29 #include "chrome/browser/sync/test_profile_sync_service.h"
     30 #include "chrome/common/net/gaia/gaia_constants.h"
     31 #include "chrome/test/profile_mock.h"
     32 #include "chrome/test/sync/engine/test_id_factory.h"
     33 #include "chrome/test/testing_profile.h"
     34 #include "content/common/notification_service.h"
     35 #include "googleurl/src/gurl.h"
     36 #include "testing/gmock/include/gmock/gmock.h"
     37 
     38 using base::Time;
     39 using base::Thread;
     40 using browser_sync::SyncBackendHost;
     41 using browser_sync::SyncBackendHostMock;
     42 using browser_sync::TestIdFactory;
     43 using browser_sync::TypedUrlChangeProcessor;
     44 using browser_sync::TypedUrlDataTypeController;
     45 using browser_sync::TypedUrlModelAssociator;
     46 using browser_sync::UnrecoverableErrorHandler;
     47 using history::HistoryBackend;
     48 using history::URLID;
     49 using history::URLRow;
     50 using sync_api::SyncManager;
     51 using sync_api::UserShare;
     52 using syncable::BASE_VERSION;
     53 using syncable::CREATE;
     54 using syncable::DirectoryManager;
     55 using syncable::IS_DEL;
     56 using syncable::IS_DIR;
     57 using syncable::IS_UNAPPLIED_UPDATE;
     58 using syncable::IS_UNSYNCED;
     59 using syncable::MutableEntry;
     60 using syncable::SERVER_IS_DIR;
     61 using syncable::SERVER_VERSION;
     62 using syncable::SPECIFICS;
     63 using syncable::ScopedDirLookup;
     64 using syncable::UNIQUE_SERVER_TAG;
     65 using syncable::UNITTEST;
     66 using syncable::WriteTransaction;
     67 using testing::_;
     68 using testing::DoAll;
     69 using testing::DoDefault;
     70 using testing::Invoke;
     71 using testing::Return;
     72 using testing::SetArgumentPointee;
     73 using testing::WithArgs;
     74 
     75 class HistoryBackendMock : public HistoryBackend {
     76  public:
     77   HistoryBackendMock() : HistoryBackend(FilePath(), NULL, NULL) {}
     78   MOCK_METHOD1(GetAllTypedURLs, bool(std::vector<history::URLRow>* entries));
     79   MOCK_METHOD2(GetVisitsForURL, bool(history::URLID id,
     80                                      history::VisitVector* visits));
     81   MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
     82   MOCK_METHOD3(AddVisits, bool(const GURL& url,
     83                                const std::vector<base::Time>& visits,
     84                                history::VisitSource visit_source));
     85   MOCK_METHOD1(RemoveVisits, bool(const history::VisitVector& visits));
     86   MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
     87   MOCK_METHOD2(SetPageTitle, void(const GURL& url, const string16& title));
     88   MOCK_METHOD1(DeleteURL, void(const GURL& url));
     89 };
     90 
     91 class HistoryServiceMock : public HistoryService {
     92  public:
     93   HistoryServiceMock() {}
     94   MOCK_METHOD2(ScheduleDBTask, Handle(HistoryDBTask*,
     95                                       CancelableRequestConsumerBase*));
     96 };
     97 
     98 class RunOnDBThreadTask : public Task {
     99  public:
    100   RunOnDBThreadTask(HistoryBackend* backend, HistoryDBTask* task)
    101       : backend_(backend), task_(task) {}
    102   virtual void Run() {
    103     task_->RunOnDBThread(backend_, NULL);
    104     task_ = NULL;
    105   }
    106  private:
    107   HistoryBackend* backend_;
    108   scoped_refptr<HistoryDBTask> task_;
    109 };
    110 
    111 ACTION_P2(RunTaskOnDBThread, thread, backend) {
    112  thread->message_loop()->PostTask(
    113     FROM_HERE,
    114     new RunOnDBThreadTask(backend, arg0));
    115  return 0;
    116 }
    117 
    118 ACTION_P3(MakeTypedUrlSyncComponents, service, hb, dtc) {
    119   TypedUrlModelAssociator* model_associator =
    120       new TypedUrlModelAssociator(service, hb);
    121   TypedUrlChangeProcessor* change_processor =
    122       new TypedUrlChangeProcessor(model_associator, hb, service);
    123   return ProfileSyncFactory::SyncComponents(model_associator, change_processor);
    124 }
    125 
    126 class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
    127  protected:
    128   ProfileSyncServiceTypedUrlTest()
    129       : history_thread_("history") {
    130   }
    131 
    132   virtual void SetUp() {
    133     profile_.CreateRequestContext();
    134     history_backend_ = new HistoryBackendMock();
    135     history_service_ = new HistoryServiceMock();
    136     EXPECT_CALL((*history_service_.get()), ScheduleDBTask(_, _))
    137         .WillRepeatedly(RunTaskOnDBThread(&history_thread_,
    138                                           history_backend_.get()));
    139     history_thread_.Start();
    140 
    141     notification_service_ =
    142       new ThreadNotificationService(&history_thread_);
    143     notification_service_->Init();
    144   }
    145 
    146   virtual void TearDown() {
    147     history_backend_ = NULL;
    148     history_service_ = NULL;
    149     service_.reset();
    150     notification_service_->TearDown();
    151     history_thread_.Stop();
    152     {
    153       // The request context gets deleted on the I/O thread. To prevent a leak
    154       // supply one here.
    155       BrowserThread io_thread(BrowserThread::IO, MessageLoop::current());
    156       profile_.ResetRequestContext();
    157     }
    158     MessageLoop::current()->RunAllPending();
    159   }
    160 
    161   void StartSyncService(Task* task) {
    162     if (!service_.get()) {
    163       service_.reset(
    164           new TestProfileSyncService(&factory_, &profile_, "test", false,
    165                                      task));
    166       TypedUrlDataTypeController* data_type_controller =
    167           new TypedUrlDataTypeController(&factory_,
    168                                          &profile_,
    169                                          service_.get());
    170 
    171       EXPECT_CALL(factory_, CreateTypedUrlSyncComponents(_, _, _)).
    172           WillOnce(MakeTypedUrlSyncComponents(service_.get(),
    173                                               history_backend_.get(),
    174                                               data_type_controller));
    175       EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
    176           WillOnce(ReturnNewDataTypeManager());
    177 
    178       EXPECT_CALL(profile_, GetHistoryServiceWithoutCreating()).
    179           WillRepeatedly(Return(history_service_.get()));
    180 
    181       EXPECT_CALL(profile_, GetPasswordStore(_)).
    182           WillOnce(Return(static_cast<PasswordStore*>(NULL)));
    183 
    184       EXPECT_CALL(profile_, GetHistoryService(_)).
    185           WillRepeatedly(Return(history_service_.get()));
    186 
    187       token_service_.IssueAuthTokenForTest(
    188           GaiaConstants::kSyncService, "token");
    189 
    190       EXPECT_CALL(profile_, GetTokenService()).
    191           WillRepeatedly(Return(&token_service_));
    192 
    193       service_->RegisterDataTypeController(data_type_controller);
    194 
    195       service_->Initialize();
    196       MessageLoop::current()->Run();
    197     }
    198   }
    199 
    200   void AddTypedUrlSyncNode(const history::URLRow& url,
    201                            const history::VisitVector& visits) {
    202     sync_api::WriteTransaction trans(service_->GetUserShare());
    203     sync_api::ReadNode typed_url_root(&trans);
    204     ASSERT_TRUE(typed_url_root.InitByTagLookup(browser_sync::kTypedUrlTag));
    205 
    206     sync_api::WriteNode node(&trans);
    207     std::string tag = url.url().spec();
    208     ASSERT_TRUE(node.InitUniqueByCreation(syncable::TYPED_URLS,
    209                                           typed_url_root,
    210                                           tag));
    211     TypedUrlModelAssociator::WriteToSyncNode(url, visits, &node);
    212   }
    213 
    214   void GetTypedUrlsFromSyncDB(std::vector<history::URLRow>* urls) {
    215     sync_api::ReadTransaction trans(service_->GetUserShare());
    216     sync_api::ReadNode typed_url_root(&trans);
    217     if (!typed_url_root.InitByTagLookup(browser_sync::kTypedUrlTag))
    218       return;
    219 
    220     int64 child_id = typed_url_root.GetFirstChildId();
    221     while (child_id != sync_api::kInvalidId) {
    222       sync_api::ReadNode child_node(&trans);
    223       if (!child_node.InitByIdLookup(child_id))
    224         return;
    225 
    226       const sync_pb::TypedUrlSpecifics& typed_url(
    227           child_node.GetTypedUrlSpecifics());
    228       history::URLRow new_url(GURL(typed_url.url()));
    229 
    230       new_url.set_title(UTF8ToUTF16(typed_url.title()));
    231       new_url.set_typed_count(typed_url.typed_count());
    232       DCHECK(typed_url.visit_size());
    233       new_url.set_visit_count(typed_url.visit_size());
    234       new_url.set_last_visit(base::Time::FromInternalValue(
    235           typed_url.visit(typed_url.visit_size() - 1)));
    236       new_url.set_hidden(typed_url.hidden());
    237 
    238       urls->push_back(new_url);
    239       child_id = child_node.GetSuccessorId();
    240     }
    241   }
    242 
    243   void SetIdleChangeProcessorExpectations() {
    244     EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).Times(0);
    245     EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).Times(0);
    246     EXPECT_CALL((*history_backend_.get()), GetURL(_, _)).Times(0);
    247     EXPECT_CALL((*history_backend_.get()), DeleteURL(_)).Times(0);
    248   }
    249 
    250   static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
    251     return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
    252            (lhs.title().compare(rhs.title()) == 0) &&
    253            (lhs.visit_count() == rhs.visit_count()) &&
    254            (lhs.typed_count() == rhs.typed_count()) &&
    255            (lhs.last_visit() == rhs.last_visit()) &&
    256            (lhs.hidden() == rhs.hidden());
    257   }
    258 
    259   static history::URLRow MakeTypedUrlEntry(const char* url,
    260                                            const char* title,
    261                                            int typed_count,
    262                                            int64 last_visit,
    263                                            bool hidden,
    264                                            history::VisitVector* visits) {
    265     GURL gurl(url);
    266     URLRow history_url(gurl);
    267     history_url.set_title(UTF8ToUTF16(title));
    268     history_url.set_typed_count(typed_count);
    269     history_url.set_last_visit(
    270         base::Time::FromInternalValue(last_visit));
    271     history_url.set_hidden(hidden);
    272     visits->push_back(history::VisitRow(
    273         history_url.id(), history_url.last_visit(), 0, 0, 0));
    274     history_url.set_visit_count(visits->size());
    275     return history_url;
    276   }
    277 
    278   friend class AddTypedUrlEntriesTask;
    279   friend class CreateTypedUrlRootTask;
    280 
    281   Thread history_thread_;
    282   scoped_refptr<ThreadNotificationService> notification_service_;
    283 
    284   ProfileMock profile_;
    285   ProfileSyncFactoryMock factory_;
    286   scoped_refptr<HistoryBackendMock> history_backend_;
    287   scoped_refptr<HistoryServiceMock> history_service_;
    288 };
    289 
    290 class AddTypedUrlEntriesTask : public Task {
    291  public:
    292   AddTypedUrlEntriesTask(ProfileSyncServiceTypedUrlTest* test,
    293                          const std::vector<history::URLRow>& entries)
    294       : test_(test), entries_(entries) {
    295   }
    296 
    297   virtual void Run() {
    298     test_->CreateRoot(syncable::TYPED_URLS);
    299     for (size_t i = 0; i < entries_.size(); ++i) {
    300       history::VisitVector visits;
    301       visits.push_back(history::VisitRow(
    302           entries_[i].id(), entries_[i].last_visit(), 0, 0, 0));
    303       test_->AddTypedUrlSyncNode(entries_[i], visits);
    304     }
    305   }
    306 
    307  private:
    308   ProfileSyncServiceTypedUrlTest* test_;
    309   const std::vector<history::URLRow>& entries_;
    310 };
    311 
    312 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
    313   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    314       WillOnce(Return(true));
    315   SetIdleChangeProcessorExpectations();
    316   CreateRootTask task(this, syncable::TYPED_URLS);
    317   StartSyncService(&task);
    318   std::vector<history::URLRow> sync_entries;
    319   GetTypedUrlsFromSyncDB(&sync_entries);
    320   EXPECT_EQ(0U, sync_entries.size());
    321 }
    322 
    323 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
    324   std::vector<history::URLRow> entries;
    325   history::VisitVector visits;
    326   entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
    327                                       2, 15, false, &visits));
    328 
    329   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    330       WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
    331   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    332       WillRepeatedly(DoAll(SetArgumentPointee<1>(visits), Return(true)));
    333   SetIdleChangeProcessorExpectations();
    334   CreateRootTask task(this, syncable::TYPED_URLS);
    335   StartSyncService(&task);
    336   std::vector<history::URLRow> sync_entries;
    337   GetTypedUrlsFromSyncDB(&sync_entries);
    338   ASSERT_EQ(1U, sync_entries.size());
    339   EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0]));
    340 }
    341 
    342 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
    343   history::VisitVector native_visits;
    344   history::VisitVector sync_visits;
    345   history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
    346                                                  2, 15, false, &native_visits));
    347   history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
    348                                                3, 16, false, &sync_visits));
    349 
    350   std::vector<history::URLRow> native_entries;
    351   native_entries.push_back(native_entry);
    352   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    353       WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
    354   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    355       WillRepeatedly(DoAll(SetArgumentPointee<1>(native_visits), Return(true)));
    356   EXPECT_CALL((*history_backend_.get()),
    357       AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(true));
    358 
    359   std::vector<history::URLRow> sync_entries;
    360   sync_entries.push_back(sync_entry);
    361   AddTypedUrlEntriesTask task(this, sync_entries);
    362 
    363   EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
    364       WillRepeatedly(Return(true));
    365   StartSyncService(&task);
    366 
    367   std::map<std::string, history::URLRow> expected;
    368   expected[native_entry.url().spec()] = native_entry;
    369   expected[sync_entry.url().spec()] = sync_entry;
    370 
    371   std::vector<history::URLRow> new_sync_entries;
    372   GetTypedUrlsFromSyncDB(&new_sync_entries);
    373 
    374   EXPECT_TRUE(new_sync_entries.size() == expected.size());
    375   for (std::vector<history::URLRow>::iterator entry = new_sync_entries.begin();
    376        entry != new_sync_entries.end(); ++entry) {
    377     EXPECT_TRUE(URLsEqual(expected[entry->url().spec()], *entry));
    378   }
    379 }
    380 
    381 TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
    382   history::VisitVector native_visits;
    383   history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
    384                                                  2, 15, false, &native_visits));
    385   history::VisitVector sync_visits;
    386   history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name",
    387                                                1, 17, false, &sync_visits));
    388   history::VisitVector merged_visits;
    389   merged_visits.push_back(history::VisitRow(
    390       sync_entry.id(), base::Time::FromInternalValue(15), 0, 0, 0));
    391 
    392   history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name",
    393                                                  2, 17, false, &merged_visits));
    394 
    395   std::vector<history::URLRow> native_entries;
    396   native_entries.push_back(native_entry);
    397   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    398       WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
    399   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    400       WillRepeatedly(DoAll(SetArgumentPointee<1>(native_visits), Return(true)));
    401   EXPECT_CALL((*history_backend_.get()),
    402       AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
    403 
    404   std::vector<history::URLRow> sync_entries;
    405   sync_entries.push_back(sync_entry);
    406   AddTypedUrlEntriesTask task(this, sync_entries);
    407 
    408   EXPECT_CALL((*history_backend_.get()), UpdateURL(_, _)).
    409       WillRepeatedly(Return(true));
    410   EXPECT_CALL((*history_backend_.get()), SetPageTitle(_, _)).
    411       WillRepeatedly(Return());
    412   StartSyncService(&task);
    413 
    414   std::vector<history::URLRow> new_sync_entries;
    415   GetTypedUrlsFromSyncDB(&new_sync_entries);
    416   ASSERT_EQ(1U, new_sync_entries.size());
    417   EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0]));
    418 }
    419 
    420 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
    421   history::VisitVector added_visits;
    422   history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
    423                                                 2, 15, false, &added_visits));
    424 
    425   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    426       WillOnce(Return(true));
    427   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    428       WillOnce(DoAll(SetArgumentPointee<1>(added_visits), Return(true)));
    429 
    430   SetIdleChangeProcessorExpectations();
    431   CreateRootTask task(this, syncable::TYPED_URLS);
    432   StartSyncService(&task);
    433 
    434   history::URLsModifiedDetails details;
    435   details.changed_urls.push_back(added_entry);
    436   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
    437   notifier->Notify(NotificationType::HISTORY_TYPED_URLS_MODIFIED,
    438                    Details<history::URLsModifiedDetails>(&details));
    439 
    440   std::vector<history::URLRow> new_sync_entries;
    441   GetTypedUrlsFromSyncDB(&new_sync_entries);
    442   ASSERT_EQ(1U, new_sync_entries.size());
    443   EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
    444 }
    445 
    446 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
    447   history::VisitVector original_visits;
    448   history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
    449                                                    2, 15, false,
    450                                                    &original_visits));
    451   std::vector<history::URLRow> original_entries;
    452   original_entries.push_back(original_entry);
    453 
    454   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    455       WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
    456   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    457       WillRepeatedly(DoAll(SetArgumentPointee<1>(original_visits),
    458                            Return(true)));
    459   CreateRootTask task(this, syncable::TYPED_URLS);
    460   StartSyncService(&task);
    461 
    462   history::VisitVector updated_visits;
    463   history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
    464                                                   7, 15, false,
    465                                                   &updated_visits));
    466 
    467   history::URLsModifiedDetails details;
    468   details.changed_urls.push_back(updated_entry);
    469   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
    470   notifier->Notify(NotificationType::HISTORY_TYPED_URLS_MODIFIED,
    471                    Details<history::URLsModifiedDetails>(&details));
    472 
    473   std::vector<history::URLRow> new_sync_entries;
    474   GetTypedUrlsFromSyncDB(&new_sync_entries);
    475   ASSERT_EQ(1U, new_sync_entries.size());
    476   EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
    477 }
    478 
    479 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
    480   history::VisitVector original_visits1;
    481   history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
    482                                                     2, 15, false,
    483                                                     &original_visits1));
    484   history::VisitVector original_visits2;
    485   history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
    486                                                     "entry2",
    487                                                     3, 15, false,
    488                                                     &original_visits2));
    489   std::vector<history::URLRow> original_entries;
    490   original_entries.push_back(original_entry1);
    491   original_entries.push_back(original_entry2);
    492 
    493   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    494       WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
    495   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    496       WillRepeatedly(DoAll(SetArgumentPointee<1>(original_visits1),
    497                            Return(true)));
    498   CreateRootTask task(this, syncable::TYPED_URLS);
    499   StartSyncService(&task);
    500 
    501   history::URLsDeletedDetails changes;
    502   changes.all_history = false;
    503   changes.urls.insert(GURL("http://mine.com"));
    504   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
    505   notifier->Notify(NotificationType::HISTORY_URLS_DELETED,
    506                    Details<history::URLsDeletedDetails>(&changes));
    507 
    508   std::vector<history::URLRow> new_sync_entries;
    509   GetTypedUrlsFromSyncDB(&new_sync_entries);
    510   ASSERT_EQ(1U, new_sync_entries.size());
    511   EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0]));
    512 }
    513 
    514 TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
    515   history::VisitVector original_visits1;
    516   history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
    517                                                     2, 15, false,
    518                                                     &original_visits1));
    519   history::VisitVector original_visits2;
    520   history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
    521                                                     "entry2",
    522                                                     3, 15, false,
    523                                                     &original_visits2));
    524   std::vector<history::URLRow> original_entries;
    525   original_entries.push_back(original_entry1);
    526   original_entries.push_back(original_entry2);
    527 
    528   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
    529       WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
    530   EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
    531       WillRepeatedly(DoAll(SetArgumentPointee<1>(original_visits1),
    532                            Return(true)));
    533   CreateRootTask task(this, syncable::TYPED_URLS);
    534   StartSyncService(&task);
    535 
    536   history::URLsDeletedDetails changes;
    537   changes.all_history = true;
    538   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
    539   notifier->Notify(NotificationType::HISTORY_URLS_DELETED,
    540                    Details<history::URLsDeletedDetails>(&changes));
    541 
    542   std::vector<history::URLRow> new_sync_entries;
    543   GetTypedUrlsFromSyncDB(&new_sync_entries);
    544   ASSERT_EQ(0U, new_sync_entries.size());
    545 }
    546