summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-04 14:41:38 +0000
committerzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-04 14:41:38 +0000
commit52af9bc3801fac7b1b258861716c807790e4e42f (patch)
tree0997e75bd774e2873e7a05bce62c5a52758a0ef2
parentc4855a524f0c6e07aeb451c7be28f661e2ca11b0 (diff)
downloadchromium_src-52af9bc3801fac7b1b258861716c807790e4e42f.zip
chromium_src-52af9bc3801fac7b1b258861716c807790e4e42f.tar.gz
chromium_src-52af9bc3801fac7b1b258861716c807790e4e42f.tar.bz2
Session sync integration tests. Left out many client for now, since even
without doing anything in the test it was timing out. BUG=30519 TEST=self Review URL: http://codereview.chromium.org/4158009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65051 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/dom_ui/foreign_session_handler.cc2
-rw-r--r--chrome/browser/sessions/session_service.h2
-rw-r--r--chrome/browser/sessions/session_service_test_helper.h1
-rw-r--r--chrome/browser/sessions/session_types.cc2
-rw-r--r--chrome/browser/sessions/session_types.h2
-rw-r--r--chrome/browser/sync/glue/session_model_associator.cc38
-rw-r--r--chrome/browser/sync/glue/session_model_associator.h4
-rw-r--r--chrome/browser/sync/profile_sync_service_session_unittest.cc2
-rw-r--r--chrome/chrome_tests.gypi7
-rw-r--r--chrome/test/live_sync/live_sessions_sync_test.h418
-rw-r--r--chrome/test/live_sync/live_sync_test.cc5
-rw-r--r--chrome/test/live_sync/multiple_client_live_sessions_sync_test.cc33
-rw-r--r--chrome/test/live_sync/single_client_live_sessions_sync_test.cc30
-rw-r--r--chrome/test/live_sync/two_client_live_sessions_sync_test.cc62
14 files changed, 588 insertions, 20 deletions
diff --git a/chrome/browser/dom_ui/foreign_session_handler.cc b/chrome/browser/dom_ui/foreign_session_handler.cc
index e35d8e5..d0ceabc 100644
--- a/chrome/browser/dom_ui/foreign_session_handler.cc
+++ b/chrome/browser/dom_ui/foreign_session_handler.cc
@@ -142,7 +142,7 @@ void ForeignSessionHandler::GetForeignSessions(
// TODO(zea): sessionTag is per client, it might be better per window.
window_data->SetString("sessionTag",
- foreign_session->foreign_tession_tag);
+ foreign_session->foreign_session_tag);
window_data->SetInteger("sessionId", entry->id);
// Give ownership to |list_value|.
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index 96bb27c..8dedb8d 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -240,7 +240,7 @@ class SessionService : public BaseSessionService,
SessionCommand* CreatePinnedStateCommand(const SessionID& tab_id,
bool is_pinned);
- // Callback form the backend for getting the commands from the previous
+ // Callback from the backend for getting the commands from the previous
// or save file. Converts the commands in SessionWindows and notifies
// the real callback.
void OnGotSessionCommands(
diff --git a/chrome/browser/sessions/session_service_test_helper.h b/chrome/browser/sessions/session_service_test_helper.h
index c0caa7e..062bb1c 100644
--- a/chrome/browser/sessions/session_service_test_helper.h
+++ b/chrome/browser/sessions/session_service_test_helper.h
@@ -63,6 +63,7 @@ class SessionServiceTestHelper {
size_t nav_count);
void set_service(SessionService* service) { service_ = service; }
+ SessionService* ReleaseService() { return service_.release(); }
SessionService* service() { return service_.get(); }
SessionBackend* backend();
diff --git a/chrome/browser/sessions/session_types.cc b/chrome/browser/sessions/session_types.cc
index 995a9a2..2ebfbb1 100644
--- a/chrome/browser/sessions/session_types.cc
+++ b/chrome/browser/sessions/session_types.cc
@@ -110,7 +110,7 @@ SessionWindow::~SessionWindow() {
// ForeignSession --------------------------------------------------------------
-ForeignSession::ForeignSession() : foreign_tession_tag("invalid") {
+ForeignSession::ForeignSession() : foreign_session_tag("invalid") {
}
ForeignSession::~ForeignSession() {
diff --git a/chrome/browser/sessions/session_types.h b/chrome/browser/sessions/session_types.h
index 119392a..4f84246 100644
--- a/chrome/browser/sessions/session_types.h
+++ b/chrome/browser/sessions/session_types.h
@@ -185,7 +185,7 @@ struct ForeignSession {
~ForeignSession();
// Unique tag for each session.
- std::string foreign_tession_tag;
+ std::string foreign_session_tag;
std::vector<SessionWindow*> windows;
};
diff --git a/chrome/browser/sync/glue/session_model_associator.cc b/chrome/browser/sync/glue/session_model_associator.cc
index 961bfc7..b4666f8 100644
--- a/chrome/browser/sync/glue/session_model_associator.cc
+++ b/chrome/browser/sync/glue/session_model_associator.cc
@@ -192,7 +192,9 @@ bool SessionModelAssociator::GetSessionData(
// Build vector of sessions from specifics data
for (std::vector<const sync_pb::SessionSpecifics*>::const_iterator i =
specifics_.begin(); i != specifics_.end(); ++i) {
- AppendForeignSessionFromSpecifics(*i, sessions);
+ // Only include sessions with open windows.
+ if ((*i)->session_window_size() > 0)
+ AppendForeignSessionFromSpecifics(*i, sessions);
}
return true;
@@ -202,7 +204,7 @@ void SessionModelAssociator::AppendForeignSessionFromSpecifics(
const sync_pb::SessionSpecifics* specifics,
std::vector<ForeignSession*>* session) {
ForeignSession* foreign_session = new ForeignSession();
- foreign_session->foreign_tession_tag = specifics->session_tag();
+ foreign_session->foreign_session_tag = specifics->session_tag();
session->insert(session->end(), foreign_session);
for (int i = 0; i < specifics->session_window_size(); i++) {
const sync_pb::SessionWindow* window = &specifics->session_window(i);
@@ -386,24 +388,16 @@ bool SessionModelAssociator::WindowHasNoTabsToSync(
void SessionModelAssociator::OnGotSession(int handle,
std::vector<SessionWindow*>* windows) {
- sync_pb::SessionSpecifics session;
+ sync_pb::SessionSpecifics specifics;
// Set the tag, then iterate through the vector of windows, extracting the
// window data, along with the tabs data and tab navigation data to populate
// the session specifics.
- session.set_session_tag(GetCurrentMachineTag());
- for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
- i != windows->end(); ++i) {
- const SessionWindow* window = *i;
- if (WindowHasNoTabsToSync(window)) {
- continue;
- }
- sync_pb::SessionWindow* session_window = session.add_session_window();
- PopulateSessionSpecificsWindow(window, session_window);
- }
+ specifics.set_session_tag(GetCurrentMachineTag());
+ FillSpecificsFromSessions(windows, &specifics);
bool has_nodes = false;
if (!SyncModelHasUserCreatedNodes(&has_nodes))
return;
- if (session.session_window_size() == 0 && has_nodes)
+ if (specifics.session_window_size() == 0 && has_nodes)
return;
sync_api::WriteTransaction trans(
sync_service_->backend()->GetUserShareHandle());
@@ -412,7 +406,21 @@ void SessionModelAssociator::OnGotSession(int handle,
LOG(ERROR) << kNoSessionsFolderError;
return;
}
- UpdateSyncModel(&session, &trans, &root);
+ UpdateSyncModel(&specifics, &trans, &root);
+}
+
+void SessionModelAssociator::FillSpecificsFromSessions(
+ std::vector<SessionWindow*>* windows,
+ sync_pb::SessionSpecifics* session) {
+ for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
+ i != windows->end(); ++i) {
+ const SessionWindow* window = *i;
+ if (WindowHasNoTabsToSync(window)) {
+ continue;
+ }
+ sync_pb::SessionWindow* session_window = session->add_session_window();
+ PopulateSessionSpecificsWindow(window, session_window);
+ }
}
void SessionModelAssociator::AppendSessionTabNavigation(
diff --git a/chrome/browser/sync/glue/session_model_associator.h b/chrome/browser/sync/glue/session_model_associator.h
index ac7a234..89d30be 100644
--- a/chrome/browser/sync/glue/session_model_associator.h
+++ b/chrome/browser/sync/glue/session_model_associator.h
@@ -129,6 +129,10 @@ class SessionModelAssociator : public PerDataTypeAssociatorInterface<
// Builds sessions from buffered specifics data
bool GetSessionData(std::vector<ForeignSession*>* sessions);
+ // Helper method to generate session specifics from session windows.
+ void FillSpecificsFromSessions(std::vector<SessionWindow*>* windows,
+ sync_pb::SessionSpecifics* session);
+
// Helper method for converting session specifics to windows.
void AppendForeignSessionFromSpecifics(
const sync_pb::SessionSpecifics* specifics,
diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc
index 77790e4..fc0757e 100644
--- a/chrome/browser/sync/profile_sync_service_session_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc
@@ -314,7 +314,7 @@ TEST_F(ProfileSyncServiceSessionTest, WriteForeignSessionToNode) {
ASSERT_EQ(1U, foreign_sessions[0]->windows.size());
ASSERT_EQ(1U, foreign_sessions[0]->windows[0]->tabs.size());
ASSERT_EQ(1U, foreign_sessions[0]->windows[0]->tabs[0]->navigations.size());
- ASSERT_EQ(foreign_sessions[0]->foreign_tession_tag, machine_tag);
+ ASSERT_EQ(foreign_sessions[0]->foreign_session_tag, machine_tag);
ASSERT_EQ(1, foreign_sessions[0]->windows[0]->selected_tab_index);
ASSERT_EQ(1, foreign_sessions[0]->windows[0]->type);
ASSERT_EQ(13, foreign_sessions[0]->windows[0]->tabs[0]->tab_visual_index);
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index f9b5505..e0b99dd 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2676,6 +2676,9 @@
'browser/autofill/autofill_common_test.cc',
'browser/autofill/autofill_common_test.h',
'browser/password_manager/password_form_data.cc',
+ 'browser/sessions/session_backend.cc',
+ 'browser/sessions/session_service_test_helper.cc',
+ 'browser/sync/glue/session_model_associator.cc',
'test/bookmark_load_observer.h',
'test/in_process_browser_test.cc',
'test/in_process_browser_test.h',
@@ -2686,6 +2689,7 @@
'test/live_sync/live_bookmarks_sync_test.h',
'test/live_sync/live_passwords_sync_test.h',
'test/live_sync/live_preferences_sync_test.h',
+ 'test/live_sync/live_sessions_sync_test.h',
'test/live_sync/live_sync_test.cc',
'test/live_sync/live_sync_test.h',
'test/live_sync/many_client_live_bookmarks_sync_test.cc',
@@ -2694,13 +2698,16 @@
'test/live_sync/multiple_client_live_bookmarks_sync_test.cc',
'test/live_sync/multiple_client_live_passwords_sync_test.cc',
'test/live_sync/multiple_client_live_preferences_sync_test.cc',
+ 'test/live_sync/multiple_client_live_sessions_sync_test.cc',
'test/live_sync/single_client_live_bookmarks_sync_test.cc',
'test/live_sync/single_client_live_passwords_sync_test.cc',
'test/live_sync/single_client_live_preferences_sync_test.cc',
+ 'test/live_sync/single_client_live_sessions_sync_test.cc',
'test/live_sync/two_client_live_autofill_sync_test.cc',
'test/live_sync/two_client_live_bookmarks_sync_test.cc',
'test/live_sync/two_client_live_preferences_sync_test.cc',
'test/live_sync/two_client_live_passwords_sync_test.cc',
+ 'test/live_sync/two_client_live_sessions_sync_test.cc',
'test/test_notification_tracker.cc',
'test/test_notification_tracker.h',
'test/testing_browser_process.h',
diff --git a/chrome/test/live_sync/live_sessions_sync_test.h b/chrome/test/live_sync/live_sessions_sync_test.h
new file mode 100644
index 0000000..48c9d63
--- /dev/null
+++ b/chrome/test/live_sync/live_sessions_sync_test.h
@@ -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_
+
diff --git a/chrome/test/live_sync/live_sync_test.cc b/chrome/test/live_sync/live_sync_test.cc
index 062df35..3b0bec6 100644
--- a/chrome/test/live_sync/live_sync_test.cc
+++ b/chrome/test/live_sync/live_sync_test.cc
@@ -118,6 +118,11 @@ void LiveSyncTest::SetUp() {
cl->AppendSwitch(switches::kSyncTrySsltcpFirstForXmpp);
}
+ // TODO(sync): Remove this once sessions sync is enabled by default.
+ if (!cl->HasSwitch(switches::kEnableSyncSessions)) {
+ cl->AppendSwitch(switches::kEnableSyncSessions);
+ }
+
// Mock the Mac Keychain service. The real Keychain can block on user input.
#if defined(OS_MACOSX)
Encryptor::UseMockKeychain(true);
diff --git a/chrome/test/live_sync/multiple_client_live_sessions_sync_test.cc b/chrome/test/live_sync/multiple_client_live_sessions_sync_test.cc
new file mode 100644
index 0000000..f5e8e1e
--- /dev/null
+++ b/chrome/test/live_sync/multiple_client_live_sessions_sync_test.cc
@@ -0,0 +1,33 @@
+// 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.
+
+#include "base/stringprintf.h"
+#include "chrome/test/live_sync/live_sessions_sync_test.h"
+
+IN_PROC_BROWSER_TEST_F(MultipleClientLiveSessionsSyncTest, AllChanged) {
+ ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+ std::vector<std::vector<SessionWindow*>* > client_windows;
+
+ for (int i = 0; i < num_clients(); ++i) {
+ ASSERT_TRUE(CheckInitialState(i));
+ }
+
+ // Open tabs on all clients and retain window information.
+ for (int i = 0; i < num_clients(); ++i) {
+ std::vector<SessionWindow*>* new_windows =
+ InitializeNewWindowWithTab(i, GURL(StringPrintf("about:bubba%i", i)));
+ ASSERT_TRUE(new_windows);
+ client_windows.push_back(new_windows);
+ }
+
+ // Wait for sync.
+ ASSERT_TRUE(AwaitQuiescence());
+
+ // Get foreign session data from all clients and check it against all
+ // client_windows.
+ for (int i = 0; i < num_clients(); ++i) {
+ ASSERT_TRUE(CheckForeignSessionsAgainst(i, client_windows));
+ }
+}
+
diff --git a/chrome/test/live_sync/single_client_live_sessions_sync_test.cc b/chrome/test/live_sync/single_client_live_sessions_sync_test.cc
new file mode 100644
index 0000000..9c5b2f7
--- /dev/null
+++ b/chrome/test/live_sync/single_client_live_sessions_sync_test.cc
@@ -0,0 +1,30 @@
+// 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.
+
+#include "base/scoped_vector.h"
+#include "chrome/test/live_sync/live_sessions_sync_test.h"
+
+IN_PROC_BROWSER_TEST_F(SingleClientLiveSessionsSyncTest, Sanity) {
+ ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+
+ ASSERT_TRUE(CheckInitialState(0));
+
+ std::vector<SessionWindow*>* old_windows =
+ InitializeNewWindowWithTab(0, GURL("about:bubba"));
+ ASSERT_TRUE(old_windows);
+
+ ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion(
+ "Waiting for session change."));
+
+ // Get foreign session data from client 0.
+ ScopedVector<ForeignSession> sessions;
+ ASSERT_TRUE(GetSessionData(0, &sessions.get()));
+ ASSERT_EQ(0U, sessions.size());
+
+ // Verify client didn't change.
+ std::vector<SessionWindow*>* new_windows = GetHelper(0)->ReadWindows();
+ ASSERT_TRUE(new_windows);
+ ASSERT_TRUE(WindowsMatch(*old_windows, *new_windows));
+}
+
diff --git a/chrome/test/live_sync/two_client_live_sessions_sync_test.cc b/chrome/test/live_sync/two_client_live_sessions_sync_test.cc
new file mode 100644
index 0000000..c6cf184
--- /dev/null
+++ b/chrome/test/live_sync/two_client_live_sessions_sync_test.cc
@@ -0,0 +1,62 @@
+// 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.
+
+#include "chrome/test/live_sync/live_sessions_sync_test.h"
+
+// @TODO(zea): Test each individual session command we care about separately.
+// (as well as multi-window). We're currently only checking basic single-window/
+// single-tab functionality.
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveSessionsSyncTest, SingleClientChanged) {
+ ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+
+ ASSERT_TRUE(CheckInitialState(0));
+ ASSERT_TRUE(CheckInitialState(1));
+
+ std::vector<SessionWindow*>* client0_windows =
+ InitializeNewWindowWithTab(0, GURL("about:bubba"));
+ ASSERT_TRUE(client0_windows);
+
+ GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
+
+ // Get foreign session data from client 1.
+ ScopedVector<ForeignSession> sessions1;
+ ASSERT_TRUE(GetSessionData(1, &sessions1.get()));
+
+ // Verify client 1's foreign session matches client 0 current window.
+ ASSERT_EQ(1U, sessions1.size());
+ ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, *client0_windows));
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveSessionsSyncTest, BothChanged) {
+ ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+
+ ASSERT_TRUE(CheckInitialState(0));
+ ASSERT_TRUE(CheckInitialState(1));
+
+ // Open tabs on both clients and retain window information.
+ std::vector<SessionWindow*>* client0_windows =
+ InitializeNewWindowWithTab(0, GURL("about:bubba0"));
+ ASSERT_TRUE(client0_windows);
+ std::vector<SessionWindow*>* client1_windows =
+ InitializeNewWindowWithTab(1, GURL("about:bubba1"));
+ ASSERT_TRUE(client1_windows);
+
+ // Wait for sync.
+ ASSERT_TRUE(AwaitQuiescence());
+
+ // Get foreign session data from client 0 and 1.
+ ScopedVector<ForeignSession> sessions0;
+ ScopedVector<ForeignSession> sessions1;
+ ASSERT_TRUE(GetSessionData(0, &sessions0.get()));
+ ASSERT_TRUE(GetSessionData(1, &sessions1.get()));
+
+ // Verify client 1's foreign session matches client 0's current window and
+ // vice versa.
+ ASSERT_EQ(1U, sessions0.size());
+ ASSERT_EQ(1U, sessions1.size());
+ ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, *client0_windows));
+ ASSERT_TRUE(WindowsMatch(sessions0[0]->windows, *client1_windows));
+}
+