typed_urls_helper.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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
21using sync_datatype_helper::test;
22
23namespace {
24
25class 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
43class 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
65class 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
92class 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
117class 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.
142void 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.
154void 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
171history::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
181bool 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
192history::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
203void 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
212static base::Time* timestamp = NULL;
213
214}  // namespace
215
216namespace typed_urls_helper {
217
218history::URLRows GetTypedUrlsFromClient(int index) {
219  HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
220      test()->GetProfile(index));
221  return GetTypedUrlsFromHistoryService(service);
222}
223
224bool 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
230history::VisitVector GetVisitsFromClient(int index, history::URLID id) {
231  HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
232      test()->GetProfile(index));
233  return GetVisitsFromHistoryService(service, id);
234}
235
236void RemoveVisitsFromClient(int index, const history::VisitVector& visits) {
237  HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
238      test()->GetProfile(index));
239  RemoveVisitsFromHistoryService(service, visits);
240}
241
242base::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
254void AddUrlToHistory(int index, const GURL& url) {
255  AddUrlToHistoryWithTransition(index, url, content::PAGE_TRANSITION_TYPED,
256                                history::SOURCE_BROWSED);
257}
258void 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}
265void 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
291void 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
301void 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
311void 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
329bool 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
342bool 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
352void 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
362void 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