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