Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / sessions_helper.cc
blob2eb4e8bf76e06e64bb9e435b9aa1dec07fa168f3
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.
5 #include "chrome/browser/sync/test/integration/sessions_helper.h"
7 #include <algorithm>
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/glue/session_model_associator.h"
17 #include "chrome/browser/sync/open_tabs_ui_delegate.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/browser/sync/sessions2/notification_service_sessions_router.h"
21 #include "chrome/browser/sync/sessions2/sessions_sync_manager.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 "chrome/test/base/ui_test_utils.h"
28 #include "url/gurl.h"
30 using sync_datatype_helper::test;
32 namespace sessions_helper {
34 ScopedWindowMap::ScopedWindowMap() {
37 ScopedWindowMap::ScopedWindowMap(SessionWindowMap* windows) {
38 Reset(windows);
41 ScopedWindowMap::~ScopedWindowMap() {
42 STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end());
45 SessionWindowMap* ScopedWindowMap::GetMutable() {
46 return &windows_;
49 const SessionWindowMap* ScopedWindowMap::Get() const {
50 return &windows_;
53 void ScopedWindowMap::Reset(SessionWindowMap* windows) {
54 STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end());
55 windows_.clear();
56 std::swap(*windows, windows_);
59 bool GetLocalSession(int index, const browser_sync::SyncedSession** session) {
60 return ProfileSyncServiceFactory::GetInstance()->GetForProfile(
61 test()->GetProfile(index))->GetOpenTabsUIDelegate()->
62 GetLocalSession(session);
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;
72 if (local_session->windows.size() == 0) {
73 DVLOG(1) << "Empty windows vector";
74 return false;
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;
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;
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;
102 return true;
106 DVLOG(1) << "Could not find tab with url " << url.spec();
107 return false;
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));
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);
125 return WaitForTabsToLoad(index, urls);
128 namespace {
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());
139 virtual 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()));
147 virtual 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()));
155 private:
156 void QuitLoop() {
157 base::MessageLoop::current()->Quit();
160 base::WeakPtrFactory<TabEventHandler> weak_factory_;
163 } // namespace
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;
181 if (!found) {
182 if (!CommandLine::ForCurrentProcess()->HasSwitch(
183 switches::kEnableSyncSessionsV2)) {
184 ProfileSyncServiceFactory::GetForProfile(test()->GetProfile(index))->
185 GetSessionModelAssociatorDeprecated()->
186 BlockUntilLocalChangeForTest(TestTimeouts::action_max_timeout());
187 content::RunMessageLoop();
188 } else {
189 TabEventHandler handler;
190 browser_sync::NotificationServiceSessionsRouter router(
191 test()->GetProfile(index),
192 syncer::SyncableService::StartSyncFlare());
193 router.StartRoutingTo(&handler);
194 content::RunMessageLoop();
199 return true;
202 bool GetLocalWindows(int index, SessionWindowMap* local_windows) {
203 // The local session provided by GetLocalSession is owned, and has lifetime
204 // controlled, by the model associator, so we must make our own copy.
205 const browser_sync::SyncedSession* local_session;
206 if (!GetLocalSession(index, &local_session)) {
207 return false;
209 for (SessionWindowMap::const_iterator w = local_session->windows.begin();
210 w != local_session->windows.end(); ++w) {
211 const SessionWindow& window = *(w->second);
212 SessionWindow* new_window = new SessionWindow();
213 new_window->window_id.set_id(window.window_id.id());
214 for (size_t t = 0; t < window.tabs.size(); ++t) {
215 const SessionTab& tab = *window.tabs.at(t);
216 SessionTab* new_tab = new SessionTab();
217 new_tab->navigations.resize(tab.navigations.size());
218 std::copy(tab.navigations.begin(), tab.navigations.end(),
219 new_tab->navigations.begin());
220 new_window->tabs.push_back(new_tab);
222 (*local_windows)[new_window->window_id.id()] = new_window;
225 return true;
228 bool OpenTabAndGetLocalWindows(int index,
229 const GURL& url,
230 SessionWindowMap* local_windows) {
231 if (!OpenTab(index, url)) {
232 return false;
234 return GetLocalWindows(index, local_windows);
237 bool CheckInitialState(int index) {
238 if (0 != GetNumWindows(index))
239 return false;
240 if (0 != GetNumForeignSessions(index))
241 return false;
242 return true;
245 int GetNumWindows(int index) {
246 const browser_sync::SyncedSession* local_session;
247 if (!GetLocalSession(index, &local_session)) {
248 return 0;
250 return local_session->windows.size();
253 int GetNumForeignSessions(int index) {
254 SyncedSessionVector sessions;
255 if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
256 test()->GetProfile(index))->
257 GetOpenTabsUIDelegate()->GetAllForeignSessions(
258 &sessions)) {
259 return 0;
261 return sessions.size();
264 bool GetSessionData(int index, SyncedSessionVector* sessions) {
265 if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
266 test()->GetProfile(index))->
267 GetOpenTabsUIDelegate()->GetAllForeignSessions(
268 sessions)) {
269 return false;
271 SortSyncedSessions(sessions);
272 return true;
275 bool CompareSyncedSessions(const browser_sync::SyncedSession* lhs,
276 const browser_sync::SyncedSession* rhs) {
277 if (!lhs ||
278 !rhs ||
279 lhs->windows.size() < 1 ||
280 rhs->windows.size() < 1) {
281 // Catchall for uncomparable data.
282 return false;
285 return lhs->windows < rhs->windows;
288 void SortSyncedSessions(SyncedSessionVector* sessions) {
289 std::sort(sessions->begin(), sessions->end(),
290 CompareSyncedSessions);
293 bool NavigationEquals(const sessions::SerializedNavigationEntry& expected,
294 const sessions::SerializedNavigationEntry& actual) {
295 if (expected.virtual_url() != actual.virtual_url()) {
296 LOG(ERROR) << "Expected url " << expected.virtual_url()
297 << ", actual " << actual.virtual_url();
298 return false;
300 if (expected.referrer().url != actual.referrer().url) {
301 LOG(ERROR) << "Expected referrer "
302 << expected.referrer().url
303 << ", actual "
304 << actual.referrer().url;
305 return false;
307 if (expected.title() != actual.title()) {
308 LOG(ERROR) << "Expected title " << expected.title()
309 << ", actual " << actual.title();
310 return false;
312 if (expected.transition_type() != actual.transition_type()) {
313 LOG(ERROR) << "Expected transition "
314 << expected.transition_type()
315 << ", actual "
316 << actual.transition_type();
317 return false;
319 return true;
322 bool WindowsMatch(const SessionWindowMap& win1,
323 const SessionWindowMap& win2) {
324 SessionTab* client0_tab;
325 SessionTab* client1_tab;
326 if (win1.size() != win2.size())
327 return false;
328 for (SessionWindowMap::const_iterator i = win1.begin();
329 i != win1.end(); ++i) {
330 SessionWindowMap::const_iterator j = win2.find(i->first);
331 if (j == win2.end())
332 return false;
333 if (i->second->tabs.size() != j->second->tabs.size())
334 return false;
335 for (size_t t = 0; t < i->second->tabs.size(); ++t) {
336 client0_tab = i->second->tabs[t];
337 client1_tab = j->second->tabs[t];
338 for (size_t n = 0; n < client0_tab->navigations.size(); ++n) {
339 if (!NavigationEquals(client0_tab->navigations[n],
340 client1_tab->navigations[n])) {
341 return false;
347 return true;
350 bool CheckForeignSessionsAgainst(
351 int index,
352 const std::vector<ScopedWindowMap>& windows) {
353 SyncedSessionVector sessions;
354 if (!GetSessionData(index, &sessions))
355 return false;
356 if ((size_t)(test()->num_clients()-1) != sessions.size())
357 return false;
359 int window_index = 0;
360 for (size_t j = 0; j < sessions.size(); ++j, ++window_index) {
361 if (window_index == index)
362 window_index++; // Skip self.
363 if (!WindowsMatch(sessions[j]->windows,
364 *(windows[window_index].Get())))
365 return false;
368 return true;
371 void DeleteForeignSession(int index, std::string session_tag) {
372 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
373 test()->GetProfile(index))->
374 GetOpenTabsUIDelegate()->DeleteForeignSession(session_tag);
377 } // namespace sessions_helper