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"
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"
30 using sync_datatype_helper::test
;
32 namespace sessions_helper
{
34 ScopedWindowMap::ScopedWindowMap() {
37 ScopedWindowMap::ScopedWindowMap(SessionWindowMap
* windows
) {
41 ScopedWindowMap::~ScopedWindowMap() {
42 STLDeleteContainerPairSecondPointers(windows_
.begin(), windows_
.end());
45 SessionWindowMap
* ScopedWindowMap::GetMutable() {
49 const SessionWindowMap
* ScopedWindowMap::Get() const {
53 void ScopedWindowMap::Reset(SessionWindowMap
* windows
) {
54 STLDeleteContainerPairSecondPointers(windows_
.begin(), windows_
.end());
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
)) {
72 if (local_session
->windows
.size() == 0) {
73 DVLOG(1) << "Empty windows vector";
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";
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";
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";
106 DVLOG(1) << "Could not find tab with url " << url
.spec();
110 bool OpenTab(int index
, const GURL
& url
) {
111 DVLOG(1) << "Opening tab: " << url
.spec() << " using profile "
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
123 chrome::ShowSingletonTab(browser
, *it
);
125 return WaitForTabsToLoad(index
, urls
);
130 class TabEventHandler
: public browser_sync::LocalSessionEventHandler
{
132 TabEventHandler() : weak_factory_(this) {
133 base::MessageLoop::current()->PostDelayedTask(
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(
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(
152 base::Bind(&TabEventHandler::QuitLoop
, weak_factory_
.GetWeakPtr()));
157 base::MessageLoop::current()->Quit();
160 base::WeakPtrFactory
<TabEventHandler
> weak_factory_
;
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();
170 for (std::vector
<GURL
>::const_iterator it
= urls
.begin();
171 it
!= urls
.end(); ++it
) {
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()
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();
189 TabEventHandler handler
;
190 browser_sync::NotificationServiceSessionsRouter
router(
191 test()->GetProfile(index
),
192 syncer::SyncableService::StartSyncFlare());
193 router
.StartRoutingTo(&handler
);
194 content::RunMessageLoop();
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
)) {
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
;
228 bool OpenTabAndGetLocalWindows(int index
,
230 SessionWindowMap
* local_windows
) {
231 if (!OpenTab(index
, url
)) {
234 return GetLocalWindows(index
, local_windows
);
237 bool CheckInitialState(int index
) {
238 if (0 != GetNumWindows(index
))
240 if (0 != GetNumForeignSessions(index
))
245 int GetNumWindows(int index
) {
246 const browser_sync::SyncedSession
* local_session
;
247 if (!GetLocalSession(index
, &local_session
)) {
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(
261 return sessions
.size();
264 bool GetSessionData(int index
, SyncedSessionVector
* sessions
) {
265 if (!ProfileSyncServiceFactory::GetInstance()->GetForProfile(
266 test()->GetProfile(index
))->
267 GetOpenTabsUIDelegate()->GetAllForeignSessions(
271 SortSyncedSessions(sessions
);
275 bool CompareSyncedSessions(const browser_sync::SyncedSession
* lhs
,
276 const browser_sync::SyncedSession
* rhs
) {
279 lhs
->windows
.size() < 1 ||
280 rhs
->windows
.size() < 1) {
281 // Catchall for uncomparable data.
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();
300 if (expected
.referrer().url
!= actual
.referrer().url
) {
301 LOG(ERROR
) << "Expected referrer "
302 << expected
.referrer().url
304 << actual
.referrer().url
;
307 if (expected
.title() != actual
.title()) {
308 LOG(ERROR
) << "Expected title " << expected
.title()
309 << ", actual " << actual
.title();
312 if (expected
.transition_type() != actual
.transition_type()) {
313 LOG(ERROR
) << "Expected transition "
314 << expected
.transition_type()
316 << actual
.transition_type();
322 bool WindowsMatch(const SessionWindowMap
& win1
,
323 const SessionWindowMap
& win2
) {
324 SessionTab
* client0_tab
;
325 SessionTab
* client1_tab
;
326 if (win1
.size() != win2
.size())
328 for (SessionWindowMap::const_iterator i
= win1
.begin();
329 i
!= win1
.end(); ++i
) {
330 SessionWindowMap::const_iterator j
= win2
.find(i
->first
);
333 if (i
->second
->tabs
.size() != j
->second
->tabs
.size())
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
])) {
350 bool CheckForeignSessionsAgainst(
352 const std::vector
<ScopedWindowMap
>& windows
) {
353 SyncedSessionVector sessions
;
354 if (!GetSessionData(index
, &sessions
))
356 if ((size_t)(test()->num_clients()-1) != sessions
.size())
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())))
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