Index: components/sync_sessions/sessions_sync_manager_unittest.cc |
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc |
index 7479a1833c5add313f4e0c0555dd263f569eba93..bc22ca1151ece4a41a006121d3f81fb5618ddbd7 100644 |
--- a/components/sync_sessions/sessions_sync_manager_unittest.cc |
+++ b/components/sync_sessions/sessions_sync_manager_unittest.cc |
@@ -243,7 +243,7 @@ class TestSyncedTabDelegate : public SyncedTabDelegate { |
private: |
int current_entry_index_ = -1; |
bool is_supervised_ = false; |
- int sync_id_ = -1; |
+ int sync_id_ = kInvalidTabID; |
SessionID tab_id_; |
SessionID window_id_; |
std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>> |
@@ -328,7 +328,7 @@ class PlaceholderTabDelegate : public SyncedTabDelegate { |
private: |
SessionID::id_type session_id_; |
- int sync_id_; |
+ int sync_id_ = kInvalidTabID; |
}; |
class TestSyncedWindowDelegate : public SyncedWindowDelegate { |
@@ -358,6 +358,10 @@ class TestSyncedWindowDelegate : public SyncedWindowDelegate { |
return false; |
} |
+ void OverrideWindowTypeToCustomTab() { |
+ window_type_ = sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB; |
+ } |
+ |
SyncedTabDelegate* GetTabAt(int index) const override { |
if (tab_delegates_.find(index) != tab_delegates_.end()) |
return tab_delegates_.find(index)->second; |
@@ -387,6 +391,8 @@ class TestSyncedWindowDelegate : public SyncedWindowDelegate { |
SessionID window_id_; |
sync_pb::SessionWindow_BrowserType window_type_ = |
sync_pb::SessionWindow_BrowserType_TYPE_TABBED; |
+ std::map<int, SyncedTabDelegate*> tab_overrides_; |
+ std::map<int, SessionID::id_type> tab_id_overrides_; |
}; |
class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter { |
@@ -410,6 +416,8 @@ class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter { |
delegates_[delegate->GetSessionId()] = delegate; |
} |
+ void ClearSyncedWindowDelegates() { delegates_.clear(); } |
+ |
private: |
SyncedWindowDelegateMap delegates_; |
}; |
@@ -469,7 +477,7 @@ class DummyRouter : public LocalSessionEventRouter { |
void StartRoutingTo(LocalSessionEventHandler* handler) override { |
handler_ = handler; |
} |
- void Stop() override {} |
+ void Stop() override { handler_ = nullptr; } |
void NotifyNav(SyncedTabDelegate* tab) { |
if (handler_) |
@@ -716,12 +724,45 @@ class SessionsSyncManagerTest : public testing::Test { |
NavigateTab(delegate, url, base::Time()); |
} |
+ void ResetWindows() { |
+ window_getter_.ClearSyncedWindowDelegates(); |
+ windows_.clear(); |
+ } |
+ |
TestSyncedWindowDelegate* AddWindow() { |
windows_.push_back(base::MakeUnique<TestSyncedWindowDelegate>()); |
window_getter_.AddSyncedWindowDelegate(windows_.back().get()); |
return windows_.back().get(); |
} |
+ syncer::SyncDataList GetDataFromChanges( |
+ const syncer::SyncChangeList& changes) { |
+ syncer::SyncDataList data_list; |
+ for (auto& change : changes) { |
+ syncer::SyncDataLocal change_data(change.sync_data()); |
+ bool found = false; |
+ for (auto&& data : data_list) { |
+ syncer::SyncDataLocal local_data(data); |
+ if (local_data.GetTag() == change_data.GetTag()) { |
+ data = change.sync_data(); |
+ found = true; |
+ break; |
+ } |
+ } |
+ if (!found) |
+ data_list.push_back(change_data); |
+ } |
+ return data_list; |
+ } |
+ |
+ syncer::SyncDataList ConvertToRemote(const syncer::SyncDataList& in) { |
+ syncer::SyncDataList out; |
+ for (auto& data : in) { |
+ out.push_back(CreateRemoteData(data.GetSpecifics())); |
+ } |
+ return out; |
+ } |
+ |
private: |
std::unique_ptr<syncer::FakeSyncClient> sync_client_; |
std::unique_ptr<SyncSessionsClientShim> sessions_client_shim_; |
@@ -737,41 +778,6 @@ class SessionsSyncManagerTest : public testing::Test { |
std::unique_ptr<LocalDeviceInfoProviderMock> local_device_; |
}; |
-// Test that the SyncSessionManager can properly fill in a SessionHeader. |
-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 translation between protobuf types and chrome session types. |
-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); |
- |
- SyncedSession* session = manager()->session_tracker_.GetSession(kTag1); |
- manager()->session_tracker_.PutWindowInSession(kTag1, 0); |
- manager()->BuildSyncedSessionFromSpecifics(kTag1, window_s, base::Time(), |
- session->windows[0].get()); |
- ASSERT_EQ(1U, session->windows[0]->wrapped_window.tabs.size()); |
- ASSERT_EQ(1, session->windows[0]->wrapped_window.selected_tab_index); |
- ASSERT_EQ(sessions::SessionWindow::TYPE_TABBED, |
- session->windows[0]->wrapped_window.type); |
- ASSERT_EQ(1U, manager()->session_tracker_.num_synced_sessions()); |
- ASSERT_EQ(1U, manager()->session_tracker_.num_synced_tabs(kTag1)); |
-} |
- |
-// Populate the fake tab delegate with some data and navigation |
// entries and make sure that setting a SessionTab from it preserves |
// those entries (and clobbers any existing data). |
TEST_F(SessionsSyncManagerTest, SetSessionTabFromDelegate) { |
@@ -952,6 +958,117 @@ TEST_F(SessionsSyncManagerTest, MergeLocalSessionNoTabs) { |
EXPECT_TRUE(out[0].sync_data().GetSpecifics().session().has_header()); |
} |
+// Ensure that tabbed windows from a previous session are preserved if no |
+// windows are present on startup. |
+TEST_F(SessionsSyncManagerTest, PreserveTabbedDataNoWindows) { |
+ syncer::SyncDataList in; |
+ syncer::SyncChangeList out; |
+ |
+ // Set up one tab and start sync with it. |
+ TestSyncedTabDelegate* tab = AddTab(AddWindow()->GetSessionId(), kFoo1); |
+ NavigateTab(tab, kFoo2); |
+ InitWithSyncDataTakeOutput(in, &out); |
+ |
+ // There should be two entities, a header and a tab. |
+ in = GetDataFromChanges(out); |
+ out.clear(); |
+ ASSERT_EQ(2U, in.size()); |
+ |
+ // Resync, using the previous sync data, but with no windows open now. |
+ manager()->StopSyncing(syncer::SESSIONS); |
+ ResetWindows(); |
+ InitWithSyncDataTakeOutput(ConvertToRemote(in), &out); |
+ |
+ // There should be two changes: the rewritten tab (to update the tab id), and |
+ // the rewritten header. |
+ ASSERT_TRUE(ChangeTypeMatches( |
+ out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE})); |
+ VerifyLocalTabChange(out[0], 2, kFoo2); |
+ VerifyLocalHeaderChange(out[1], 1, 1); |
+ |
+ // Verify the tab id of the restored tab is updated and consistent. |
+ int restored_tab_id = |
+ out[0].sync_data().GetSpecifics().session().tab().tab_id(); |
+ // SessionId should be rewritten on restore. |
+ ASSERT_NE(tab->GetSessionId(), restored_tab_id); |
+ ASSERT_EQ( |
+ restored_tab_id, |
+ out[1].sync_data().GetSpecifics().session().header().window(0).tab(0)); |
+} |
+ |
+// Ensure that tabbed windows from a previous session are preserved if only |
+// transient windows are present at startup. |
+TEST_F(SessionsSyncManagerTest, PreserveTabbedDataCustomTab) { |
+ syncer::SyncDataList in; |
+ syncer::SyncChangeList out; |
+ |
+ // Set up one tab and start sync with it. |
+ TestSyncedWindowDelegate* window = AddWindow(); |
+ TestSyncedTabDelegate* tab = AddTab(window->GetSessionId(), kFoo1); |
+ NavigateTab(tab, kFoo2); |
+ InitWithSyncDataTakeOutput(in, &out); |
+ |
+ // There should be two entities, a header and a tab. |
+ in = GetDataFromChanges(out); |
+ out.clear(); |
+ ASSERT_EQ(2U, in.size()); |
+ |
+ // Resync, using the previous sync data, but with only a custom tab open. |
+ manager()->StopSyncing(syncer::SESSIONS); |
+ window->OverrideWindowTypeToCustomTab(); |
+ SessionID new_window_id; |
+ window->OverrideWindowId(new_window_id.id()); |
+ std::unique_ptr<TestSyncedTabDelegate> custom_tab = |
+ base::MakeUnique<TestSyncedTabDelegate>(); |
+ NavigateTab(custom_tab.get(), kBar1); |
+ window->OverrideTabAt(0, custom_tab.get()); |
+ InitWithSyncDataTakeOutput(ConvertToRemote(in), &out); |
+ |
+ // The previous session should be preserved, and the transient window should |
+ // be synced as a new transient window. This means that the original tab |
+ // node will be updated with its new tab id, a new tab node will be created, |
+ // and the header will be updated to reflect the two windows and two tabs. |
+ ASSERT_TRUE( |
+ ChangeTypeMatches(out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_ADD, |
+ SyncChange::ACTION_UPDATE})); |
+ VerifyLocalTabChange(out[0], 2, kFoo2); |
+ VerifyLocalTabChange(out[1], 1, kBar1); |
+ VerifyLocalHeaderChange(out[2], 2, 2); |
+ |
+ // The two windows should have different window types. |
+ ASSERT_EQ(sync_pb::SessionWindow::TYPE_CUSTOM_TAB, out[2] |
+ .sync_data() |
+ .GetSpecifics() |
+ .session() |
+ .header() |
+ .window(0) |
+ .browser_type()); |
+ ASSERT_EQ(sync_pb::SessionWindow::TYPE_TABBED, out[2] |
+ .sync_data() |
+ .GetSpecifics() |
+ .session() |
+ .header() |
+ .window(1) |
+ .browser_type()); |
+ |
+ // Verify the tab id of the restored tab is updated and consistent. |
+ int restored_tab_id = |
+ out[0].sync_data().GetSpecifics().session().tab().tab_id(); |
+ // SessionId should be rewritten on restore. |
+ ASSERT_NE(tab->GetSessionId(), restored_tab_id); |
+ ASSERT_EQ( |
+ restored_tab_id, |
+ out[2].sync_data().GetSpecifics().session().header().window(1).tab(0)); |
+ |
+ // Verify the tab id of the custom tab is consistent. |
+ int custom_tab_id = |
+ out[1].sync_data().GetSpecifics().session().tab().tab_id(); |
+ ASSERT_EQ(custom_tab->GetSessionId(), custom_tab_id); |
+ ASSERT_EQ( |
+ custom_tab_id, |
+ out[2].sync_data().GetSpecifics().session().header().window(0).tab(0)); |
+} |
+ |
// Tests MergeDataAndStartSyncing with sync data but no local data. |
TEST_F(SessionsSyncManagerTest, MergeWithInitialForeignSession) { |
std::vector<SessionID::id_type> tab_list1(std::begin(kTabIds1), |
@@ -1582,9 +1699,9 @@ TEST_F(SessionsSyncManagerTest, AssociationReusesNodes) { |
sync_pb::SessionSpecifics new_tab( |
changes[1].sync_data().GetSpecifics().session()); |
new_tab.set_tab_node_id(tab_node_id + 1); |
- in.push_back(CreateRemoteData(new_tab)); // New tab node. |
in.push_back(CreateRemoteData( |
changes[1].sync_data().GetSpecifics())); // Old tab node. |
+ in.push_back(CreateRemoteData(new_tab)); // New tab node. |
changes.clear(); |
// Reassociate (with the same single tab/window open). |
@@ -2396,12 +2513,12 @@ TEST_F(SessionsSyncManagerTest, PlaceholderConflictAcrossWindows) { |
// The tab entity will be overwritten twice. Once with the information for |
// tab 1 and then again with the information for tab 2. This will be followed |
- // by a header change reflecting both tabs. |
+ // by a header change reflecting only the final tab. |
ASSERT_TRUE( |
ChangeTypeMatches(out, |
{SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE, |
SyncChange::ACTION_UPDATE})); |
- VerifyLocalHeaderChange(out[2], 2, 2); |
+ VerifyLocalHeaderChange(out[2], 2, 1); |
VerifyLocalTabChange(out[0], 1, kFoo1); |
EXPECT_EQ(sync_id, out[0].sync_data().GetSpecifics().session().tab_node_id()); |
EXPECT_EQ(tab1->GetSessionId(), |