Index: chrome/test/live_sync/live_sessions_sync_test.h |
=================================================================== |
--- chrome/test/live_sync/live_sessions_sync_test.h (revision 0) |
+++ chrome/test/live_sync/live_sessions_sync_test.h (revision 0) |
@@ -0,0 +1,418 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CHROME_TEST_LIVE_SYNC_LIVE_SESSIONS_SYNC_TEST_H_ |
+#define CHROME_TEST_LIVE_SYNC_LIVE_SESSIONS_SYNC_TEST_H_ |
+#pragma once |
+ |
+#include <algorithm> |
+#include <vector> |
+ |
+#include "base/compiler_specific.h" |
+#include "base/scoped_vector.h" |
+#include "base/ref_counted.h" |
+#include "base/waitable_event.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/browser_window.h" |
+#include "chrome/browser/profile.h" |
+#include "chrome/browser/renderer_host/render_view_host_delegate.h" |
+#include "chrome/browser/sessions/base_session_service.h" |
+#include "chrome/browser/sessions/session_service_test_helper.h" |
+#include "chrome/browser/tab_contents/tab_contents.h" |
+#include "chrome/test/live_sync/live_sync_test.h" |
+#include "chrome/test/ui_test_utils.h" |
+#include "googleurl/src/gurl.h" |
+#include "webkit/glue/window_open_disposition.h" |
+ |
+// Helper for accessing session service internals. |
+class TestSessionService |
+ : public SessionServiceTestHelper, |
+ public base::RefCountedThreadSafe<TestSessionService> { |
+ public: |
+ TestSessionService() |
+ : SessionServiceTestHelper(), |
+ done_saving_(false, false), |
+ got_windows_(false, false), |
+ profile_(NULL), |
+ window_bounds_(0, 1, 2, 3) {} |
+ TestSessionService(SessionService * service, |
+ Profile* profile) |
+ : SessionServiceTestHelper(service), |
+ done_saving_(false, false), |
+ got_windows_(false, false), |
+ profile_(profile), |
+ window_bounds_(0, 1, 2, 3) {} |
+ |
+ void SetUp() { |
+ ASSERT_TRUE(service()) << "SetUp() called without setting SessionService"; |
+ ASSERT_TRUE(profile_); |
+ service()->SetWindowType(window_id_, Browser::TYPE_NORMAL); |
+ service()->SetWindowBounds(window_id_, window_bounds_, false); |
+ } |
+ |
+ // Trigger saving the current session commands to file. |
+ void Save() { |
+ service()->Save(); |
+ } |
+ |
+ // Synchronously reads the contents of the current session. |
+ std::vector<SessionWindow*>* ReadWindows() { |
+ // The session backend will post the callback as a task to whatever thread |
+ // called it. In our case, we don't want the main test thread to have tasks |
+ // posted to, so we perform the actual call to session service from the same |
+ // thread the work will be done on (backend_thread aka file thread). As a |
+ // result, it will directly call back, instead of posting a task, and we can |
+ // block on that callback. |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, |
+ FROM_HERE, |
+ NewRunnableMethod(this, &TestSessionService::DoReadWindows)); |
+ |
+ // Wait for callback to happen. |
+ got_windows_.Wait(); |
+ |
+ // By the time we reach here we've received the windows, so return them. |
+ return windows_; |
+ } |
+ |
+ // Makes the actual call to session service. |
+ // Lives on the file thread. |
+ void DoReadWindows() { |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
+ LOG(ERROR) << "DoReadWindows called from wrong thread!"; |
+ windows_ = NULL; |
+ got_windows_.Signal(); |
+ return; |
+ } |
+ SessionService::SessionCallback* callback = |
+ NewCallback(this, &TestSessionService::OnGotSession); |
+ service()->GetCurrentSession(&consumer_, callback); |
+ } |
+ |
+ // Internal method used in the callback to obtain the current session. |
+ // Lives on and called from backend thread (file_thread). |
+ // We don't own windows so need to make a deep copy. |
+ void OnGotSession(int handle, std::vector<SessionWindow*>* windows) { |
+ // Hacky. We need to make a deep copy of the session windows. One way to do |
+ // this is to use the session model associators functionality to create |
+ // foreign sessions, which themselves wrap a SessionWindow vector. We just |
+ // need to make sure to destroy all the foreign sessions we created when |
+ // we're done. That's what the foreign_sessions_ ScopedVector is for. |
+ sync_pb::SessionSpecifics session; |
+ profile_->GetProfileSyncService()-> |
+ GetSessionModelAssociator()-> |
+ FillSpecificsFromSessions(windows, &session); |
+ |
+ std::vector<ForeignSession*> foreign_sessions; |
+ profile_->GetProfileSyncService()-> |
+ GetSessionModelAssociator()-> |
+ AppendForeignSessionFromSpecifics(&session, &foreign_sessions); |
+ ASSERT_EQ(foreign_sessions.size(), 1U); |
+ foreign_sessions_.push_back(foreign_sessions[0]); |
+ windows_ = &foreign_sessions[0]->windows; |
+ got_windows_.Signal(); |
+ } |
+ |
+ private: |
+ ~TestSessionService() { |
+ ReleaseService(); // We don't own this, so don't destroy it. |
+ } |
+ |
+ friend class base::RefCountedThreadSafe<TestSessionService>; |
+ |
+ // Current session buffer. |
+ std::vector<SessionWindow*>* windows_; |
+ |
+ // List of all foreign sessions we created in ReadWindows. We delete them all |
+ // at destruction time so that complex tests can keep comparing against old |
+ // SessionWindow data. Note that since we're constantly creating new foreign |
+ // sessions, we don't have to worry about duplicates. |
+ ScopedVector<ForeignSession> foreign_sessions_; |
+ |
+ // Barrier for saving session. |
+ base::WaitableEvent done_saving_; |
+ |
+ // Barrier for getting current windows in ReadWindows. |
+ base::WaitableEvent got_windows_; |
+ |
+ // Consumer used to obtain the current session. |
+ CancelableRequestConsumer consumer_; |
+ |
+ // Sync profile associated with this session service. |
+ Profile* profile_; |
+ |
+ SessionID window_id_; |
+ const gfx::Rect window_bounds_; |
+}; |
+ |
+class LiveSessionsSyncTest : public LiveSyncTest { |
+ public: |
+ explicit LiveSessionsSyncTest(TestType test_type) |
+ : LiveSyncTest(test_type), |
+ done_closing_(false, false) {} |
+ virtual ~LiveSessionsSyncTest() {} |
+ |
+ // Used to access the session service associated with a specific sync profile. |
+ SessionService* GetSessionService(int index) { |
+ return GetProfile(index)->GetSessionService(); |
+ } |
+ |
+ // Used to access the session service test helper associated with a specific |
+ // sync profile. |
+ TestSessionService* GetHelper(int index) { |
+ return test_session_services_[index]->get(); |
+ } |
+ |
+ // Used to access the browser associated with a specific sync profile. |
+ Browser* GetBrowser(int index) { |
+ return browsers_[index]; |
+ } |
+ |
+ // Sets up the TestSessionService helper and the new browser windows. |
+ bool SetupClients() { |
+ if (!LiveSyncTest::SetupClients()) { |
+ return false; |
+ } |
+ |
+ // Go through and make the TestSessionServices and Browsers. |
+ for (int i = 0; i < num_clients(); ++i) { |
+ scoped_refptr<TestSessionService>* new_tester = |
+ new scoped_refptr<TestSessionService>; |
+ *new_tester = new TestSessionService( |
+ GetSessionService(i), GetProfile(i)); |
+ test_session_services_.push_back(new_tester); |
+ GetHelper(i)->SetUp(); |
+ |
+ browsers_.push_back(Browser::Create(GetProfile(i))); |
+ } |
+ |
+ return true; |
+ } |
+ |
+ // Open a single tab and return the TabContents. TabContents must be checked |
+ // to ensure the tab opened successsfully. |
+ TabContents* OpenTab(int index, GURL url) WARN_UNUSED_RESULT { |
+ TabContents* tab = GetBrowser(index)-> |
+ AddSelectedTabWithURL(url, PageTransition::START_PAGE); |
+ |
+ // Wait for the page to finish loading. |
+ ui_test_utils::WaitForNavigation( |
+ &GetBrowser(index)->GetSelectedTabContents()->controller()); |
+ |
+ return tab; |
+ } |
+ |
+ // Creates and verifies the creation of a new window with one tab displaying |
+ // the specified GURL. |
+ // Returns: the SessionWindow associated with the new window. |
+ std::vector<SessionWindow*>* InitializeNewWindowWithTab(int index, GURL url) |
+ WARN_UNUSED_RESULT { |
+ if (!OpenTab(index, url)) { |
+ return NULL; |
+ } |
+ GetHelper(index)->Save(); |
+ std::vector<SessionWindow*>* windows = GetHelper(index)->ReadWindows(); |
+ if (windows->size() != 1) { |
+ LOG(ERROR) << "InitializeNewWindowWithTab called with open windows!"; |
+ return NULL; |
+ } |
+ if (1U != (*windows)[0]->tabs.size()) |
+ return NULL; |
+ SortSessionWindows(windows); |
+ return windows; |
+ } |
+ |
+ // Checks that window count and foreign session count are 0. |
+ bool CheckInitialState(int index) WARN_UNUSED_RESULT { |
+ if (0 != GetNumWindows(index)) |
+ return false; |
+ if (0 != GetNumForeignSessions(index)) |
+ return false; |
+ return true; |
+ } |
+ |
+ // Returns number of open windows for a profile. |
+ int GetNumWindows(int index) { |
+ // We don't own windows. |
+ std::vector<SessionWindow*>* windows = GetHelper(index)->ReadWindows(); |
+ return windows->size(); |
+ } |
+ |
+ // Returns number of foreign sessions for a profile. |
+ int GetNumForeignSessions(int index) { |
+ ScopedVector<ForeignSession> sessions; |
+ if (!GetProfile(index)->GetProfileSyncService()-> |
+ GetSessionModelAssociator()->GetSessionData(&sessions.get())) |
+ return 0; |
+ return sessions.size(); |
+ } |
+ |
+ // Fills the sessions vector with the model associator's foreign session data. |
+ // Caller owns sessions. |
+ bool GetSessionData(int index, std::vector<ForeignSession*>* sessions) |
+ WARN_UNUSED_RESULT { |
+ if (!GetProfile(index)->GetProfileSyncService()-> |
+ GetSessionModelAssociator()->GetSessionData(sessions)) |
+ return false; |
+ SortForeignSessions(sessions); |
+ return true; |
+ } |
+ |
+ // Compare session windows based on their first tab's url. |
+ // Returns true if the virtual url of the lhs is < the rhs. |
+ static bool CompareSessionWindows(SessionWindow* lhs, SessionWindow* rhs) { |
+ if (!lhs || |
+ !rhs || |
+ lhs->tabs.size() < 1 || |
+ rhs->tabs.size() < 1 || |
+ lhs->tabs[0]->navigations.size() < 1 || |
+ rhs->tabs[0]->navigations.size() < 1) { |
+ // Catchall for uncomparable data. |
+ return false; |
+ } |
+ |
+ return lhs->tabs[0]->navigations[0].virtual_url() < |
+ rhs->tabs[0]->navigations[0].virtual_url(); |
+ } |
+ |
+ // Sort session windows using our custom comparator (first tab url |
+ // comparison). |
+ void SortSessionWindows(std::vector<SessionWindow*>* windows) { |
+ std::sort(windows->begin(), windows->end(), |
+ LiveSessionsSyncTest::CompareSessionWindows); |
+ } |
+ |
+ // Compares a foreign session based on the first session window. |
+ // Returns true based on the comparison of the session windows. |
+ static bool CompareForeignSessions(ForeignSession* lhs, ForeignSession* rhs) { |
+ if (!lhs || |
+ !rhs || |
+ lhs->windows.size() < 1 || |
+ rhs->windows.size() < 1) { |
+ // Catchall for uncomparable data. |
+ return false; |
+ } |
+ |
+ return CompareSessionWindows(lhs->windows[0], rhs->windows[0]); |
+ } |
+ |
+ // Sort a foreign session vector using our custom foreign session comparator. |
+ void SortForeignSessions(std::vector<ForeignSession*>* sessions) { |
+ std::sort(sessions->begin(), sessions->end(), |
+ LiveSessionsSyncTest::CompareForeignSessions); |
+ } |
+ |
+ // Verifies that two SessionWindows match. |
+ // Returns: |
+ // - true if all the following match: |
+ // 1. number of SessionWindows per vector, |
+ // 2. number of tabs per SessionWindow, |
+ // 3. number of tab navigations per nab, |
+ // 4. actual tab navigations |
+ // - false otherwise. |
+ bool WindowsMatch(const std::vector<SessionWindow*> &win1, |
+ const std::vector<SessionWindow*> &win2) WARN_UNUSED_RESULT { |
+ SessionTab* client0_tab; |
+ SessionTab* client1_tab; |
+ if (win1.size() != win2.size()) |
+ return false; |
+ for (size_t i = 0; i < win1.size(); ++i) { |
+ if (win1[i]->tabs.size() != win2[i]->tabs.size()) |
+ return false; |
+ for (size_t j = 0; j < win1[i]->tabs.size(); ++j) { |
+ client0_tab = win1[i]->tabs[j]; |
+ client1_tab = win2[i]->tabs[j]; |
+ for (size_t k = 0; k < client0_tab->navigations.size(); ++k) { |
+ GetHelper(0)->AssertNavigationEquals(client0_tab->navigations[k], |
+ client1_tab->navigations[k]); |
+ } |
+ } |
+ } |
+ |
+ return true; |
+ } |
+ |
+ // Retrieves the foreign sessions for a particular profile and compares them |
+ // with a reference SessionWindow list. |
+ // Returns true if the session windows of the foreign session matches the |
+ // reference. |
+ bool CheckForeignSessionsAgainst(int index, |
+ const std::vector<std::vector<SessionWindow*>* >& windows) |
+ WARN_UNUSED_RESULT { |
+ ScopedVector<ForeignSession> sessions; |
+ if (!GetSessionData(index, &sessions.get())) |
+ return false; |
+ if ((size_t)(num_clients()-1) != sessions.size()) |
+ return false; |
+ |
+ int window_index = 0; |
+ for (size_t j = 0; j < sessions->size(); ++j, ++window_index) { |
+ if (window_index == index) |
+ window_index++; // Skip self. |
+ if (!WindowsMatch(sessions[j]->windows, *windows[window_index])) |
+ return false; |
+ } |
+ |
+ return true; |
+ } |
+ |
+ protected: |
+ // Clean up our mess. |
+ virtual void CleanUpOnMainThread() { |
+ // Close all browsers. We need to do this now, as opposed to letting the |
+ // test framework handle it, because we created our own browser for each |
+ // sync profile. |
+ BrowserList::CloseAllBrowsers(); |
+ ui_test_utils::RunAllPendingInMessageLoop(); |
+ |
+ // All browsers should be closed at this point, else when the framework |
+ // calls QuitBrowsers() we could see memory corruption. |
+ ASSERT_EQ(0U, BrowserList::size()); |
+ |
+ LiveSyncTest::CleanUpOnMainThread(); |
+ } |
+ |
+ // Vector of our TestSessionService helpers. |
+ ScopedVector<scoped_refptr<TestSessionService> > test_session_services_; |
+ |
+ // Vector of our browsers for each profile. |
+ std::vector<Browser*> browsers_; |
+ |
+ // Barrier for closing the browsers we create in UI thread. |
+ base::WaitableEvent done_closing_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LiveSessionsSyncTest); |
+}; |
+ |
+class SingleClientLiveSessionsSyncTest : public LiveSessionsSyncTest { |
+ public: |
+ SingleClientLiveSessionsSyncTest() |
+ : LiveSessionsSyncTest(SINGLE_CLIENT) {} |
+ virtual ~SingleClientLiveSessionsSyncTest() {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(SingleClientLiveSessionsSyncTest); |
+}; |
+ |
+class TwoClientLiveSessionsSyncTest : public LiveSessionsSyncTest { |
+ public: |
+ TwoClientLiveSessionsSyncTest() : LiveSessionsSyncTest(TWO_CLIENT) {} |
+ virtual ~TwoClientLiveSessionsSyncTest() {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(TwoClientLiveSessionsSyncTest); |
+}; |
+ |
+class MultipleClientLiveSessionsSyncTest : public LiveSessionsSyncTest { |
+ public: |
+ MultipleClientLiveSessionsSyncTest() |
+ : LiveSessionsSyncTest(MULTIPLE_CLIENT) {} |
+ virtual ~MultipleClientLiveSessionsSyncTest() {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(MultipleClientLiveSessionsSyncTest); |
+}; |
+ |
+#endif // CHROME_TEST_LIVE_SYNC_LIVE_SESSIONS_SYNC_TEST_H_ |
+ |
Property changes on: chrome/test/live_sync/live_sessions_sync_test.h |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |