Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / typed_urls_helper.cc
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/task/cancelable_task_tracker.h"
11 #include "base/time/time.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
22 using sync_datatype_helper::test;
23
24 namespace {
25
26 class 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
44 class 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
66 class 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
93 class 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
118 class 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.
143 void WaitForHistoryDBThread(int index) {
144   base::CancelableTaskTracker tracker;
145   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
146       test()->GetProfile(index));
147   base::WaitableEvent wait_event(true, false);
148   service->ScheduleDBTask(
149       scoped_ptr<history::HistoryDBTask>(
150           new FlushHistoryDBQueueTask(&wait_event)),
151       &tracker);
152   wait_event.Wait();
153 }
154
155 // Creates a URLRow in the specified HistoryService with the passed transition
156 // type.
157 void AddToHistory(HistoryService* service,
158                   const GURL& url,
159                   content::PageTransition transition,
160                   history::VisitSource source,
161                   const base::Time& timestamp) {
162   service->AddPage(url,
163                    timestamp,
164                    NULL, // scope
165                    1234, // page_id
166                    GURL(),  // referrer
167                    history::RedirectList(),
168                    transition,
169                    source,
170                    false);
171   service->SetPageTitle(url, base::ASCIIToUTF16(url.spec() + " - title"));
172 }
173
174 history::URLRows GetTypedUrlsFromHistoryService(HistoryService* service) {
175   base::CancelableTaskTracker tracker;
176   history::URLRows rows;
177   base::WaitableEvent wait_event(true, false);
178   service->ScheduleDBTask(
179       scoped_ptr<history::HistoryDBTask>(
180           new GetTypedUrlsTask(&rows, &wait_event)),
181       &tracker);
182   wait_event.Wait();
183   return rows;
184 }
185
186 bool GetUrlFromHistoryService(HistoryService* service,
187                               const GURL& url, history::URLRow* row) {
188   base::CancelableTaskTracker tracker;
189   base::WaitableEvent wait_event(true, false);
190   bool found = false;
191   service->ScheduleDBTask(
192       scoped_ptr<history::HistoryDBTask>(
193           new GetUrlTask(url, row, &found, &wait_event)),
194       &tracker);
195   wait_event.Wait();
196   return found;
197 }
198
199 history::VisitVector GetVisitsFromHistoryService(HistoryService* service,
200                                                  history::URLID id) {
201   base::CancelableTaskTracker tracker;
202   base::WaitableEvent wait_event(true, false);
203   history::VisitVector visits;
204   service->ScheduleDBTask(
205       scoped_ptr<history::HistoryDBTask>(
206           new GetVisitsTask(id, &visits, &wait_event)),
207       &tracker);
208   wait_event.Wait();
209   return visits;
210 }
211
212 void RemoveVisitsFromHistoryService(HistoryService* service,
213                                     const history::VisitVector& visits) {
214   base::CancelableTaskTracker tracker;
215   base::WaitableEvent wait_event(true, false);
216   service->ScheduleDBTask(
217       scoped_ptr<history::HistoryDBTask>(
218           new RemoveVisitsTask(visits, &wait_event)),
219       &tracker);
220   wait_event.Wait();
221 }
222
223 static base::Time* timestamp = NULL;
224
225 }  // namespace
226
227 namespace typed_urls_helper {
228
229 history::URLRows GetTypedUrlsFromClient(int index) {
230   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
231       test()->GetProfile(index));
232   return GetTypedUrlsFromHistoryService(service);
233 }
234
235 bool GetUrlFromClient(int index, const GURL& url, history::URLRow* row) {
236   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
237       test()->GetProfile(index));
238   return GetUrlFromHistoryService(service, url, row);
239 }
240
241 history::VisitVector GetVisitsFromClient(int index, history::URLID id) {
242   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
243       test()->GetProfile(index));
244   return GetVisitsFromHistoryService(service, id);
245 }
246
247 void RemoveVisitsFromClient(int index, const history::VisitVector& visits) {
248   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
249       test()->GetProfile(index));
250   RemoveVisitsFromHistoryService(service, visits);
251 }
252
253 base::Time GetTimestamp() {
254   // The history subsystem doesn't like identical timestamps for page visits,
255   // and it will massage the visit timestamps if we try to use identical
256   // values, which can lead to spurious errors. So make sure all timestamps
257   // are unique.
258   if (!::timestamp)
259     ::timestamp = new base::Time(base::Time::Now());
260   base::Time original = *::timestamp;
261   *::timestamp += base::TimeDelta::FromMilliseconds(1);
262   return original;
263 }
264
265 void AddUrlToHistory(int index, const GURL& url) {
266   AddUrlToHistoryWithTransition(index, url, content::PAGE_TRANSITION_TYPED,
267                                 history::SOURCE_BROWSED);
268 }
269 void AddUrlToHistoryWithTransition(int index,
270                                    const GURL& url,
271                                    content::PageTransition transition,
272                                    history::VisitSource source) {
273   base::Time timestamp = GetTimestamp();
274   AddUrlToHistoryWithTimestamp(index, url, transition, source, timestamp);
275 }
276 void AddUrlToHistoryWithTimestamp(int index,
277                                   const GURL& url,
278                                   content::PageTransition transition,
279                                   history::VisitSource source,
280                                   const base::Time& timestamp) {
281   AddToHistory(HistoryServiceFactory::GetForProfileWithoutCreating(
282                    test()->GetProfile(index)),
283                url,
284                transition,
285                source,
286                timestamp);
287   if (test()->use_verifier())
288     AddToHistory(
289         HistoryServiceFactory::GetForProfile(test()->verifier(),
290                                              Profile::IMPLICIT_ACCESS),
291         url,
292         transition,
293         source,
294         timestamp);
295
296   // Wait until the AddPage() request has completed so we know the change has
297   // filtered down to the sync observers (don't need to wait for the
298   // verifier profile since it doesn't sync).
299   WaitForHistoryDBThread(index);
300 }
301
302 void DeleteUrlFromHistory(int index, const GURL& url) {
303   HistoryServiceFactory::GetForProfileWithoutCreating(
304       test()->GetProfile(index))->DeleteURL(url);
305   if (test()->use_verifier())
306     HistoryServiceFactory::GetForProfile(test()->verifier(),
307                                          Profile::IMPLICIT_ACCESS)->
308         DeleteURL(url);
309   WaitForHistoryDBThread(index);
310 }
311
312 void DeleteUrlsFromHistory(int index, const std::vector<GURL>& urls) {
313   HistoryServiceFactory::GetForProfileWithoutCreating(
314       test()->GetProfile(index))->DeleteURLsForTest(urls);
315   if (test()->use_verifier())
316     HistoryServiceFactory::GetForProfile(test()->verifier(),
317                                          Profile::IMPLICIT_ACCESS)->
318         DeleteURLsForTest(urls);
319   WaitForHistoryDBThread(index);
320 }
321
322 bool CheckURLRowVectorsAreEqual(const history::URLRows& left,
323                                 const history::URLRows& right) {
324   if (left.size() != right.size())
325     return false;
326   for (size_t i = 0; i < left.size(); ++i) {
327     // URLs could be out-of-order, so look for a matching URL in the second
328     // array.
329     bool found = false;
330     for (size_t j = 0; j < right.size(); ++j) {
331       if (left[i].url() == right[j].url()) {
332         if (CheckURLRowsAreEqual(left[i], right[j])) {
333           found = true;
334           break;
335         }
336       }
337     }
338     if (!found)
339       return false;
340   }
341   return true;
342 }
343
344 bool AreVisitsEqual(const history::VisitVector& visit1,
345                     const history::VisitVector& visit2) {
346   if (visit1.size() != visit2.size())
347     return false;
348   for (size_t i = 0; i < visit1.size(); ++i) {
349     if (visit1[i].transition != visit2[i].transition)
350       return false;
351     if (visit1[i].visit_time != visit2[i].visit_time)
352       return false;
353   }
354   return true;
355 }
356
357 bool AreVisitsUnique(const history::VisitVector& visits) {
358   base::Time t = base::Time::FromInternalValue(0);
359   for (size_t i = 0; i < visits.size(); ++i) {
360     if (t == visits[i].visit_time)
361       return false;
362     t = visits[i].visit_time;
363   }
364   return true;
365 }
366
367 bool CheckURLRowsAreEqual(
368     const history::URLRow& left, const history::URLRow& right) {
369   return (left.url() == right.url()) &&
370       (left.title() == right.title()) &&
371       (left.visit_count() == right.visit_count()) &&
372       (left.typed_count() == right.typed_count()) &&
373       (left.last_visit() == right.last_visit()) &&
374       (left.hidden() == right.hidden());
375 }
376
377 bool CheckAllProfilesHaveSameURLsAsVerifier() {
378   HistoryService* verifier_service =
379       HistoryServiceFactory::GetForProfile(test()->verifier(),
380                                            Profile::IMPLICIT_ACCESS);
381   history::URLRows verifier_urls =
382       GetTypedUrlsFromHistoryService(verifier_service);
383   for (int i = 0; i < test()->num_clients(); ++i) {
384     history::URLRows urls = GetTypedUrlsFromClient(i);
385     if (!CheckURLRowVectorsAreEqual(verifier_urls, urls))
386       return false;
387   }
388   return true;
389 }
390
391 namespace {
392
393 // Helper class used in the implementation of
394 // AwaitCheckAllProfilesHaveSameURLsAsVerifier.
395 class ProfilesHaveSameURLsChecker : public MultiClientStatusChangeChecker {
396  public:
397   ProfilesHaveSameURLsChecker();
398   virtual ~ProfilesHaveSameURLsChecker();
399
400   virtual bool IsExitConditionSatisfied() OVERRIDE;
401   virtual std::string GetDebugMessage() const OVERRIDE;
402 };
403
404 ProfilesHaveSameURLsChecker::ProfilesHaveSameURLsChecker()
405     : MultiClientStatusChangeChecker(
406         sync_datatype_helper::test()->GetSyncServices()) {}
407
408 ProfilesHaveSameURLsChecker::~ProfilesHaveSameURLsChecker() {}
409
410 bool ProfilesHaveSameURLsChecker::IsExitConditionSatisfied() {
411   return CheckAllProfilesHaveSameURLsAsVerifier();
412 }
413
414 std::string ProfilesHaveSameURLsChecker::GetDebugMessage() const {
415   return "Waiting for matching typed urls profiles";
416 }
417
418 }  //  namespace
419
420 bool AwaitCheckAllProfilesHaveSameURLsAsVerifier() {
421   ProfilesHaveSameURLsChecker checker;
422   checker.Wait();
423   return !checker.TimedOut();
424 }
425
426 }  // namespace typed_urls_helper