Home | History | Annotate | Download | only in integration
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/test/integration/typed_urls_helper.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "base/synchronization/waitable_event.h"
     10 #include "base/time/time.h"
     11 #include "chrome/browser/common/cancelable_request.h"
     12 #include "chrome/browser/history/history_backend.h"
     13 #include "chrome/browser/history/history_db_task.h"
     14 #include "chrome/browser/history/history_service.h"
     15 #include "chrome/browser/history/history_service_factory.h"
     16 #include "chrome/browser/history/history_types.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
     19 #include "chrome/browser/sync/test/integration/sync_test.h"
     20 
     21 using sync_datatype_helper::test;
     22 
     23 namespace {
     24 
     25 class FlushHistoryDBQueueTask : public history::HistoryDBTask {
     26  public:
     27   explicit FlushHistoryDBQueueTask(base::WaitableEvent* event)
     28       : wait_event_(event) {}
     29   virtual bool RunOnDBThread(history::HistoryBackend* backend,
     30                              history::HistoryDatabase* db) OVERRIDE {
     31     wait_event_->Signal();
     32     return true;
     33   }
     34 
     35   virtual void DoneRunOnMainThread() OVERRIDE {}
     36 
     37  private:
     38   virtual ~FlushHistoryDBQueueTask() {}
     39 
     40   base::WaitableEvent* wait_event_;
     41 };
     42 
     43 class GetTypedUrlsTask : public history::HistoryDBTask {
     44  public:
     45   GetTypedUrlsTask(history::URLRows* rows, base::WaitableEvent* event)
     46       : rows_(rows), wait_event_(event) {}
     47 
     48   virtual bool RunOnDBThread(history::HistoryBackend* backend,
     49                              history::HistoryDatabase* db) OVERRIDE {
     50     // Fetch the typed URLs.
     51     backend->GetAllTypedURLs(rows_);
     52     wait_event_->Signal();
     53     return true;
     54   }
     55 
     56   virtual void DoneRunOnMainThread() OVERRIDE {}
     57 
     58  private:
     59   virtual ~GetTypedUrlsTask() {}
     60 
     61   history::URLRows* rows_;
     62   base::WaitableEvent* wait_event_;
     63 };
     64 
     65 class GetUrlTask : public history::HistoryDBTask {
     66  public:
     67   GetUrlTask(const GURL& url,
     68              history::URLRow* row,
     69              bool* found,
     70              base::WaitableEvent* event)
     71       : url_(url), row_(row), wait_event_(event), found_(found) {}
     72 
     73   virtual bool RunOnDBThread(history::HistoryBackend* backend,
     74                              history::HistoryDatabase* db) OVERRIDE {
     75     // Fetch the typed URLs.
     76     *found_ = backend->GetURL(url_, row_);
     77     wait_event_->Signal();
     78     return true;
     79   }
     80 
     81   virtual void DoneRunOnMainThread() OVERRIDE {}
     82 
     83  private:
     84   virtual ~GetUrlTask() {}
     85 
     86   GURL url_;
     87   history::URLRow* row_;
     88   base::WaitableEvent* wait_event_;
     89   bool* found_;
     90 };
     91 
     92 class GetVisitsTask : public history::HistoryDBTask {
     93  public:
     94   GetVisitsTask(history::URLID id,
     95                 history::VisitVector* visits,
     96                 base::WaitableEvent* event)
     97       : id_(id), visits_(visits), wait_event_(event) {}
     98 
     99   virtual bool RunOnDBThread(history::HistoryBackend* backend,
    100                              history::HistoryDatabase* db) OVERRIDE {
    101     // Fetch the visits.
    102     backend->GetVisitsForURL(id_, visits_);
    103     wait_event_->Signal();
    104     return true;
    105   }
    106 
    107   virtual void DoneRunOnMainThread() OVERRIDE {}
    108 
    109  private:
    110   virtual ~GetVisitsTask() {}
    111 
    112   history::URLID id_;
    113   history::VisitVector* visits_;
    114   base::WaitableEvent* wait_event_;
    115 };
    116 
    117 class RemoveVisitsTask : public history::HistoryDBTask {
    118  public:
    119   RemoveVisitsTask(const history::VisitVector& visits,
    120                    base::WaitableEvent* event)
    121       : visits_(visits), wait_event_(event) {}
    122 
    123   virtual bool RunOnDBThread(history::HistoryBackend* backend,
    124                              history::HistoryDatabase* db) OVERRIDE {
    125     // Fetch the visits.
    126     backend->RemoveVisits(visits_);
    127     wait_event_->Signal();
    128     return true;
    129   }
    130 
    131   virtual void DoneRunOnMainThread() OVERRIDE {}
    132 
    133  private:
    134   virtual ~RemoveVisitsTask() {}
    135 
    136   const history::VisitVector& visits_;
    137   base::WaitableEvent* wait_event_;
    138 };
    139 
    140 // Waits for the history DB thread to finish executing its current set of
    141 // tasks.
    142 void WaitForHistoryDBThread(int index) {
    143   CancelableRequestConsumer cancelable_consumer;
    144   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
    145       test()->GetProfile(index));
    146   base::WaitableEvent wait_event(true, false);
    147   service->ScheduleDBTask(new FlushHistoryDBQueueTask(&wait_event),
    148                           &cancelable_consumer);
    149   wait_event.Wait();
    150 }
    151 
    152 // Creates a URLRow in the specified HistoryService with the passed transition
    153 // type.
    154 void AddToHistory(HistoryService* service,
    155                   const GURL& url,
    156                   content::PageTransition transition,
    157                   history::VisitSource source,
    158                   const base::Time& timestamp) {
    159   service->AddPage(url,
    160                    timestamp,
    161                    NULL, // scope
    162                    1234, // page_id
    163                    GURL(),  // referrer
    164                    history::RedirectList(),
    165                    transition,
    166                    source,
    167                    false);
    168   service->SetPageTitle(url, ASCIIToUTF16(url.spec() + " - title"));
    169 }
    170 
    171 history::URLRows GetTypedUrlsFromHistoryService(HistoryService* service) {
    172   CancelableRequestConsumer cancelable_consumer;
    173   history::URLRows rows;
    174   base::WaitableEvent wait_event(true, false);
    175   service->ScheduleDBTask(new GetTypedUrlsTask(&rows, &wait_event),
    176                           &cancelable_consumer);
    177   wait_event.Wait();
    178   return rows;
    179 }
    180 
    181 bool GetUrlFromHistoryService(HistoryService* service,
    182                               const GURL& url, history::URLRow* row) {
    183   CancelableRequestConsumer cancelable_consumer;
    184   base::WaitableEvent wait_event(true, false);
    185   bool found;
    186   service->ScheduleDBTask(new GetUrlTask(url, row, &found, &wait_event),
    187                           &cancelable_consumer);
    188   wait_event.Wait();
    189   return found;
    190 }
    191 
    192 history::VisitVector GetVisitsFromHistoryService(HistoryService* service,
    193                                                  history::URLID id) {
    194   CancelableRequestConsumer cancelable_consumer;
    195   base::WaitableEvent wait_event(true, false);
    196   history::VisitVector visits;
    197   service->ScheduleDBTask(new GetVisitsTask(id, &visits, &wait_event),
    198                           &cancelable_consumer);
    199   wait_event.Wait();
    200   return visits;
    201 }
    202 
    203 void RemoveVisitsFromHistoryService(HistoryService* service,
    204                                     const history::VisitVector& visits) {
    205   CancelableRequestConsumer cancelable_consumer;
    206   base::WaitableEvent wait_event(true, false);
    207   service->ScheduleDBTask(new RemoveVisitsTask(visits, &wait_event),
    208                           &cancelable_consumer);
    209   wait_event.Wait();
    210 }
    211 
    212 static base::Time* timestamp = NULL;
    213 
    214 }  // namespace
    215 
    216 namespace typed_urls_helper {
    217 
    218 history::URLRows GetTypedUrlsFromClient(int index) {
    219   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
    220       test()->GetProfile(index));
    221   return GetTypedUrlsFromHistoryService(service);
    222 }
    223 
    224 bool GetUrlFromClient(int index, const GURL& url, history::URLRow* row) {
    225   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
    226       test()->GetProfile(index));
    227   return GetUrlFromHistoryService(service, url, row);
    228 }
    229 
    230 history::VisitVector GetVisitsFromClient(int index, history::URLID id) {
    231   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
    232       test()->GetProfile(index));
    233   return GetVisitsFromHistoryService(service, id);
    234 }
    235 
    236 void RemoveVisitsFromClient(int index, const history::VisitVector& visits) {
    237   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
    238       test()->GetProfile(index));
    239   RemoveVisitsFromHistoryService(service, visits);
    240 }
    241 
    242 base::Time GetTimestamp() {
    243   // The history subsystem doesn't like identical timestamps for page visits,
    244   // and it will massage the visit timestamps if we try to use identical
    245   // values, which can lead to spurious errors. So make sure all timestamps
    246   // are unique.
    247   if (!::timestamp)
    248     ::timestamp = new base::Time(base::Time::Now());
    249   base::Time original = *::timestamp;
    250   *::timestamp += base::TimeDelta::FromMilliseconds(1);
    251   return original;
    252 }
    253 
    254 void AddUrlToHistory(int index, const GURL& url) {
    255   AddUrlToHistoryWithTransition(index, url, content::PAGE_TRANSITION_TYPED,
    256                                 history::SOURCE_BROWSED);
    257 }
    258 void AddUrlToHistoryWithTransition(int index,
    259                                    const GURL& url,
    260                                    content::PageTransition transition,
    261                                    history::VisitSource source) {
    262   base::Time timestamp = GetTimestamp();
    263   AddUrlToHistoryWithTimestamp(index, url, transition, source, timestamp);
    264 }
    265 void AddUrlToHistoryWithTimestamp(int index,
    266                                   const GURL& url,
    267                                   content::PageTransition transition,
    268                                   history::VisitSource source,
    269                                   const base::Time& timestamp) {
    270   AddToHistory(HistoryServiceFactory::GetForProfileWithoutCreating(
    271                    test()->GetProfile(index)),
    272                url,
    273                transition,
    274                source,
    275                timestamp);
    276   if (test()->use_verifier())
    277     AddToHistory(
    278         HistoryServiceFactory::GetForProfile(test()->verifier(),
    279                                              Profile::IMPLICIT_ACCESS),
    280         url,
    281         transition,
    282         source,
    283         timestamp);
    284 
    285   // Wait until the AddPage() request has completed so we know the change has
    286   // filtered down to the sync observers (don't need to wait for the
    287   // verifier profile since it doesn't sync).
    288   WaitForHistoryDBThread(index);
    289 }
    290 
    291 void DeleteUrlFromHistory(int index, const GURL& url) {
    292   HistoryServiceFactory::GetForProfileWithoutCreating(
    293       test()->GetProfile(index))->DeleteURL(url);
    294   if (test()->use_verifier())
    295     HistoryServiceFactory::GetForProfile(test()->verifier(),
    296                                          Profile::IMPLICIT_ACCESS)->
    297         DeleteURL(url);
    298   WaitForHistoryDBThread(index);
    299 }
    300 
    301 void DeleteUrlsFromHistory(int index, const std::vector<GURL>& urls) {
    302   HistoryServiceFactory::GetForProfileWithoutCreating(
    303       test()->GetProfile(index))->DeleteURLsForTest(urls);
    304   if (test()->use_verifier())
    305     HistoryServiceFactory::GetForProfile(test()->verifier(),
    306                                          Profile::IMPLICIT_ACCESS)->
    307         DeleteURLsForTest(urls);
    308   WaitForHistoryDBThread(index);
    309 }
    310 
    311 void AssertURLRowVectorsAreEqual(const history::URLRows& left,
    312                                  const history::URLRows& right) {
    313   ASSERT_EQ(left.size(), right.size());
    314   for (size_t i = 0; i < left.size(); ++i) {
    315     // URLs could be out-of-order, so look for a matching URL in the second
    316     // array.
    317     bool found = false;
    318     for (size_t j = 0; j < right.size(); ++j) {
    319       if (left[i].url() == right[j].url()) {
    320         AssertURLRowsAreEqual(left[i], right[j]);
    321         found = true;
    322         break;
    323       }
    324     }
    325     ASSERT_TRUE(found);
    326   }
    327 }
    328 
    329 bool AreVisitsEqual(const history::VisitVector& visit1,
    330                     const history::VisitVector& visit2) {
    331   if (visit1.size() != visit2.size())
    332     return false;
    333   for (size_t i = 0; i < visit1.size(); ++i) {
    334     if (visit1[i].transition != visit2[i].transition)
    335       return false;
    336     if (visit1[i].visit_time != visit2[i].visit_time)
    337       return false;
    338   }
    339   return true;
    340 }
    341 
    342 bool AreVisitsUnique(const history::VisitVector& visits) {
    343   base::Time t = base::Time::FromInternalValue(0);
    344   for (size_t i = 0; i < visits.size(); ++i) {
    345     if (t == visits[i].visit_time)
    346       return false;
    347     t = visits[i].visit_time;
    348   }
    349   return true;
    350 }
    351 
    352 void AssertURLRowsAreEqual(
    353     const history::URLRow& left, const history::URLRow& right) {
    354   ASSERT_EQ(left.url(), right.url());
    355   ASSERT_EQ(left.title(), right.title());
    356   ASSERT_EQ(left.visit_count(), right.visit_count());
    357   ASSERT_EQ(left.typed_count(), right.typed_count());
    358   ASSERT_EQ(left.last_visit(), right.last_visit());
    359   ASSERT_EQ(left.hidden(), right.hidden());
    360 }
    361 
    362 void AssertAllProfilesHaveSameURLsAsVerifier() {
    363   HistoryService* verifier_service =
    364       HistoryServiceFactory::GetForProfile(test()->verifier(),
    365                                            Profile::IMPLICIT_ACCESS);
    366   history::URLRows verifier_urls =
    367       GetTypedUrlsFromHistoryService(verifier_service);
    368   for (int i = 0; i < test()->num_clients(); ++i) {
    369     history::URLRows urls = GetTypedUrlsFromClient(i);
    370     AssertURLRowVectorsAreEqual(verifier_urls, urls);
    371   }
    372 }
    373 
    374 }  // namespace typed_urls_helper
    375