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