summaryrefslogtreecommitdiffstats
path: root/chrome/test
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 /chrome/test
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
Diffstat (limited to 'chrome/test')
-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
5 files changed, 548 insertions, 0 deletions
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));
+}
+