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