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