This source file includes following definitions.
- HasWindow
- GetSessionId
- GetTabCount
- GetActiveIndex
- IsApp
- IsTypeTabbed
- IsTypePopup
- IsTabPinned
- GetTabAt
- OverrideTabAt
- GetTabIdAt
- IsSessionRestoreInProgress
- GetSyncedWindowDelegates
- ProcessSyncChanges
- GetAllSyncData
- FailProcessSyncChangesWith
- SetSyncDataToReturn
- MakeRemoteChange
- AddTabsToChangeList
- AddTabsToSyncDataList
- StartRoutingTo
- Stop
- NewDummyRouter
- SetUp
- TearDown
- GetLocalDeviceInfo
- GetLocalSyncCacheGUID
- manager
- helper
- InitWithSyncDataTakeOutput
- InitWithNoSyncData
- TriggerProcessSyncChangesError
- SetSyncData
- FilterOutLocalHeaderChanges
- TEST_F
- TEST_F
- blocked_navigations_
- GetCurrentEntryIndex
- set_current_entry_index
- GetEntryAtIndex
- AppendEntry
- GetEntryCount
- GetPendingEntryIndex
- set_pending_entry_index
- GetWindowId
- GetSessionId
- IsBeingDestroyed
- profile
- GetExtensionAppId
- GetPendingEntry
- GetActiveEntry
- ProfileIsManaged
- set_is_managed
- GetBlockedNavigations
- set_blocked_navigations
- IsPinned
- HasWebContents
- GetWebContents
- GetSyncId
- SetSyncId
- reset
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- notified_of_refresh_
- Observe
- notified_of_update
- notified_of_refresh
- Reset
- TEST_F
- TEST_F
- TEST_F
#include "chrome/browser/sync/sessions2/sessions_sync_manager.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sync/glue/device_info.h"
#include "chrome/browser/sync/glue/session_sync_test_helper.h"
#include "chrome/browser/sync/glue/synced_tab_delegate.h"
#include "chrome/browser/sync/glue/synced_window_delegate.h"
#include "chrome/browser/sync/sessions2/notification_service_sessions_router.h"
#include "chrome/browser/sync/sessions2/sessions_util.h"
#include "chrome/browser/sync/sessions2/synced_window_delegates_getter.h"
#include "chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "components/sessions/serialized_navigation_entry_test_helper.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "sync/api/sync_error_factory_mock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::WebContents;
using sessions::SerializedNavigationEntry;
using sessions::SerializedNavigationEntryTestHelper;
using syncer::SyncChange;
using syncer::SyncData;
namespace browser_sync {
namespace {
class SyncedWindowDelegateOverride : public SyncedWindowDelegate {
public:
explicit SyncedWindowDelegateOverride(SyncedWindowDelegate* wrapped)
: wrapped_(wrapped) {
}
virtual ~SyncedWindowDelegateOverride() {}
virtual bool HasWindow() const OVERRIDE {
return wrapped_->HasWindow();
}
virtual SessionID::id_type GetSessionId() const OVERRIDE {
return wrapped_->GetSessionId();
}
virtual int GetTabCount() const OVERRIDE {
return wrapped_->GetTabCount();
}
virtual int GetActiveIndex() const OVERRIDE {
return wrapped_->GetActiveIndex();
}
virtual bool IsApp() const OVERRIDE {
return wrapped_->IsApp();
}
virtual bool IsTypeTabbed() const OVERRIDE {
return wrapped_->IsTypeTabbed();
}
virtual bool IsTypePopup() const OVERRIDE {
return wrapped_->IsTypePopup();
}
virtual bool IsTabPinned(const SyncedTabDelegate* tab) const OVERRIDE {
return wrapped_->IsTabPinned(tab);
}
virtual SyncedTabDelegate* GetTabAt(int index) const OVERRIDE {
if (tab_overrides_.find(index) != tab_overrides_.end())
return tab_overrides_.find(index)->second;
return wrapped_->GetTabAt(index);
}
void OverrideTabAt(int index,
SyncedTabDelegate* delegate,
SessionID::id_type tab_id) {
tab_overrides_[index] = delegate;
tab_id_overrides_[index] = tab_id;
}
virtual SessionID::id_type GetTabIdAt(int index) const OVERRIDE {
if (tab_id_overrides_.find(index) != tab_id_overrides_.end())
return tab_id_overrides_.find(index)->second;
return wrapped_->GetTabIdAt(index);
}
virtual bool IsSessionRestoreInProgress() const OVERRIDE {
return wrapped_->IsSessionRestoreInProgress();
}
private:
std::map<int, SyncedTabDelegate*> tab_overrides_;
std::map<int, SessionID::id_type> tab_id_overrides_;
SyncedWindowDelegate* wrapped_;
};
class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter {
public:
TestSyncedWindowDelegatesGetter(
const std::set<SyncedWindowDelegate*>& delegates)
: delegates_(delegates) {}
virtual const std::set<SyncedWindowDelegate*> GetSyncedWindowDelegates()
OVERRIDE {
return delegates_;
}
private:
const std::set<SyncedWindowDelegate*> delegates_;
};
class TestSyncProcessorStub : public syncer::SyncChangeProcessor {
public:
explicit TestSyncProcessorStub(syncer::SyncChangeList* output)
: output_(output) {}
virtual syncer::SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) OVERRIDE {
if (error_.IsSet()) {
syncer::SyncError error = error_;
error_ = syncer::SyncError();
return error;
}
if (output_)
output_->insert(output_->end(), change_list.begin(), change_list.end());
return syncer::SyncError();
}
virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
const OVERRIDE {
return sync_data_to_return_;
}
void FailProcessSyncChangesWith(const syncer::SyncError& error) {
error_ = error;
}
void SetSyncDataToReturn(const syncer::SyncDataList& data) {
sync_data_to_return_ = data;
}
private:
syncer::SyncError error_;
syncer::SyncChangeList* output_;
syncer::SyncDataList sync_data_to_return_;
};
syncer::SyncChange MakeRemoteChange(
int64 id,
const sync_pb::SessionSpecifics& specifics,
SyncChange::SyncChangeType type) {
sync_pb::EntitySpecifics entity;
entity.mutable_session()->CopyFrom(specifics);
return syncer::SyncChange(
FROM_HERE, type,
syncer::SyncData::CreateRemoteData(id, entity, base::Time()));
}
void AddTabsToChangeList(
const std::vector<sync_pb::SessionSpecifics>& batch,
SyncChange::SyncChangeType type,
syncer::SyncChangeList* change_list) {
std::vector<sync_pb::SessionSpecifics>::const_iterator iter;
for (iter = batch.begin();
iter != batch.end(); ++iter) {
sync_pb::EntitySpecifics entity;
entity.mutable_session()->CopyFrom(*iter);
change_list->push_back(syncer::SyncChange(
FROM_HERE, type,
syncer::SyncData::CreateRemoteData(iter->tab_node_id(),
entity, base::Time())));
}
}
void AddTabsToSyncDataList(const std::vector<sync_pb::SessionSpecifics> tabs,
syncer::SyncDataList* list) {
for (size_t i = 0; i < tabs.size(); i++) {
sync_pb::EntitySpecifics entity;
entity.mutable_session()->CopyFrom(tabs[i]);
list->push_back(SyncData::CreateRemoteData(
i + 2, entity, base::Time()));
}
}
class DummyRouter : public LocalSessionEventRouter {
public:
virtual ~DummyRouter() {}
virtual void StartRoutingTo(LocalSessionEventHandler* handler) OVERRIDE {}
virtual void Stop() OVERRIDE {}
};
scoped_ptr<LocalSessionEventRouter> NewDummyRouter() {
return scoped_ptr<LocalSessionEventRouter>(new DummyRouter());
}
}
class SessionsSyncManagerTest
: public BrowserWithTestWindowTest,
public SessionsSyncManager::SyncInternalApiDelegate {
public:
SessionsSyncManagerTest() : test_processor_(NULL) {}
virtual void SetUp() OVERRIDE {
BrowserWithTestWindowTest::SetUp();
browser_sync::NotificationServiceSessionsRouter* router(
new browser_sync::NotificationServiceSessionsRouter(
profile(), syncer::SyncableService::StartSyncFlare()));
manager_.reset(new SessionsSyncManager(profile(), this,
scoped_ptr<LocalSessionEventRouter>(router)));
}
virtual void TearDown() OVERRIDE {
test_processor_ = NULL;
helper()->Reset();
manager_.reset();
BrowserWithTestWindowTest::TearDown();
}
virtual scoped_ptr<DeviceInfo> GetLocalDeviceInfo() const OVERRIDE {
return scoped_ptr<DeviceInfo>(
new DeviceInfo(GetLocalSyncCacheGUID(),
"Wayne Gretzky's Hacking Box",
"Chromium 10k",
"Chrome 10k",
sync_pb::SyncEnums_DeviceType_TYPE_LINUX));
}
virtual std::string GetLocalSyncCacheGUID() const OVERRIDE {
return "cache_guid";
}
SessionsSyncManager* manager() { return manager_.get(); }
SessionSyncTestHelper* helper() { return &helper_; }
void InitWithSyncDataTakeOutput(const syncer::SyncDataList& initial_data,
syncer::SyncChangeList* output) {
test_processor_ = new TestSyncProcessorStub(output);
syncer::SyncMergeResult result = manager_->MergeDataAndStartSyncing(
syncer::SESSIONS, initial_data,
scoped_ptr<syncer::SyncChangeProcessor>(test_processor_),
scoped_ptr<syncer::SyncErrorFactory>(
new syncer::SyncErrorFactoryMock()));
EXPECT_FALSE(result.error().IsSet());
}
void InitWithNoSyncData() {
InitWithSyncDataTakeOutput(syncer::SyncDataList(), NULL);
}
void TriggerProcessSyncChangesError() {
test_processor_->FailProcessSyncChangesWith(syncer::SyncError(
FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "Error",
syncer::SESSIONS));
}
void SetSyncData(const syncer::SyncDataList& data) {
test_processor_->SetSyncDataToReturn(data);
}
syncer::SyncChangeList* FilterOutLocalHeaderChanges(
syncer::SyncChangeList* list) {
syncer::SyncChangeList::iterator it = list->begin();
bool found = false;
while (it != list->end()) {
if (syncer::SyncDataLocal(it->sync_data()).GetTag() ==
manager_->current_machine_tag()) {
EXPECT_TRUE(SyncChange::ACTION_ADD == it->change_type() ||
SyncChange::ACTION_UPDATE == it->change_type());
it = list->erase(it);
found = true;
} else {
++it;
}
}
EXPECT_TRUE(found);
return list;
}
private:
scoped_ptr<SessionsSyncManager> manager_;
SessionSyncTestHelper helper_;
TestSyncProcessorStub* test_processor_;
};
TEST_F(SessionsSyncManagerTest, PopulateSessionHeader) {
sync_pb::SessionHeader header_s;
header_s.set_client_name("Client 1");
header_s.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_WIN);
SyncedSession session;
base::Time time = base::Time::Now();
SessionsSyncManager::PopulateSessionHeaderFromSpecifics(
header_s, time, &session);
ASSERT_EQ("Client 1", session.session_name);
ASSERT_EQ(SyncedSession::TYPE_WIN, session.device_type);
ASSERT_EQ(time, session.modified_time);
}
TEST_F(SessionsSyncManagerTest, PopulateSessionWindow) {
sync_pb::SessionWindow window_s;
window_s.add_tab(0);
window_s.set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
window_s.set_selected_tab_index(1);
std::string tag = "tag";
SyncedSession* session = manager()->session_tracker_.GetSession(tag);
manager()->session_tracker_.PutWindowInSession(tag, 0);
manager()->BuildSyncedSessionFromSpecifics(
tag, window_s, base::Time(), session->windows[0]);
ASSERT_EQ(1U, session->windows[0]->tabs.size());
ASSERT_EQ(1, session->windows[0]->selected_tab_index);
ASSERT_EQ(1, session->windows[0]->type);
ASSERT_EQ(1U, manager()->session_tracker_.num_synced_sessions());
ASSERT_EQ(1U,
manager()->session_tracker_.num_synced_tabs(std::string("tag")));
}
namespace {
class SyncedTabDelegateFake : public SyncedTabDelegate {
public:
SyncedTabDelegateFake() : current_entry_index_(0),
pending_entry_index_(-1),
is_managed_(false),
sync_id_(-1),
blocked_navigations_(NULL) {}
virtual ~SyncedTabDelegateFake() {}
virtual int GetCurrentEntryIndex() const OVERRIDE {
return current_entry_index_;
}
void set_current_entry_index(int i) {
current_entry_index_ = i;
}
virtual content::NavigationEntry* GetEntryAtIndex(int i) const OVERRIDE {
const int size = entries_.size();
return (size < i + 1) ? NULL : entries_[i];
}
void AppendEntry(content::NavigationEntry* entry) {
entries_.push_back(entry);
}
virtual int GetEntryCount() const OVERRIDE {
return entries_.size();
}
virtual int GetPendingEntryIndex() const OVERRIDE {
return pending_entry_index_;
}
void set_pending_entry_index(int i) {
pending_entry_index_ = i;
}
virtual SessionID::id_type GetWindowId() const OVERRIDE {
return SessionID::id_type();
}
virtual SessionID::id_type GetSessionId() const OVERRIDE {
return SessionID::id_type();
}
virtual bool IsBeingDestroyed() const OVERRIDE { return false; }
virtual Profile* profile() const OVERRIDE { return NULL; }
virtual std::string GetExtensionAppId() const OVERRIDE {
return std::string();
}
virtual content::NavigationEntry* GetPendingEntry() const OVERRIDE {
return NULL;
}
virtual content::NavigationEntry* GetActiveEntry() const OVERRIDE {
return NULL;
}
virtual bool ProfileIsManaged() const OVERRIDE {
return is_managed_;
}
void set_is_managed(bool is_managed) { is_managed_ = is_managed; }
virtual const std::vector<const content::NavigationEntry*>*
GetBlockedNavigations() const OVERRIDE {
return blocked_navigations_;
}
void set_blocked_navigations(
std::vector<const content::NavigationEntry*>* navs) {
blocked_navigations_ = navs;
}
virtual bool IsPinned() const OVERRIDE {
return false;
}
virtual bool HasWebContents() const OVERRIDE {
return false;
}
virtual content::WebContents* GetWebContents() const OVERRIDE {
return NULL;
}
virtual int GetSyncId() const OVERRIDE {
return sync_id_;
}
virtual void SetSyncId(int sync_id) OVERRIDE {
sync_id_ = sync_id;
}
void reset() {
current_entry_index_ = 0;
pending_entry_index_ = -1;
sync_id_ = -1;
entries_.clear();
}
private:
int current_entry_index_;
int pending_entry_index_;
bool is_managed_;
int sync_id_;
std::vector<const content::NavigationEntry*>* blocked_navigations_;
ScopedVector<content::NavigationEntry> entries_;
};
}
TEST_F(SessionsSyncManagerTest, ValidTabs) {
SyncedTabDelegateFake tab;
tab.AppendEntry(NULL);
EXPECT_FALSE(sessions_util::ShouldSyncTab(tab));
tab.reset();
content::NavigationEntry* entry(content::NavigationEntry::Create());
entry->SetVirtualURL(GURL("chrome://preferences/"));
tab.AppendEntry(entry);
EXPECT_FALSE(sessions_util::ShouldSyncTab(tab));
content::NavigationEntry* entry2(content::NavigationEntry::Create());
entry2->SetVirtualURL(GURL("file://bla"));
tab.AppendEntry(entry2);
EXPECT_FALSE(sessions_util::ShouldSyncTab(tab));
content::NavigationEntry* entry3(content::NavigationEntry::Create());
entry3->SetVirtualURL(GURL("http://www.google.com"));
tab.AppendEntry(entry3);
EXPECT_FALSE(sessions_util::ShouldSyncTab(tab));
}
TEST_F(SessionsSyncManagerTest, GetCurrentVirtualURLPending) {
SyncedTabDelegateFake tab;
content::NavigationEntry* entry(content::NavigationEntry::Create());
entry->SetVirtualURL(GURL("http://www.google.com"));
tab.AppendEntry(entry);
EXPECT_EQ(entry->GetVirtualURL(), manager()->GetCurrentVirtualURL(tab));
}
TEST_F(SessionsSyncManagerTest, GetCurrentVirtualURLNonPending) {
SyncedTabDelegateFake tab;
content::NavigationEntry* entry(content::NavigationEntry::Create());
entry->SetVirtualURL(GURL("http://www.google.com"));
tab.AppendEntry(entry);
EXPECT_EQ(entry->GetVirtualURL(), manager()->GetCurrentVirtualURL(tab));
}
static const base::Time kTime1 = base::Time::FromInternalValue(100);
static const base::Time kTime2 = base::Time::FromInternalValue(105);
static const base::Time kTime3 = base::Time::FromInternalValue(110);
static const base::Time kTime4 = base::Time::FromInternalValue(120);
static const base::Time kTime5 = base::Time::FromInternalValue(130);
TEST_F(SessionsSyncManagerTest, SetSessionTabFromDelegate) {
SyncedTabDelegateFake tab;
content::NavigationEntry* entry1(content::NavigationEntry::Create());
entry1->SetVirtualURL(GURL("http://www.google.com"));
entry1->SetTimestamp(kTime1);
entry1->SetHttpStatusCode(200);
content::NavigationEntry* entry2(content::NavigationEntry::Create());
entry2->SetVirtualURL(GURL("http://www.noodle.com"));
entry2->SetTimestamp(kTime2);
entry2->SetHttpStatusCode(201);
content::NavigationEntry* entry3(content::NavigationEntry::Create());
entry3->SetVirtualURL(GURL("http://www.doodle.com"));
entry3->SetTimestamp(kTime3);
entry3->SetHttpStatusCode(202);
tab.AppendEntry(entry1);
tab.AppendEntry(entry2);
tab.AppendEntry(entry3);
tab.set_current_entry_index(2);
SessionTab session_tab;
session_tab.window_id.set_id(1);
session_tab.tab_id.set_id(1);
session_tab.tab_visual_index = 1;
session_tab.current_navigation_index = 1;
session_tab.pinned = true;
session_tab.extension_app_id = "app id";
session_tab.user_agent_override = "override";
session_tab.timestamp = kTime5;
session_tab.navigations.push_back(
SerializedNavigationEntryTestHelper::CreateNavigation(
"http://www.example.com", "Example"));
session_tab.session_storage_persistent_id = "persistent id";
manager()->SetSessionTabFromDelegate(tab, kTime4, &session_tab);
EXPECT_EQ(0, session_tab.window_id.id());
EXPECT_EQ(0, session_tab.tab_id.id());
EXPECT_EQ(0, session_tab.tab_visual_index);
EXPECT_EQ(2, session_tab.current_navigation_index);
EXPECT_FALSE(session_tab.pinned);
EXPECT_TRUE(session_tab.extension_app_id.empty());
EXPECT_TRUE(session_tab.user_agent_override.empty());
EXPECT_EQ(kTime4, session_tab.timestamp);
ASSERT_EQ(3u, session_tab.navigations.size());
EXPECT_EQ(entry1->GetVirtualURL(),
session_tab.navigations[0].virtual_url());
EXPECT_EQ(entry2->GetVirtualURL(),
session_tab.navigations[1].virtual_url());
EXPECT_EQ(entry3->GetVirtualURL(),
session_tab.navigations[2].virtual_url());
EXPECT_EQ(kTime1, session_tab.navigations[0].timestamp());
EXPECT_EQ(kTime2, session_tab.navigations[1].timestamp());
EXPECT_EQ(kTime3, session_tab.navigations[2].timestamp());
EXPECT_EQ(200, session_tab.navigations[0].http_status_code());
EXPECT_EQ(201, session_tab.navigations[1].http_status_code());
EXPECT_EQ(202, session_tab.navigations[2].http_status_code());
EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID,
session_tab.navigations[0].blocked_state());
EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID,
session_tab.navigations[1].blocked_state());
EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID,
session_tab.navigations[2].blocked_state());
EXPECT_TRUE(session_tab.session_storage_persistent_id.empty());
}
TEST_F(SessionsSyncManagerTest, BlockedNavigations) {
SyncedTabDelegateFake tab;
content::NavigationEntry* entry1(content::NavigationEntry::Create());
entry1->SetVirtualURL(GURL("http://www.google.com"));
entry1->SetTimestamp(kTime1);
tab.AppendEntry(entry1);
content::NavigationEntry* entry2 = content::NavigationEntry::Create();
entry2->SetVirtualURL(GURL("http://blocked.com/foo"));
entry2->SetTimestamp(kTime2);
content::NavigationEntry* entry3 = content::NavigationEntry::Create();
entry3->SetVirtualURL(GURL("http://evil.com"));
entry3->SetTimestamp(kTime3);
ScopedVector<const content::NavigationEntry> blocked_navigations;
blocked_navigations.push_back(entry2);
blocked_navigations.push_back(entry3);
tab.set_is_managed(true);
tab.set_blocked_navigations(&blocked_navigations.get());
SessionTab session_tab;
session_tab.window_id.set_id(1);
session_tab.tab_id.set_id(1);
session_tab.tab_visual_index = 1;
session_tab.current_navigation_index = 1;
session_tab.pinned = true;
session_tab.extension_app_id = "app id";
session_tab.user_agent_override = "override";
session_tab.timestamp = kTime5;
session_tab.navigations.push_back(
SerializedNavigationEntryTestHelper::CreateNavigation(
"http://www.example.com", "Example"));
session_tab.session_storage_persistent_id = "persistent id";
manager()->SetSessionTabFromDelegate(tab, kTime4, &session_tab);
EXPECT_EQ(0, session_tab.window_id.id());
EXPECT_EQ(0, session_tab.tab_id.id());
EXPECT_EQ(0, session_tab.tab_visual_index);
EXPECT_EQ(0, session_tab.current_navigation_index);
EXPECT_FALSE(session_tab.pinned);
EXPECT_TRUE(session_tab.extension_app_id.empty());
EXPECT_TRUE(session_tab.user_agent_override.empty());
EXPECT_EQ(kTime4, session_tab.timestamp);
ASSERT_EQ(3u, session_tab.navigations.size());
EXPECT_EQ(entry1->GetVirtualURL(),
session_tab.navigations[0].virtual_url());
EXPECT_EQ(entry2->GetVirtualURL(),
session_tab.navigations[1].virtual_url());
EXPECT_EQ(entry3->GetVirtualURL(),
session_tab.navigations[2].virtual_url());
EXPECT_EQ(kTime1, session_tab.navigations[0].timestamp());
EXPECT_EQ(kTime2, session_tab.navigations[1].timestamp());
EXPECT_EQ(kTime3, session_tab.navigations[2].timestamp());
EXPECT_EQ(SerializedNavigationEntry::STATE_ALLOWED,
session_tab.navigations[0].blocked_state());
EXPECT_EQ(SerializedNavigationEntry::STATE_BLOCKED,
session_tab.navigations[1].blocked_state());
EXPECT_EQ(SerializedNavigationEntry::STATE_BLOCKED,
session_tab.navigations[2].blocked_state());
EXPECT_TRUE(session_tab.session_storage_persistent_id.empty());
}
TEST_F(SessionsSyncManagerTest, MergeLocalSessionNoTabs) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
EXPECT_FALSE(manager()->current_machine_tag().empty());
EXPECT_EQ(2U, out.size());
EXPECT_TRUE(out[0].IsValid());
EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
const SyncData data(out[0].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data).GetTag());
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
EXPECT_TRUE(specifics.has_header());
const sync_pb::SessionHeader& header_s = specifics.header();
EXPECT_TRUE(header_s.has_device_type());
EXPECT_EQ(GetLocalDeviceInfo()->client_name(), header_s.client_name());
EXPECT_EQ(0, header_s.window_size());
EXPECT_TRUE(out[1].IsValid());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type());
const SyncData data_2(out[1].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data_2).GetTag());
const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics2.session_tag());
EXPECT_TRUE(specifics2.has_header());
const sync_pb::SessionHeader& header_s2 = specifics2.header();
EXPECT_EQ(0, header_s2.window_size());
SyncData d(SyncData::CreateRemoteData(1, data.GetSpecifics(), base::Time()));
syncer::SyncDataList in(&d, &d + 1);
out.clear();
SessionsSyncManager manager2(profile(), this, NewDummyRouter());
syncer::SyncMergeResult result = manager2.MergeDataAndStartSyncing(
syncer::SESSIONS, in,
scoped_ptr<syncer::SyncChangeProcessor>(
new TestSyncProcessorStub(&out)),
scoped_ptr<syncer::SyncErrorFactory>(
new syncer::SyncErrorFactoryMock()));
ASSERT_FALSE(result.error().IsSet());
EXPECT_EQ(1U, out.size());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
EXPECT_TRUE(out[0].sync_data().GetSpecifics().session().has_header());
}
TEST_F(SessionsSyncManagerTest, SwappedOutOnRestore) {
AddTab(browser(), GURL("http://foo1"));
NavigateAndCommitActiveTab(GURL("http://foo2"));
AddTab(browser(), GURL("http://bar1"));
NavigateAndCommitActiveTab(GURL("http://bar2"));
AddTab(browser(), GURL("http://baz1"));
NavigateAndCommitActiveTab(GURL("http://baz2"));
const int kRestoredTabId = 1337;
const int kNewTabId = 2468;
syncer::SyncDataList in;
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(in, &out);
ASSERT_EQ(8U, out.size());
SyncData t0(SyncData::CreateRemoteData(1, out[2].sync_data().GetSpecifics(),
base::Time()));
sync_pb::EntitySpecifics entity(out[4].sync_data().GetSpecifics());
entity.mutable_session()->mutable_tab()->set_tab_id(kRestoredTabId);
SyncData t1(SyncData::CreateRemoteData(2, entity, base::Time()));
SyncData t2(SyncData::CreateRemoteData(3, out[6].sync_data().GetSpecifics(),
base::Time()));
in.push_back(t0);
in.push_back(t1);
in.push_back(t2);
out.clear();
manager()->StopSyncing(syncer::SESSIONS);
const std::set<SyncedWindowDelegate*> windows(
SyncedWindowDelegate::GetSyncedWindowDelegates());
ASSERT_EQ(1U, windows.size());
SyncedTabDelegateFake t1_override, t2_override;
t1_override.SetSyncId(1);
t2_override.SetSyncId(2);
SyncedWindowDelegateOverride window_override(*windows.begin());
window_override.OverrideTabAt(1, &t1_override, kNewTabId);
window_override.OverrideTabAt(2, &t2_override,
t2.GetSpecifics().session().tab().tab_id());
std::set<SyncedWindowDelegate*> delegates;
delegates.insert(&window_override);
scoped_ptr<TestSyncedWindowDelegatesGetter> getter(
new TestSyncedWindowDelegatesGetter(delegates));
manager()->synced_window_getter_.reset(getter.release());
syncer::SyncMergeResult result = manager()->MergeDataAndStartSyncing(
syncer::SESSIONS, in,
scoped_ptr<syncer::SyncChangeProcessor>(
new TestSyncProcessorStub(&out)),
scoped_ptr<syncer::SyncErrorFactory>(
new syncer::SyncErrorFactoryMock()));
ASSERT_EQ(2U, FilterOutLocalHeaderChanges(&out)->size());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type());
EXPECT_EQ(kNewTabId,
out[1].sync_data().GetSpecifics().session().tab().tab_id());
SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
ASSERT_EQ(3U, tab_map.size());
int t2_tab_id = t2.GetSpecifics().session().tab().tab_id();
EXPECT_EQ(2, tab_map.find(t2_tab_id)->second->tab_node_id());
EXPECT_EQ(1, tab_map.find(kNewTabId)->second->tab_node_id());
int t0_tab_id = out[0].sync_data().GetSpecifics().session().tab().tab_id();
EXPECT_EQ(0, tab_map.find(t0_tab_id)->second->tab_node_id());
}
TEST_F(SessionsSyncManagerTest, MergeWithInitialForeignSession) {
std::string tag = "tag1";
SessionID::id_type n1[] = {5, 10, 13, 17};
std::vector<SessionID::id_type> tab_list1(n1, n1 + arraysize(n1));
std::vector<sync_pb::SessionSpecifics> tabs1;
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag, tab_list1, &tabs1));
SessionID::id_type n2[] = {7, 15, 18, 20};
std::vector<SessionID::id_type> tab_list2(n2, n2 + arraysize(n2));
helper()->AddWindowSpecifics(1, tab_list2, &meta);
syncer::SyncDataList initial_data;
sync_pb::EntitySpecifics entity;
entity.mutable_session()->CopyFrom(meta);
initial_data.push_back(SyncData::CreateRemoteData(1, entity, base::Time()));
AddTabsToSyncDataList(tabs1, &initial_data);
for (size_t i = 0; i < tab_list2.size(); ++i) {
sync_pb::EntitySpecifics entity;
helper()->BuildTabSpecifics(tag, 0, tab_list2[i],
entity.mutable_session());
initial_data.push_back(
SyncData::CreateRemoteData(i + 10, entity, base::Time()));
}
syncer::SyncChangeList output;
InitWithSyncDataTakeOutput(initial_data, &output);
EXPECT_TRUE(FilterOutLocalHeaderChanges(&output)->empty());
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
std::vector<std::vector<SessionID::id_type> > session_reference;
session_reference.push_back(tab_list1);
session_reference.push_back(tab_list2);
helper()->VerifySyncedSession(tag, session_reference, *(foreign_sessions[0]));
}
TEST_F(SessionsSyncManagerTest, MergeWithLocalAndForeignTabs) {
AddTab(browser(), GURL("http://foo1"));
NavigateAndCommitActiveTab(GURL("http://foo2"));
std::string tag = "tag1";
SessionID::id_type n1[] = {5, 10, 13, 17};
std::vector<SessionID::id_type> tab_list1(n1, n1 + arraysize(n1));
std::vector<sync_pb::SessionSpecifics> tabs1;
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag, tab_list1, &tabs1));
syncer::SyncDataList foreign_data;
sync_pb::EntitySpecifics entity;
entity.mutable_session()->CopyFrom(meta);
foreign_data.push_back(SyncData::CreateRemoteData(1, entity, base::Time()));
AddTabsToSyncDataList(tabs1, &foreign_data);
syncer::SyncChangeList output;
InitWithSyncDataTakeOutput(foreign_data, &output);
ASSERT_EQ(4U, output.size());
EXPECT_TRUE(output[0].IsValid());
EXPECT_EQ(SyncChange::ACTION_ADD, output[0].change_type());
const SyncData data(output[0].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data).GetTag());
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
EXPECT_TRUE(specifics.has_header());
const sync_pb::SessionHeader& header_s = specifics.header();
EXPECT_TRUE(header_s.has_device_type());
EXPECT_EQ(GetLocalDeviceInfo()->client_name(), header_s.client_name());
EXPECT_EQ(0, header_s.window_size());
for (int i = 1; i < 3; i++) {
EXPECT_TRUE(output[i].IsValid());
const SyncData data(output[i].sync_data());
EXPECT_TRUE(StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
manager()->current_machine_tag(), true));
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
}
EXPECT_EQ(SyncChange::ACTION_ADD, output[1].change_type());
EXPECT_EQ(SyncChange::ACTION_UPDATE, output[2].change_type());
EXPECT_TRUE(output[2].sync_data().GetSpecifics().session().has_tab());
EXPECT_TRUE(output[3].IsValid());
EXPECT_EQ(SyncChange::ACTION_UPDATE, output[3].change_type());
const SyncData data_2(output[3].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data_2).GetTag());
const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics2.session_tag());
EXPECT_TRUE(specifics2.has_header());
const sync_pb::SessionHeader& header_s2 = specifics2.header();
EXPECT_EQ(1, header_s2.window_size());
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
std::vector<std::vector<SessionID::id_type> > session_reference;
session_reference.push_back(tab_list1);
helper()->VerifySyncedSession(tag, session_reference, *(foreign_sessions[0]));
EXPECT_EQ(1U, foreign_sessions.size());
}
TEST_F(SessionsSyncManagerTest, UpdatesAfterMixedMerge) {
AddTab(browser(), GURL("http://foo1"));
NavigateAndCommitActiveTab(GURL("http://foo2"));
std::string tag1 = "tag1";
syncer::SyncDataList foreign_data1;
std::vector<std::vector<SessionID::id_type> > meta1_reference;
sync_pb::SessionSpecifics meta1;
SessionID::id_type n1[] = {5, 10, 13, 17};
std::vector<SessionID::id_type> tab_list1(n1, n1 + arraysize(n1));
meta1_reference.push_back(tab_list1);
std::vector<sync_pb::SessionSpecifics> tabs1;
meta1 = helper()->BuildForeignSession(tag1, tab_list1, &tabs1);
sync_pb::EntitySpecifics entity;
entity.mutable_session()->CopyFrom(meta1);
foreign_data1.push_back(SyncData::CreateRemoteData(
1, entity, base::Time()));
AddTabsToSyncDataList(tabs1, &foreign_data1);
syncer::SyncChangeList output1;
InitWithSyncDataTakeOutput(foreign_data1, &output1);
ASSERT_EQ(4U, output1.size());
SessionID::id_type tab_nums2[] = {7, 15, 18, 20};
std::vector<SessionID::id_type> tab_list2(
tab_nums2, tab_nums2 + arraysize(tab_nums2));
meta1_reference.push_back(tab_list2);
helper()->AddWindowSpecifics(1, tab_list2, &meta1);
std::vector<sync_pb::SessionSpecifics> tabs2;
tabs2.resize(tab_list2.size());
for (size_t i = 0; i < tab_list2.size(); ++i) {
helper()->BuildTabSpecifics(tag1, 0, tab_list2[i], &tabs2[i]);
}
syncer::SyncChangeList changes;
changes.push_back(MakeRemoteChange(1, meta1, SyncChange::ACTION_UPDATE));
AddTabsToChangeList(tabs2, SyncChange::ACTION_ADD, &changes);
manager()->ProcessSyncChanges(FROM_HERE, changes);
changes.clear();
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
ASSERT_EQ(4U, foreign_sessions[0]->windows.find(0)->second->tabs.size());
ASSERT_EQ(4U, foreign_sessions[0]->windows.find(1)->second->tabs.size());
helper()->VerifySyncedSession(tag1, meta1_reference, *(foreign_sessions[0]));
std::string tag2 = "tag2";
SessionID::id_type n2[] = {107, 115};
std::vector<SessionID::id_type> tag2_tab_list(n2, n2 + arraysize(n2));
std::vector<sync_pb::SessionSpecifics> tag2_tabs;
sync_pb::SessionSpecifics meta2(helper()->BuildForeignSession(
tag2, tag2_tab_list, &tag2_tabs));
changes.push_back(MakeRemoteChange(100, meta2, SyncChange::ACTION_ADD));
AddTabsToChangeList(tag2_tabs, SyncChange::ACTION_ADD, &changes);
manager()->ProcessSyncChanges(FROM_HERE, changes);
changes.clear();
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
std::vector<std::vector<SessionID::id_type> > meta2_reference;
meta2_reference.push_back(tag2_tab_list);
ASSERT_EQ(2U, foreign_sessions.size());
ASSERT_EQ(2U, foreign_sessions[1]->windows.find(0)->second->tabs.size());
helper()->VerifySyncedSession(tag2, meta2_reference, *(foreign_sessions[1]));
foreign_sessions.clear();
meta1_reference[0].pop_back();
tab_list1.pop_back();
sync_pb::SessionWindow* win = meta1.mutable_header()->mutable_window(0);
win->clear_tab();
for (std::vector<int>::const_iterator iter = tab_list1.begin();
iter != tab_list1.end(); ++iter) {
win->add_tab(*iter);
}
syncer::SyncChangeList removal;
removal.push_back(MakeRemoteChange(1, meta1, SyncChange::ACTION_UPDATE));
AddTabsToChangeList(tabs1, SyncChange::ACTION_UPDATE, &removal);
manager()->ProcessSyncChanges(FROM_HERE, removal);
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(2U, foreign_sessions.size());
ASSERT_EQ(3U, foreign_sessions[0]->windows.find(0)->second->tabs.size());
helper()->VerifySyncedSession(tag1, meta1_reference, *(foreign_sessions[0]));
}
TEST_F(SessionsSyncManagerTest, DeleteForeignSession) {
InitWithNoSyncData();
std::string tag = "tag1";
syncer::SyncChangeList changes;
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_FALSE(manager()->GetAllForeignSessions(&foreign_sessions));
manager()->DeleteForeignSessionInternal(tag, &changes);
ASSERT_FALSE(manager()->GetAllForeignSessions(&foreign_sessions));
EXPECT_TRUE(changes.empty());
std::vector<sync_pb::SessionSpecifics> tabs;
SessionID::id_type n1[] = {5, 10, 13, 17};
std::vector<SessionID::id_type> tab_nums1(n1, n1 + arraysize(n1));
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag, tab_nums1, &tabs));
manager()->UpdateTrackerWithForeignSession(meta, base::Time());
for (std::vector<sync_pb::SessionSpecifics>::iterator iter = tabs.begin();
iter != tabs.end(); ++iter) {
manager()->UpdateTrackerWithForeignSession(*iter, base::Time());
}
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
manager()->DeleteForeignSessionInternal(tag, &changes);
EXPECT_FALSE(manager()->GetAllForeignSessions(&foreign_sessions));
EXPECT_EQ(5U, changes.size());
std::set<std::string> expected_tags(&tag, &tag + 1);
for (int i = 0; i < 5; i++)
expected_tags.insert(TabNodePool2::TabIdToTag(tag, i));
for (int i = 0; i < 5; i++) {
SCOPED_TRACE(changes[i].ToString());
EXPECT_TRUE(changes[i].IsValid());
EXPECT_EQ(SyncChange::ACTION_DELETE, changes[i].change_type());
EXPECT_TRUE(changes[i].sync_data().IsValid());
EXPECT_EQ(1U,
expected_tags.erase(
syncer::SyncDataLocal(changes[i].sync_data()).GetTag()));
}
}
TEST_F(SessionsSyncManagerTest, WriteForeignSessionToNodeTabsFirst) {
InitWithNoSyncData();
std::string tag = "tag1";
SessionID::id_type nums1[] = {5, 10, 13, 17};
std::vector<sync_pb::SessionSpecifics> tabs1;
std::vector<SessionID::id_type> tab_list1 (nums1, nums1 + arraysize(nums1));
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag, tab_list1, &tabs1));
syncer::SyncChangeList adds;
AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &adds);
adds.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
manager()->ProcessSyncChanges(FROM_HERE, adds);
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
std::vector<std::vector<SessionID::id_type> > session_reference;
session_reference.push_back(tab_list1);
helper()->VerifySyncedSession(tag, session_reference, *(foreign_sessions[0]));
}
TEST_F(SessionsSyncManagerTest, WriteForeignSessionToNodeMissingTabs) {
InitWithNoSyncData();
std::string tag = "tag1";
SessionID::id_type nums1[] = {5, 10, 13, 17};
std::vector<sync_pb::SessionSpecifics> tabs1;
std::vector<SessionID::id_type> tab_list1 (nums1, nums1 + arraysize(nums1));
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag, tab_list1, &tabs1));
SessionID::id_type tab_nums2[] = {7, 15, 18, 20};
std::vector<SessionID::id_type> tab_list2(
tab_nums2, tab_nums2 + arraysize(tab_nums2));
helper()->AddWindowSpecifics(1, tab_list2, &meta);
std::vector<sync_pb::SessionSpecifics> tabs2;
tabs2.resize(2);
for (size_t i = 0; i < 2; ++i) {
helper()->BuildTabSpecifics(tag, 0, tab_list2[i], &tabs2[i]);
}
syncer::SyncChangeList changes;
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
AddTabsToChangeList(tabs2, SyncChange::ACTION_ADD, &changes);
manager()->ProcessSyncChanges(FROM_HERE, changes);
changes.clear();
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
ASSERT_EQ(2U, foreign_sessions[0]->windows.size());
ASSERT_EQ(4U, foreign_sessions[0]->windows.find(0)->second->tabs.size());
ASSERT_EQ(4U, foreign_sessions[0]->windows.find(1)->second->tabs.size());
meta.mutable_header()->clear_window();
helper()->AddWindowSpecifics(0, tab_list1, &meta);
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_UPDATE));
manager()->ProcessSyncChanges(FROM_HERE, changes);
foreign_sessions.clear();
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
ASSERT_EQ(1U, foreign_sessions[0]->windows.size());
std::vector<std::vector<SessionID::id_type> > session_reference;
session_reference.push_back(tab_list1);
helper()->VerifySyncedSession(tag, session_reference, *(foreign_sessions[0]));
}
TEST_F(SessionsSyncManagerTest, ProcessRemoteDeleteOfLocalSession) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
ASSERT_EQ(2U, out.size());
sync_pb::EntitySpecifics entity(out[0].sync_data().GetSpecifics());
SyncData d(SyncData::CreateRemoteData(1, entity, base::Time()));
SetSyncData(syncer::SyncDataList(&d, &d + 1));
out.clear();
syncer::SyncChangeList changes;
changes.push_back(
MakeRemoteChange(1, entity.session(), SyncChange::ACTION_DELETE));
manager()->ProcessSyncChanges(FROM_HERE, changes);
EXPECT_TRUE(manager()->local_tab_pool_out_of_sync_);
EXPECT_TRUE(out.empty());
const GURL foo1("http://foo/1");
AddTab(browser(), foo1);
EXPECT_FALSE(manager()->local_tab_pool_out_of_sync_);
ASSERT_EQ(4U, out.size());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
ASSERT_TRUE(out[0].sync_data().GetSpecifics().session().has_header());
EXPECT_EQ(SyncChange::ACTION_ADD, out[1].change_type());
int tab_node_id = out[1].sync_data().GetSpecifics().session().tab_node_id();
EXPECT_EQ(TabNodePool2::TabIdToTag(
manager()->current_machine_tag(), tab_node_id),
syncer::SyncDataLocal(out[1].sync_data()).GetTag());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type());
ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_tab());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[3].change_type());
ASSERT_TRUE(out[3].sync_data().GetSpecifics().session().has_header());
const sync_pb::SessionHeader& session_header =
out[3].sync_data().GetSpecifics().session().header();
ASSERT_EQ(1, session_header.window_size());
EXPECT_EQ(1, session_header.window(0).tab_size());
const sync_pb::SessionTab& tab1 =
out[2].sync_data().GetSpecifics().session().tab();
ASSERT_EQ(1, tab1.navigation_size());
EXPECT_EQ(foo1.spec(), tab1.navigation(0).virtual_url());
EXPECT_EQ(1U, manager()->local_tab_pool_.Capacity());
EXPECT_TRUE(manager()->local_tab_pool_.Empty());
SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
ASSERT_EQ(1U, tab_map.size());
int tab_id = out[2].sync_data().GetSpecifics().session().tab().tab_id();
EXPECT_EQ(tab_node_id, tab_map.find(tab_id)->second->tab_node_id());
}
TEST_F(SessionsSyncManagerTest, ProcessForeignDelete) {
InitWithNoSyncData();
SessionID::id_type n[] = {5};
std::vector<sync_pb::SessionSpecifics> tabs1;
std::vector<SessionID::id_type> tab_list(n, n + arraysize(n));
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
"tag1", tab_list, &tabs1));
syncer::SyncChangeList changes;
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
manager()->ProcessSyncChanges(FROM_HERE, changes);
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
changes.clear();
foreign_sessions.clear();
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_DELETE));
manager()->ProcessSyncChanges(FROM_HERE, changes);
EXPECT_FALSE(manager()->GetAllForeignSessions(&foreign_sessions));
}
TEST_F(SessionsSyncManagerTest, SaveUnassociatedNodesForReassociation) {
syncer::SyncChangeList changes;
InitWithNoSyncData();
std::string local_tag = manager()->current_machine_tag();
manager()->local_tab_pool_.GetFreeTabNode(&changes);
sync_pb::EntitySpecifics entity(changes[0].sync_data().GetSpecifics());
entity.mutable_session()->mutable_tab()->set_tab_id(1);
SyncData d(SyncData::CreateRemoteData(1, entity, base::Time()));
syncer::SyncDataList in(&d, &d + 1);
changes.clear();
SessionsSyncManager manager2(profile(), this, NewDummyRouter());
syncer::SyncMergeResult result = manager2.MergeDataAndStartSyncing(
syncer::SESSIONS, in,
scoped_ptr<syncer::SyncChangeProcessor>(
new TestSyncProcessorStub(&changes)),
scoped_ptr<syncer::SyncErrorFactory>(
new syncer::SyncErrorFactoryMock()));
ASSERT_FALSE(result.error().IsSet());
EXPECT_TRUE(FilterOutLocalHeaderChanges(&changes)->empty());
}
TEST_F(SessionsSyncManagerTest, MergeDeletesCorruptNode) {
syncer::SyncChangeList changes;
InitWithNoSyncData();
std::string local_tag = manager()->current_machine_tag();
int tab_node_id = manager()->local_tab_pool_.GetFreeTabNode(&changes);
SyncData d(SyncData::CreateRemoteData(
1, changes[0].sync_data().GetSpecifics(), base::Time()));
syncer::SyncDataList in(&d, &d + 1);
changes.clear();
TearDown();
SetUp();
InitWithSyncDataTakeOutput(in, &changes);
EXPECT_EQ(1U, FilterOutLocalHeaderChanges(&changes)->size());
EXPECT_EQ(SyncChange::ACTION_DELETE, changes[0].change_type());
EXPECT_EQ(TabNodePool2::TabIdToTag(local_tag, tab_node_id),
syncer::SyncDataLocal(changes[0].sync_data()).GetTag());
}
TEST_F(SessionsSyncManagerTest, AssociateWindowsDontReloadTabs) {
syncer::SyncChangeList out;
AddTab(browser(), GURL("chrome://preferences/"));
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
ASSERT_EQ(2U, out.size());
EXPECT_EQ(
0,
out[1].sync_data().GetSpecifics().session().header().window_size());
out.clear();
NavigateAndCommitActiveTab(GURL("http://foo2"));
EXPECT_EQ(3U, out.size());
EXPECT_TRUE(
StartsWithASCII(syncer::SyncDataLocal(out[0].sync_data()).GetTag(),
manager()->current_machine_tag(),
true));
EXPECT_EQ(manager()->current_machine_tag(),
out[0].sync_data().GetSpecifics().session().session_tag());
EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
EXPECT_TRUE(
StartsWithASCII(syncer::SyncDataLocal(out[1].sync_data()).GetTag(),
manager()->current_machine_tag(),
true));
EXPECT_EQ(manager()->current_machine_tag(),
out[1].sync_data().GetSpecifics().session().session_tag());
EXPECT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type());
EXPECT_TRUE(out[2].IsValid());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type());
const SyncData data(out[2].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data).GetTag());
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
EXPECT_TRUE(specifics.has_header());
const sync_pb::SessionHeader& header_s = specifics.header();
EXPECT_EQ(1, header_s.window_size());
EXPECT_EQ(1, header_s.window(0).tab_size());
}
TEST_F(SessionsSyncManagerTest, OnLocalTabModified) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
ASSERT_FALSE(manager()->current_machine_tag().empty());
ASSERT_EQ(2U, out.size());
sync_pb::EntitySpecifics header(out[0].sync_data().GetSpecifics());
out.clear();
const GURL foo1("http://foo/1");
const GURL foo2("http://foo/2");
const GURL bar1("http://bar/1");
const GURL bar2("http://bar/2");
AddTab(browser(), foo1);
NavigateAndCommitActiveTab(foo2);
AddTab(browser(), bar1);
NavigateAndCommitActiveTab(bar2);
ASSERT_EQ(12U, out.size());
for (int i = 0; i < 12; i++) {
SCOPED_TRACE(i);
EXPECT_TRUE(out[i].IsValid());
const SyncData data(out[i].sync_data());
EXPECT_TRUE(StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
manager()->current_machine_tag(), true));
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
if (i % 6 == 0) {
EXPECT_EQ(header.SerializeAsString(),
data.GetSpecifics().SerializeAsString());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data).GetTag());
} else if (i % 6 == 1) {
EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type());
EXPECT_EQ(TabNodePool2::TabIdToTag(
manager()->current_machine_tag(),
data.GetSpecifics().session().tab_node_id()),
syncer::SyncDataLocal(data).GetTag());
} else if (i % 6 == 2) {
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
EXPECT_EQ(TabNodePool2::TabIdToTag(
manager()->current_machine_tag(),
data.GetSpecifics().session().tab_node_id()),
syncer::SyncDataLocal(data).GetTag());
ASSERT_TRUE(specifics.has_tab());
} else if (i % 6 == 3) {
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
EXPECT_TRUE(specifics.has_header());
} else if (i % 6 == 4) {
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
EXPECT_EQ(TabNodePool2::TabIdToTag(
manager()->current_machine_tag(),
data.GetSpecifics().session().tab_node_id()),
syncer::SyncDataLocal(data).GetTag());
ASSERT_TRUE(specifics.has_tab());
} else if (i % 6 == 5) {
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
ASSERT_TRUE(specifics.has_header());
header = data.GetSpecifics();
}
}
const sync_pb::SessionHeader& session_header = header.session().header();
ASSERT_EQ(1, session_header.window_size());
EXPECT_EQ(2, session_header.window(0).tab_size());
const sync_pb::SessionTab& tab1_1 =
out[2].sync_data().GetSpecifics().session().tab();
ASSERT_EQ(1, tab1_1.navigation_size());
EXPECT_EQ(foo1.spec(), tab1_1.navigation(0).virtual_url());
const sync_pb::SessionTab& tab1_2 =
out[4].sync_data().GetSpecifics().session().tab();
ASSERT_EQ(2, tab1_2.navigation_size());
EXPECT_EQ(foo1.spec(), tab1_2.navigation(0).virtual_url());
EXPECT_EQ(foo2.spec(), tab1_2.navigation(1).virtual_url());
const sync_pb::SessionTab& tab2_1 =
out[8].sync_data().GetSpecifics().session().tab();
ASSERT_EQ(1, tab2_1.navigation_size());
EXPECT_EQ(bar1.spec(), tab2_1.navigation(0).virtual_url());
const sync_pb::SessionTab& tab2_2 =
out[10].sync_data().GetSpecifics().session().tab();
ASSERT_EQ(2, tab2_2.navigation_size());
EXPECT_EQ(bar1.spec(), tab2_2.navigation(0).virtual_url());
EXPECT_EQ(bar2.spec(), tab2_2.navigation(1).virtual_url());
}
TEST_F(SessionsSyncManagerTest, MergeLocalSessionExistingTabs) {
AddTab(browser(), GURL("http://foo1"));
NavigateAndCommitActiveTab(GURL("http://foo2"));
AddTab(browser(), GURL("http://bar1"));
NavigateAndCommitActiveTab(GURL("http://bar2"));
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
ASSERT_EQ(6U, out.size());
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_FALSE(manager()->GetAllForeignSessions(&foreign_sessions));
EXPECT_TRUE(out[0].IsValid());
EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
const SyncData data(out[0].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data).GetTag());
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
EXPECT_TRUE(specifics.has_header());
const sync_pb::SessionHeader& header_s = specifics.header();
EXPECT_TRUE(header_s.has_device_type());
EXPECT_EQ(GetLocalDeviceInfo()->client_name(), header_s.client_name());
EXPECT_EQ(0, header_s.window_size());
for (int i = 1; i < 5; i++) {
EXPECT_TRUE(out[i].IsValid());
const SyncData data(out[i].sync_data());
EXPECT_TRUE(StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
manager()->current_machine_tag(), true));
const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
if (i % 2 == 1) {
EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type());
} else {
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
EXPECT_TRUE(specifics.has_tab());
}
}
EXPECT_TRUE(out[5].IsValid());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type());
const SyncData data_2(out[5].sync_data());
EXPECT_EQ(manager()->current_machine_tag(),
syncer::SyncDataLocal(data_2).GetTag());
const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session());
EXPECT_EQ(manager()->current_machine_tag(), specifics2.session_tag());
EXPECT_TRUE(specifics2.has_header());
const sync_pb::SessionHeader& header_s2 = specifics2.header();
EXPECT_EQ(1, header_s2.window_size());
SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
ASSERT_EQ(2U, tab_map.size());
SessionsSyncManager::TabLinksMap::iterator iter = tab_map.begin();
ASSERT_EQ(2, iter->second->tab()->GetEntryCount());
EXPECT_EQ(GURL("http://foo1"), iter->second->tab()->
GetEntryAtIndex(0)->GetVirtualURL());
EXPECT_EQ(GURL("http://foo2"), iter->second->tab()->
GetEntryAtIndex(1)->GetVirtualURL());
iter++;
ASSERT_EQ(2, iter->second->tab()->GetEntryCount());
EXPECT_EQ(GURL("http://bar1"), iter->second->tab()->
GetEntryAtIndex(0)->GetVirtualURL());
EXPECT_EQ(GURL("http://bar2"), iter->second->tab()->
GetEntryAtIndex(1)->GetVirtualURL());
}
TEST_F(SessionsSyncManagerTest, DoGarbageCollection) {
std::string tag1 = "tag1";
SessionID::id_type n1[] = {5, 10, 13, 17};
std::vector<SessionID::id_type> tab_list1(n1, n1 + arraysize(n1));
std::vector<sync_pb::SessionSpecifics> tabs1;
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag1, tab_list1, &tabs1));
std::string tag2 = "tag2";
SessionID::id_type n2[] = {8, 15, 18, 20};
std::vector<SessionID::id_type> tab_list2(n2, n2 + arraysize(n2));
std::vector<sync_pb::SessionSpecifics> tabs2;
sync_pb::SessionSpecifics meta2(helper()->BuildForeignSession(
tag2, tab_list2, &tabs2));
base::Time tag1_time = base::Time::Now() - base::TimeDelta::FromDays(21);
base::Time tag2_time = base::Time::Now() - base::TimeDelta::FromDays(5);
syncer::SyncDataList foreign_data;
sync_pb::EntitySpecifics entity1, entity2;
entity1.mutable_session()->CopyFrom(meta);
entity2.mutable_session()->CopyFrom(meta2);
foreign_data.push_back(SyncData::CreateRemoteData(1, entity1, tag1_time));
foreign_data.push_back(SyncData::CreateRemoteData(1, entity2, tag2_time));
AddTabsToSyncDataList(tabs1, &foreign_data);
AddTabsToSyncDataList(tabs2, &foreign_data);
syncer::SyncChangeList output;
InitWithSyncDataTakeOutput(foreign_data, &output);
ASSERT_EQ(2U, output.size());
output.clear();
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(2U, foreign_sessions.size());
foreign_sessions.clear();
manager()->DoGarbageCollection();
ASSERT_EQ(5U, output.size());
EXPECT_EQ(SyncChange::ACTION_DELETE, output[0].change_type());
const SyncData data(output[0].sync_data());
EXPECT_EQ(tag1, syncer::SyncDataLocal(data).GetTag());
for (int i = 1; i < 5; i++) {
EXPECT_EQ(SyncChange::ACTION_DELETE, output[i].change_type());
const SyncData data(output[i].sync_data());
EXPECT_EQ(TabNodePool2::TabIdToTag(tag1, i),
syncer::SyncDataLocal(data).GetTag());
}
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
std::vector<std::vector<SessionID::id_type> > session_reference;
session_reference.push_back(tab_list2);
helper()->VerifySyncedSession(tag2, session_reference,
*(foreign_sessions[0]));
}
TEST_F(SessionsSyncManagerTest, GarbageCollectionHonoursUpdate) {
std::string tag1 = "tag1";
SessionID::id_type n1[] = {5, 10, 13, 17};
std::vector<SessionID::id_type> tab_list1(n1, n1 + arraysize(n1));
std::vector<sync_pb::SessionSpecifics> tabs1;
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag1, tab_list1, &tabs1));
syncer::SyncDataList foreign_data;
sync_pb::EntitySpecifics entity1;
base::Time tag1_time = base::Time::Now() - base::TimeDelta::FromDays(21);
entity1.mutable_session()->CopyFrom(meta);
foreign_data.push_back(SyncData::CreateRemoteData(1, entity1, tag1_time));
AddTabsToSyncDataList(tabs1, &foreign_data);
syncer::SyncChangeList output;
InitWithSyncDataTakeOutput(foreign_data, &output);
ASSERT_EQ(2U, output.size());
sync_pb::EntitySpecifics update_entity;
update_entity.mutable_session()->CopyFrom(tabs1[0]);
syncer::SyncChangeList changes;
changes.push_back(syncer::SyncChange(
FROM_HERE,
SyncChange::ACTION_UPDATE,
syncer::SyncData::CreateRemoteData(1, update_entity,
base::Time::Now())));
manager()->ProcessSyncChanges(FROM_HERE, changes);
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
foreign_sessions.clear();
manager()->DoGarbageCollection();
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
std::vector<std::vector<SessionID::id_type> > session_reference;
session_reference.push_back(tab_list1);
helper()->VerifySyncedSession(
tag1, session_reference, *(foreign_sessions[0]));
}
TEST_F(SessionsSyncManagerTest, CheckPrerenderedWebContentsSwap) {
AddTab(browser(), GURL("http://foo1"));
NavigateAndCommitActiveTab(GURL("http://foo2"));
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
ASSERT_EQ(4U, out.size());
scoped_ptr<content::WebContents> old_web_contents;
old_web_contents.reset(browser()->tab_strip_model()->GetActiveWebContents());
WebContents* new_web_contents = WebContents::CreateWithSessionStorage(
WebContents::CreateParams(profile()),
old_web_contents->GetController().GetSessionStorageNamespaceMap());
SessionTabHelper::CreateForWebContents(new_web_contents);
TabContentsSyncedTabDelegate::CreateForWebContents(new_web_contents);
new_web_contents->GetController()
.CopyStateFrom(old_web_contents->GetController());
int index = browser()->tab_strip_model()->GetIndexOfWebContents(
old_web_contents.get());
browser()->tab_strip_model()->ReplaceWebContentsAt(index, new_web_contents);
ASSERT_EQ(9U, out.size());
EXPECT_EQ(SyncChange::ACTION_ADD, out[4].change_type());
EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type());
NavigateAndCommitActiveTab(GURL("http://bar2"));
old_web_contents.reset();
NavigateAndCommitActiveTab(GURL("http://bar3"));
AddTab(browser(), GURL("http://bar4"));
NavigateAndCommitActiveTab(GURL("http://bar5"));
ASSERT_EQ(19U, out.size());
}
namespace {
class SessionNotificationObserver : public content::NotificationObserver {
public:
SessionNotificationObserver() : notified_of_update_(false),
notified_of_refresh_(false) {
registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
content::NotificationService::AllSources());
}
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE {
switch (type) {
case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED:
notified_of_update_ = true;
break;
case chrome::NOTIFICATION_SYNC_REFRESH_LOCAL:
notified_of_refresh_ = true;
break;
default:
NOTREACHED();
break;
}
}
bool notified_of_update() const { return notified_of_update_; }
bool notified_of_refresh() const { return notified_of_refresh_; }
void Reset() {
notified_of_update_ = false;
notified_of_refresh_ = false;
}
private:
content::NotificationRegistrar registrar_;
bool notified_of_update_;
bool notified_of_refresh_;
};
}
TEST_F(SessionsSyncManagerTest, NotifiedOfUpdates) {
SessionNotificationObserver observer;
ASSERT_FALSE(observer.notified_of_update());
InitWithNoSyncData();
SessionID::id_type n[] = {5};
std::vector<sync_pb::SessionSpecifics> tabs1;
std::vector<SessionID::id_type> tab_list(n, n + arraysize(n));
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
"tag1", tab_list, &tabs1));
syncer::SyncChangeList changes;
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
manager()->ProcessSyncChanges(FROM_HERE, changes);
EXPECT_TRUE(observer.notified_of_update());
changes.clear();
observer.Reset();
AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
manager()->ProcessSyncChanges(FROM_HERE, changes);
EXPECT_TRUE(observer.notified_of_update());
changes.clear();
observer.Reset();
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_DELETE));
manager()->ProcessSyncChanges(FROM_HERE, changes);
EXPECT_TRUE(observer.notified_of_update());
}
TEST_F(SessionsSyncManagerTest, NotifiedOfLocalRemovalOfForeignSession) {
InitWithNoSyncData();
const std::string tag("tag1");
SessionID::id_type n[] = {5};
std::vector<sync_pb::SessionSpecifics> tabs1;
std::vector<SessionID::id_type> tab_list(n, n + arraysize(n));
sync_pb::SessionSpecifics meta(helper()->BuildForeignSession(
tag, tab_list, &tabs1));
syncer::SyncChangeList changes;
changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
manager()->ProcessSyncChanges(FROM_HERE, changes);
SessionNotificationObserver observer;
ASSERT_FALSE(observer.notified_of_update());
manager()->DeleteForeignSession(tag);
ASSERT_TRUE(observer.notified_of_update());
}
#if defined(OS_ANDROID) || defined(OS_IOS)
TEST_F(SessionsSyncManagerTest, NotifiedOfRefresh) {
SessionNotificationObserver observer;
ASSERT_FALSE(observer.notified_of_refresh());
InitWithNoSyncData();
AddTab(browser(), GURL("http://foo1"));
EXPECT_FALSE(observer.notified_of_refresh());
NavigateAndCommitActiveTab(GURL("chrome://newtab/#open_tabs"));
EXPECT_TRUE(observer.notified_of_refresh());
}
#endif
}