sessions_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/sessions_helper.h"
6
7#include <algorithm>
8
9#include "base/stl_util.h"
10#include "base/test/test_timeouts.h"
11#include "base/time.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/sessions/session_types_test_helper.h"
14#include "chrome/browser/sync/glue/session_model_associator.h"
15#include "chrome/browser/sync/profile_sync_service.h"
16#include "chrome/browser/sync/profile_sync_service_factory.h"
17#include "chrome/browser/sync/profile_sync_service_harness.h"
18#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
19#include "chrome/browser/sync/test/integration/sync_test.h"
20#include "chrome/browser/ui/singleton_tabs.h"
21#include "chrome/browser/ui/tab_contents/tab_contents.h"
22#include "chrome/test/base/ui_test_utils.h"
23#include "content/public/browser/browser_thread.h"
24#include "googleurl/src/gurl.h"
25
26using sync_datatype_helper::test;
27
28namespace sessions_helper {
29
30ScopedWindowMap::ScopedWindowMap() {
31}
32
33ScopedWindowMap::ScopedWindowMap(SessionWindowMap* windows) {
34  Reset(windows);
35}
36
37ScopedWindowMap::~ScopedWindowMap() {
38  STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end());
39}
40
41SessionWindowMap* ScopedWindowMap::GetMutable() {
42  return &windows_;
43}
44
45const SessionWindowMap* ScopedWindowMap::Get() const {
46  return &windows_;
47}
48
49void ScopedWindowMap::Reset(SessionWindowMap* windows) {
50  STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end());
51  windows_.clear();
52  std::swap(*windows, windows_);
53}
54
55bool GetLocalSession(int index, const browser_sync::SyncedSession** session) {
56  return ProfileSyncServiceFactory::GetInstance()->GetForProfile(
57      test()->GetProfile(index))->GetSessionModelAssociator()->GetLocalSession(
58          session);
59}
60
61bool ModelAssociatorHasTabWithUrl(int index, const GURL& url) {
62  content::RunAllPendingInMessageLoop();
63  const browser_sync::SyncedSession* local_session;
64  if (!GetLocalSession(index, &local_session)) {
65    return false;
66  }
67
68  if (local_session->windows.size() == 0) {
69    DVLOG(1) << "Empty windows vector";
70    return false;
71  }
72
73  int nav_index;
74  TabNavigation nav;
75  for (SessionWindowMap::const_iterator it =
76           local_session->windows.begin();
77       it != local_session->windows.end(); ++it) {
78    if (it->second->tabs.size() == 0) {
79      DVLOG(1) << "Empty tabs vector";
80      continue;
81    }
82    for (std::vector<SessionTab*>::const_iterator tab_it =
83             it->second->tabs.begin();
84         tab_it != it->second->tabs.end(); ++tab_it) {
85      if ((*tab_it)->navigations.size() == 0) {
86        DVLOG(1) << "Empty navigations vector";
87        continue;
88      }
89      nav_index = (*tab_it)->current_navigation_index;
90      nav = (*tab_it)->navigations[nav_index];
91      if (nav.virtual_url() == url) {
92        DVLOG(1) << "Found tab with url " << url.spec();
93        DVLOG(1) << "Timestamp is "
94                 << SessionTypesTestHelper::GetTimestamp(nav).ToInternalValue();
95        if (nav.title().empty()) {
96          DVLOG(1) << "Title empty -- tab hasn't finished loading yet";
97          continue;
98        }
99        return true;
100      }
101    }
102  }
103  DVLOG(1) << "Could not find tab with url " << url.spec();
104  return false;
105}
106
107bool OpenTab(int index, const GURL& url) {
108  DVLOG(1) << "Opening tab: " << url.spec() << " using profile "
109           << index << ".";
110  chrome::ShowSingletonTab(test()->GetBrowser(index), url);
111  return WaitForTabsToLoad(index, std::vector<GURL>(1, url));
112}
113
114bool OpenMultipleTabs(int index, const std::vector<GURL>& urls) {
115  Browser* browser = test()->GetBrowser(index);
116  for (std::vector<GURL>::const_iterator it = urls.begin();
117       it != urls.end(); ++it) {
118    DVLOG(1) << "Opening tab: " << it->spec() << " using profile " << index
119             << ".";
120    chrome::ShowSingletonTab(browser, *it);
121  }
122  return WaitForTabsToLoad(index, urls);
123}
124
125bool WaitForTabsToLoad(int index, const std::vector<GURL>& urls) {
126  DVLOG(1) << "Waiting for session to propagate to associator.";
127  base::TimeTicks start_time = base::TimeTicks::Now();
128  base::TimeTicks end_time = start_time + TestTimeouts::action_max_timeout();
129  bool found;
130  for (std::vector<GURL>::const_iterator it = urls.begin();
131       it != urls.end(); ++it) {
132    found = false;
133    while (!found) {
134      found = ModelAssociatorHasTabWithUrl(index, *it);
135      if (base::TimeTicks::Now() >= end_time) {
136        LOG(ERROR) << "Failed to find all tabs after "
137                   << TestTimeouts::action_max_timeout().InSecondsF()
138                   << " seconds.";
139        return false;
140      }
141      if (!found) {
142        ProfileSyncServiceFactory::GetInstance()->GetForProfile(
143            test()->GetProfile(index))->GetSessionModelAssociator()->
144            BlockUntilLocalChangeForTest(TestTimeouts::action_max_timeout());
145        content::RunMessageLoop();
146      }
147    }
148  }
149  return true;
150}
151
152bool GetLocalWindows(int index, SessionWindowMap* local_windows) {
153  // The local session provided by GetLocalSession is owned, and has lifetime
154  // controlled, by the model associator, so we must make our own copy.
155  const browser_sync::SyncedSession* local_session;
156  if (!GetLocalSession(index, &local_session)) {
157    return false;
158  }
159  for (SessionWindowMap::const_iterator w = local_session->windows.begin();
160       w != local_session->windows.end(); ++w) {
161    const SessionWindow& window = *(w->second);
162    SessionWindow* new_window = new SessionWindow();
163    new_window->window_id.set_id(window.window_id.id());
164    for (size_t t = 0; t < window.tabs.size(); ++t) {
165      const SessionTab& tab = *window.tabs.at(t);
166      SessionTab* new_tab = new SessionTab();
167      new_tab->navigations.resize(tab.navigations.size());
168      std::copy(tab.navigations.begin(), tab.navigations.end(),
169                new_tab->navigations.begin());
170      new_window->tabs.push_back(new_tab);
171    }
172    (*local_windows)[new_window->window_id.id()] = new_window;
173  }
174
175  return true;
176}
177
178bool OpenTabAndGetLocalWindows(int index,
179                               const GURL& url,
180                               SessionWindowMap* local_windows) {
181  if (!OpenTab(index, url)) {
182    return false;
183  }
184  return GetLocalWindows(index, local_windows);
185}
186
187bool CheckInitialState(int index) {
188  if (0 != GetNumWindows(index))
189    return false;
190  if (0 != GetNumForeignSessions(index))
191    return false;
192  return true;
193}
194
195int GetNumWindows(int index) {
196  const browser_sync::SyncedSession* local_session;
197  if (!GetLocalSession(index, &local_session)) {
198    return 0;
199  }
200  return local_session->windows.size();
201}
202
203int GetNumForeignSessions(int index) {
204  SyncedSessionVector sessions;
205  if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
206          test()->GetProfile(index))->
207          GetSessionModelAssociator()->GetAllForeignSessions(&sessions))
208    return 0;
209  return sessions.size();
210}
211
212bool GetSessionData(int index, SyncedSessionVector* sessions) {
213  if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
214          test()->GetProfile(index))->
215          GetSessionModelAssociator()->GetAllForeignSessions(sessions))
216    return false;
217  SortSyncedSessions(sessions);
218  return true;
219}
220
221bool CompareSyncedSessions(const browser_sync::SyncedSession* lhs,
222                           const browser_sync::SyncedSession* rhs) {
223  if (!lhs ||
224      !rhs ||
225      lhs->windows.size() < 1 ||
226      rhs->windows.size() < 1) {
227    // Catchall for uncomparable data.
228    return false;
229  }
230
231  return lhs->windows < rhs->windows;
232}
233
234void SortSyncedSessions(SyncedSessionVector* sessions) {
235  std::sort(sessions->begin(), sessions->end(),
236            CompareSyncedSessions);
237}
238
239bool NavigationEquals(const TabNavigation& expected,
240                      const TabNavigation& actual) {
241  if (expected.virtual_url() != actual.virtual_url()) {
242    LOG(ERROR) << "Expected url " << expected.virtual_url()
243               << ", actual " << actual.virtual_url();
244    return false;
245  }
246  if (SessionTypesTestHelper::GetReferrer(expected).url !=
247      SessionTypesTestHelper::GetReferrer(actual).url) {
248    LOG(ERROR) << "Expected referrer "
249               << SessionTypesTestHelper::GetReferrer(expected).url
250               << ", actual "
251               << SessionTypesTestHelper::GetReferrer(actual).url;
252    return false;
253  }
254  if (expected.title() != actual.title()) {
255    LOG(ERROR) << "Expected title " << expected.title()
256               << ", actual " << actual.title();
257    return false;
258  }
259  if (SessionTypesTestHelper::GetTransitionType(expected) !=
260      SessionTypesTestHelper::GetTransitionType(actual)) {
261    LOG(ERROR) << "Expected transition "
262               << SessionTypesTestHelper::GetTransitionType(expected)
263               << ", actual "
264               << SessionTypesTestHelper::GetTransitionType(actual);
265    return false;
266  }
267  return true;
268}
269
270bool WindowsMatch(const SessionWindowMap& win1,
271                  const SessionWindowMap& win2) {
272  SessionTab* client0_tab;
273  SessionTab* client1_tab;
274  if (win1.size() != win2.size())
275    return false;
276  for (SessionWindowMap::const_iterator i = win1.begin();
277       i != win1.end(); ++i) {
278    SessionWindowMap::const_iterator j = win2.find(i->first);
279    if (j == win2.end())
280      return false;
281    if (i->second->tabs.size() != j->second->tabs.size())
282      return false;
283    for (size_t t = 0; t < i->second->tabs.size(); ++t) {
284      client0_tab = i->second->tabs[t];
285      client1_tab = j->second->tabs[t];
286      for (size_t n = 0; n < client0_tab->navigations.size(); ++n) {
287        if (!NavigationEquals(client0_tab->navigations[n],
288                              client1_tab->navigations[n])) {
289          return false;
290        }
291      }
292    }
293  }
294
295  return true;
296}
297
298bool CheckForeignSessionsAgainst(
299    int index,
300    const std::vector<ScopedWindowMap>& windows) {
301  SyncedSessionVector sessions;
302  if (!GetSessionData(index, &sessions))
303    return false;
304  if ((size_t)(test()->num_clients()-1) != sessions.size())
305    return false;
306
307  int window_index = 0;
308  for (size_t j = 0; j < sessions.size(); ++j, ++window_index) {
309    if (window_index == index)
310      window_index++;  // Skip self.
311    if (!WindowsMatch(sessions[j]->windows,
312                      *(windows[window_index].Get())))
313      return false;
314  }
315
316  return true;
317}
318
319void DeleteForeignSession(int index, std::string session_tag) {
320  ProfileSyncServiceFactory::GetInstance()->GetForProfile(
321      test()->GetProfile(index))->
322      GetSessionModelAssociator()->DeleteForeignSession(session_tag);
323}
324
325}  // namespace sessions_helper
326