Upstream version 7.36.149.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/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
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   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.
155 void 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
172 history::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
182 bool 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
193 history::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
204 void 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
213 static base::Time* timestamp = NULL;
214
215 }  // namespace
216
217 namespace typed_urls_helper {
218
219 history::URLRows GetTypedUrlsFromClient(int index) {
220   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
221       test()->GetProfile(index));
222   return GetTypedUrlsFromHistoryService(service);
223 }
224
225 bool 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
231 history::VisitVector GetVisitsFromClient(int index, history::URLID id) {
232   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
233       test()->GetProfile(index));
234   return GetVisitsFromHistoryService(service, id);
235 }
236
237 void RemoveVisitsFromClient(int index, const history::VisitVector& visits) {
238   HistoryService* service = HistoryServiceFactory::GetForProfileWithoutCreating(
239       test()->GetProfile(index));
240   RemoveVisitsFromHistoryService(service, visits);
241 }
242
243 base::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
255 void AddUrlToHistory(int index, const GURL& url) {
256   AddUrlToHistoryWithTransition(index, url, content::PAGE_TRANSITION_TYPED,
257                                 history::SOURCE_BROWSED);
258 }
259 void 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 }
266 void 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
292 void 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
302 void 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
312 bool 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
334 bool 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
347 bool 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
357 bool 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
367 bool 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
381 namespace {
382
383 // Helper class used in the implementation of
384 // AwaitCheckAllProfilesHaveSameURLsAsVerifier.
385 class 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
394 ProfilesHaveSameURLsChecker::ProfilesHaveSameURLsChecker()
395     : MultiClientStatusChangeChecker(
396         sync_datatype_helper::test()->GetSyncServices()) {}
397
398 ProfilesHaveSameURLsChecker::~ProfilesHaveSameURLsChecker() {}
399
400 bool ProfilesHaveSameURLsChecker::IsExitConditionSatisfied() {
401   return CheckAllProfilesHaveSameURLsAsVerifier();
402 }
403
404 std::string ProfilesHaveSameURLsChecker::GetDebugMessage() const {
405   return "Waiting for matching typed urls profiles";
406 }
407
408 }  //  namespace
409
410 bool AwaitCheckAllProfilesHaveSameURLsAsVerifier() {
411   ProfilesHaveSameURLsChecker checker;
412   checker.Wait();
413   return !checker.TimedOut();
414 }
415
416 }  // namespace typed_urls_helper