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/test/integration/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 23 using sync_datatype_helper::test; 24 25 namespace sessions_helper { 26 27 ScopedWindowMap::ScopedWindowMap() { 28 } 29 30 ScopedWindowMap::ScopedWindowMap(SessionWindowMap* windows) { 31 Reset(windows); 32 } 33 34 ScopedWindowMap::~ScopedWindowMap() { 35 STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end()); 36 } 37 38 SessionWindowMap* ScopedWindowMap::GetMutable() { 39 return &windows_; 40 } 41 42 const SessionWindowMap* ScopedWindowMap::Get() const { 43 return &windows_; 44 } 45 46 void ScopedWindowMap::Reset(SessionWindowMap* windows) { 47 STLDeleteContainerPairSecondPointers(windows_.begin(), windows_.end()); 48 windows_.clear(); 49 std::swap(*windows, windows_); 50 } 51 52 bool GetLocalSession(int index, const browser_sync::SyncedSession** session) { 53 return ProfileSyncServiceFactory::GetInstance()->GetForProfile( 54 test()->GetProfile(index))->GetSessionModelAssociatorDeprecated()-> 55 GetLocalSession(session); 56 } 57 58 bool 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 103 bool 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 110 bool 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 121 bool 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 148 bool 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 174 bool 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 183 bool CheckInitialState(int index) { 184 if (0 != GetNumWindows(index)) 185 return false; 186 if (0 != GetNumForeignSessions(index)) 187 return false; 188 return true; 189 } 190 191 int 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 199 int 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 210 bool 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 221 bool 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 234 void SortSyncedSessions(SyncedSessionVector* sessions) { 235 std::sort(sessions->begin(), sessions->end(), 236 CompareSyncedSessions); 237 } 238 239 bool 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 268 bool 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 296 bool 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 317 void 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