Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / sessions_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/sessions_helper.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/stl_util.h"
13 #include "base/test/test_timeouts.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sync/open_tabs_ui_delegate.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/sync/sessions/notification_service_sessions_router.h"
20 #include "chrome/browser/sync/sessions/sessions_sync_manager.h"
21 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
22 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
23 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
24 #include "chrome/browser/sync/test/integration/sync_test.h"
25 #include "chrome/browser/ui/singleton_tabs.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "content/public/test/test_utils.h"
28 #include "url/gurl.h"
29
30 using sync_datatype_helper::test;
31
32 namespace sessions_helper {
33
34 ScopedWindowMap::ScopedWindowMap() {
35 }
36
37 ScopedWindowMap::ScopedWindowMap(SessionWindowMap* windows) {
38   Reset(windows);
39 }
40
41 ScopedWindowMap::~ScopedWindowMap() {
42   STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end());
43 }
44
45 SessionWindowMap* ScopedWindowMap::GetMutable() {
46   return &windows_;
47 }
48
49 const SessionWindowMap* ScopedWindowMap::Get() const {
50   return &windows_;
51 }
52
53 void ScopedWindowMap::Reset(SessionWindowMap* windows) {
54   STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end());
55   windows_.clear();
56   std::swap(*windows, windows_);
57 }
58
59 bool GetLocalSession(int index, const browser_sync::SyncedSession** session) {
60   return ProfileSyncServiceFactory::GetInstance()->GetForProfile(
61       test()->GetProfile(index))->GetOpenTabsUIDelegate()->
62           GetLocalSession(session);
63 }
64
65 bool ModelAssociatorHasTabWithUrl(int index, const GURL& url) {
66   content::RunAllPendingInMessageLoop();
67   const browser_sync::SyncedSession* local_session;
68   if (!GetLocalSession(index, &local_session)) {
69     return false;
70   }
71
72   if (local_session->windows.size() == 0) {
73     DVLOG(1) << "Empty windows vector";
74     return false;
75   }
76
77   int nav_index;
78   sessions::SerializedNavigationEntry nav;
79   for (SessionWindowMap::const_iterator it =
80            local_session->windows.begin();
81        it != local_session->windows.end(); ++it) {
82     if (it->second->tabs.size() == 0) {
83       DVLOG(1) << "Empty tabs vector";
84       continue;
85     }
86     for (std::vector<SessionTab*>::const_iterator tab_it =
87              it->second->tabs.begin();
88          tab_it != it->second->tabs.end(); ++tab_it) {
89       if ((*tab_it)->navigations.size() == 0) {
90         DVLOG(1) << "Empty navigations vector";
91         continue;
92       }
93       nav_index = (*tab_it)->current_navigation_index;
94       nav = (*tab_it)->navigations[nav_index];
95       if (nav.virtual_url() == url) {
96         DVLOG(1) << "Found tab with url " << url.spec();
97         DVLOG(1) << "Timestamp is " << nav.timestamp().ToInternalValue();
98         if (nav.title().empty()) {
99           DVLOG(1) << "Title empty -- tab hasn't finished loading yet";
100           continue;
101         }
102         return true;
103       }
104     }
105   }
106   DVLOG(1) << "Could not find tab with url " << url.spec();
107   return false;
108 }
109
110 bool OpenTab(int index, const GURL& url) {
111   DVLOG(1) << "Opening tab: " << url.spec() << " using profile "
112            << index << ".";
113   chrome::ShowSingletonTab(test()->GetBrowser(index), url);
114   return WaitForTabsToLoad(index, std::vector<GURL>(1, url));
115 }
116
117 bool OpenMultipleTabs(int index, const std::vector<GURL>& urls) {
118   Browser* browser = test()->GetBrowser(index);
119   for (std::vector<GURL>::const_iterator it = urls.begin();
120        it != urls.end(); ++it) {
121     DVLOG(1) << "Opening tab: " << it->spec() << " using profile " << index
122              << ".";
123     chrome::ShowSingletonTab(browser, *it);
124   }
125   return WaitForTabsToLoad(index, urls);
126 }
127
128 namespace {
129
130 class TabEventHandler : public browser_sync::LocalSessionEventHandler {
131  public:
132   TabEventHandler() : weak_factory_(this) {
133     base::MessageLoop::current()->PostDelayedTask(
134         FROM_HERE,
135         base::Bind(&TabEventHandler::QuitLoop, weak_factory_.GetWeakPtr()),
136         TestTimeouts::action_max_timeout());
137   }
138
139   void OnLocalTabModified(
140       browser_sync::SyncedTabDelegate* modified_tab) override {
141     // Unwind to ensure SessionsSyncManager has processed the event.
142     base::MessageLoop::current()->PostTask(
143         FROM_HERE,
144         base::Bind(&TabEventHandler::QuitLoop, weak_factory_.GetWeakPtr()));
145   }
146
147   void OnFaviconPageUrlsUpdated(
148       const std::set<GURL>& updated_page_urls) override {
149     // Unwind to ensure SessionsSyncManager has processed the event.
150     base::MessageLoop::current()->PostTask(
151         FROM_HERE,
152         base::Bind(&TabEventHandler::QuitLoop, weak_factory_.GetWeakPtr()));
153   }
154
155  private:
156   void QuitLoop() {
157     base::MessageLoop::current()->Quit();
158   }
159
160   base::WeakPtrFactory<TabEventHandler> weak_factory_;
161 };
162
163 }  // namespace
164
165 bool WaitForTabsToLoad(int index, const std::vector<GURL>& urls) {
166   DVLOG(1) << "Waiting for session to propagate to associator.";
167   base::TimeTicks start_time = base::TimeTicks::Now();
168   base::TimeTicks end_time = start_time + TestTimeouts::action_max_timeout();
169   bool found;
170   for (std::vector<GURL>::const_iterator it = urls.begin();
171        it != urls.end(); ++it) {
172     found = false;
173     while (!found) {
174       found = ModelAssociatorHasTabWithUrl(index, *it);
175       if (base::TimeTicks::Now() >= end_time) {
176         LOG(ERROR) << "Failed to find all tabs after "
177                    << TestTimeouts::action_max_timeout().InSecondsF()
178                    << " seconds.";
179         return false;
180       }
181       if (!found) {
182         TabEventHandler handler;
183         browser_sync::NotificationServiceSessionsRouter router(
184             test()->GetProfile(index),
185             syncer::SyncableService::StartSyncFlare());
186         router.StartRoutingTo(&handler);
187         content::RunMessageLoop();
188       }
189     }
190   }
191   return true;
192 }
193
194 bool GetLocalWindows(int index, SessionWindowMap* local_windows) {
195   // The local session provided by GetLocalSession is owned, and has lifetime
196   // controlled, by the model associator, so we must make our own copy.
197   const browser_sync::SyncedSession* local_session;
198   if (!GetLocalSession(index, &local_session)) {
199     return false;
200   }
201   for (SessionWindowMap::const_iterator w = local_session->windows.begin();
202        w != local_session->windows.end(); ++w) {
203     const SessionWindow& window = *(w->second);
204     SessionWindow* new_window = new SessionWindow();
205     new_window->window_id.set_id(window.window_id.id());
206     for (size_t t = 0; t < window.tabs.size(); ++t) {
207       const SessionTab& tab = *window.tabs.at(t);
208       SessionTab* new_tab = new SessionTab();
209       new_tab->navigations.resize(tab.navigations.size());
210       std::copy(tab.navigations.begin(), tab.navigations.end(),
211                 new_tab->navigations.begin());
212       new_window->tabs.push_back(new_tab);
213     }
214     (*local_windows)[new_window->window_id.id()] = new_window;
215   }
216
217   return true;
218 }
219
220 bool OpenTabAndGetLocalWindows(int index,
221                                const GURL& url,
222                                SessionWindowMap* local_windows) {
223   if (!OpenTab(index, url)) {
224     return false;
225   }
226   return GetLocalWindows(index, local_windows);
227 }
228
229 bool CheckInitialState(int index) {
230   if (0 != GetNumWindows(index))
231     return false;
232   if (0 != GetNumForeignSessions(index))
233     return false;
234   return true;
235 }
236
237 int GetNumWindows(int index) {
238   const browser_sync::SyncedSession* local_session;
239   if (!GetLocalSession(index, &local_session)) {
240     return 0;
241   }
242   return local_session->windows.size();
243 }
244
245 int GetNumForeignSessions(int index) {
246   SyncedSessionVector sessions;
247   if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
248           test()->GetProfile(index))->
249           GetOpenTabsUIDelegate()->GetAllForeignSessions(
250               &sessions)) {
251     return 0;
252   }
253   return sessions.size();
254 }
255
256 bool GetSessionData(int index, SyncedSessionVector* sessions) {
257   if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
258           test()->GetProfile(index))->
259           GetOpenTabsUIDelegate()->GetAllForeignSessions(
260               sessions)) {
261     return false;
262   }
263   SortSyncedSessions(sessions);
264   return true;
265 }
266
267 bool CompareSyncedSessions(const browser_sync::SyncedSession* lhs,
268                            const browser_sync::SyncedSession* rhs) {
269   if (!lhs ||
270       !rhs ||
271       lhs->windows.size() < 1 ||
272       rhs->windows.size() < 1) {
273     // Catchall for uncomparable data.
274     return false;
275   }
276
277   return lhs->windows < rhs->windows;
278 }
279
280 void SortSyncedSessions(SyncedSessionVector* sessions) {
281   std::sort(sessions->begin(), sessions->end(),
282             CompareSyncedSessions);
283 }
284
285 bool NavigationEquals(const sessions::SerializedNavigationEntry& expected,
286                       const sessions::SerializedNavigationEntry& actual) {
287   if (expected.virtual_url() != actual.virtual_url()) {
288     LOG(ERROR) << "Expected url " << expected.virtual_url()
289                << ", actual " << actual.virtual_url();
290     return false;
291   }
292   if (expected.referrer_url() != actual.referrer_url()) {
293     LOG(ERROR) << "Expected referrer "
294                << expected.referrer_url()
295                << ", actual "
296                << actual.referrer_url();
297     return false;
298   }
299   if (expected.title() != actual.title()) {
300     LOG(ERROR) << "Expected title " << expected.title()
301                << ", actual " << actual.title();
302     return false;
303   }
304   if (expected.transition_type() != actual.transition_type()) {
305     LOG(ERROR) << "Expected transition "
306                << expected.transition_type()
307                << ", actual "
308                << actual.transition_type();
309     return false;
310   }
311   return true;
312 }
313
314 bool WindowsMatch(const SessionWindowMap& win1,
315                   const SessionWindowMap& win2) {
316   SessionTab* client0_tab;
317   SessionTab* client1_tab;
318   if (win1.size() != win2.size())
319     return false;
320   for (SessionWindowMap::const_iterator i = win1.begin();
321        i != win1.end(); ++i) {
322     SessionWindowMap::const_iterator j = win2.find(i->first);
323     if (j == win2.end())
324       return false;
325     if (i->second->tabs.size() != j->second->tabs.size())
326       return false;
327     for (size_t t = 0; t < i->second->tabs.size(); ++t) {
328       client0_tab = i->second->tabs[t];
329       client1_tab = j->second->tabs[t];
330       for (size_t n = 0; n < client0_tab->navigations.size(); ++n) {
331         if (!NavigationEquals(client0_tab->navigations[n],
332                               client1_tab->navigations[n])) {
333           return false;
334         }
335       }
336     }
337   }
338
339   return true;
340 }
341
342 bool CheckForeignSessionsAgainst(
343     int index,
344     const std::vector<ScopedWindowMap>& windows) {
345   SyncedSessionVector sessions;
346   if (!GetSessionData(index, &sessions))
347     return false;
348   if ((size_t)(test()->num_clients()-1) != sessions.size())
349     return false;
350
351   int window_index = 0;
352   for (size_t j = 0; j < sessions.size(); ++j, ++window_index) {
353     if (window_index == index)
354       window_index++;  // Skip self.
355     if (!WindowsMatch(sessions[j]->windows,
356                       *(windows[window_index].Get())))
357       return false;
358   }
359
360   return true;
361 }
362
363 namespace {
364
365 // Helper class used in the implementation of AwaitCheckForeignSessionsAgainst.
366 class CheckForeignSessionsChecker : public MultiClientStatusChangeChecker {
367  public:
368   CheckForeignSessionsChecker(int index,
369                               const std::vector<ScopedWindowMap>& windows);
370   ~CheckForeignSessionsChecker() override;
371
372   bool IsExitConditionSatisfied() override;
373   std::string GetDebugMessage() const override;
374
375  private:
376   int index_;
377   const std::vector<ScopedWindowMap>& windows_;
378 };
379
380 CheckForeignSessionsChecker::CheckForeignSessionsChecker(
381     int index, const std::vector<ScopedWindowMap>& windows)
382     : MultiClientStatusChangeChecker(
383         sync_datatype_helper::test()->GetSyncServices()),
384       index_(index),
385       windows_(windows) {}
386
387 CheckForeignSessionsChecker::~CheckForeignSessionsChecker() {}
388
389 bool CheckForeignSessionsChecker::IsExitConditionSatisfied() {
390   return CheckForeignSessionsAgainst(index_, windows_);
391 }
392
393 std::string CheckForeignSessionsChecker::GetDebugMessage() const {
394   return "Waiting for matching foreign sessions";
395 }
396
397 }  //  namespace
398
399 bool AwaitCheckForeignSessionsAgainst(
400     int index, const std::vector<ScopedWindowMap>& windows) {
401   CheckForeignSessionsChecker checker(index, windows);
402   checker.Wait();
403   return !checker.TimedOut();
404 }
405
406 void DeleteForeignSession(int index, std::string session_tag) {
407   ProfileSyncServiceFactory::GetInstance()->GetForProfile(
408       test()->GetProfile(index))->
409           GetOpenTabsUIDelegate()->DeleteForeignSession(session_tag);
410 }
411
412 }  // namespace sessions_helper