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.
5 #include "chrome/browser/sync/test/integration/typed_urls_helper.h"
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"
21 using sync_datatype_helper::test;
25 class FlushHistoryDBQueueTask : public history::HistoryDBTask {
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();
35 virtual void DoneRunOnMainThread() OVERRIDE {}
38 virtual ~FlushHistoryDBQueueTask() {}
40 base::WaitableEvent* wait_event_;
43 class GetTypedUrlsTask : public history::HistoryDBTask {
45 GetTypedUrlsTask(history::URLRows* rows, base::WaitableEvent* event)
46 : rows_(rows), wait_event_(event) {}
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();
56 virtual void DoneRunOnMainThread() OVERRIDE {}
59 virtual ~GetTypedUrlsTask() {}
61 history::URLRows* rows_;
62 base::WaitableEvent* wait_event_;
65 class GetUrlTask : public history::HistoryDBTask {
67 GetUrlTask(const GURL& url,
70 base::WaitableEvent* event)
71 : url_(url), row_(row), wait_event_(event), found_(found) {}
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();
81 virtual void DoneRunOnMainThread() OVERRIDE {}
84 virtual ~GetUrlTask() {}
87 history::URLRow* row_;
88 base::WaitableEvent* wait_event_;
92 class GetVisitsTask : public history::HistoryDBTask {
94 GetVisitsTask(history::URLID id,
95 history::VisitVector* visits,
96 base::WaitableEvent* event)
97 : id_(id), visits_(visits), wait_event_(event) {}
99 virtual bool RunOnDBThread(history::HistoryBackend* backend,
100 history::HistoryDatabase* db) OVERRIDE {
102 backend->GetVisitsForURL(id_, visits_);
103 wait_event_->Signal();
107 virtual void DoneRunOnMainThread() OVERRIDE {}
110 virtual ~GetVisitsTask() {}
113 history::VisitVector* visits_;
114 base::WaitableEvent* wait_event_;
117 class RemoveVisitsTask : public history::HistoryDBTask {
119 RemoveVisitsTask(const history::VisitVector& visits,
120 base::WaitableEvent* event)
121 : visits_(visits), wait_event_(event) {}
123 virtual bool RunOnDBThread(history::HistoryBackend* backend,
124 history::HistoryDatabase* db) OVERRIDE {
126 backend->RemoveVisits(visits_);
127 wait_event_->Signal();
131 virtual void DoneRunOnMainThread() OVERRIDE {}
134 virtual ~RemoveVisitsTask() {}
136 const history::VisitVector& visits_;
137 base::WaitableEvent* wait_event_;
140 // Waits for the history DB thread to finish executing its current set of
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);
152 // Creates a URLRow in the specified HistoryService with the passed transition
154 void AddToHistory(HistoryService* service,
156 content::PageTransition transition,
157 history::VisitSource source,
158 const base::Time& timestamp) {
159 service->AddPage(url,
164 history::RedirectList(),
168 service->SetPageTitle(url, ASCIIToUTF16(url.spec() + " - title"));
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);
181 bool GetUrlFromHistoryService(HistoryService* service,
182 const GURL& url, history::URLRow* row) {
183 CancelableRequestConsumer cancelable_consumer;
184 base::WaitableEvent wait_event(true, false);
186 service->ScheduleDBTask(new GetUrlTask(url, row, &found, &wait_event),
187 &cancelable_consumer);
192 history::VisitVector GetVisitsFromHistoryService(HistoryService* service,
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);
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);
212 static base::Time* timestamp = NULL;
216 namespace typed_urls_helper {
218 history::URLRows GetTypedUrlsFromClient(int index) {
219 HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
220 test()->GetProfile(index));
221 return GetTypedUrlsFromHistoryService(service);
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);
230 history::VisitVector GetVisitsFromClient(int index, history::URLID id) {
231 HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
232 test()->GetProfile(index));
233 return GetVisitsFromHistoryService(service, id);
236 void RemoveVisitsFromClient(int index, const history::VisitVector& visits) {
237 HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
238 test()->GetProfile(index));
239 RemoveVisitsFromHistoryService(service, visits);
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
248 ::timestamp = new base::Time(base::Time::Now());
249 base::Time original = *::timestamp;
250 *::timestamp += base::TimeDelta::FromMilliseconds(1);
254 void AddUrlToHistory(int index, const GURL& url) {
255 AddUrlToHistoryWithTransition(index, url, content::PAGE_TRANSITION_TYPED,
256 history::SOURCE_BROWSED);
258 void AddUrlToHistoryWithTransition(int index,
260 content::PageTransition transition,
261 history::VisitSource source) {
262 base::Time timestamp = GetTimestamp();
263 AddUrlToHistoryWithTimestamp(index, url, transition, source, timestamp);
265 void AddUrlToHistoryWithTimestamp(int index,
267 content::PageTransition transition,
268 history::VisitSource source,
269 const base::Time& timestamp) {
270 AddToHistory(HistoryServiceFactory::GetForProfileWithoutCreating(
271 test()->GetProfile(index)),
276 if (test()->use_verifier())
278 HistoryServiceFactory::GetForProfile(test()->verifier(),
279 Profile::IMPLICIT_ACCESS),
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);
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)->
298 WaitForHistoryDBThread(index);
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);
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
318 for (size_t j = 0; j < right.size(); ++j) {
319 if (left[i].url() == right[j].url()) {
320 AssertURLRowsAreEqual(left[i], right[j]);
329 bool AreVisitsEqual(const history::VisitVector& visit1,
330 const history::VisitVector& visit2) {
331 if (visit1.size() != visit2.size())
333 for (size_t i = 0; i < visit1.size(); ++i) {
334 if (visit1[i].transition != visit2[i].transition)
336 if (visit1[i].visit_time != visit2[i].visit_time)
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)
347 t = visits[i].visit_time;
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());
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);
374 } // namespace typed_urls_helper