| // Copyright 2012 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/macros.h" |
| #include "base/run_loop.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "chrome/browser/sessions/session_service.h" |
| #include "chrome/browser/sessions/session_tab_helper.h" |
| #include "chrome/browser/sync/session_sync_service_factory.h" |
| #include "chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h" |
| #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" |
| #include "chrome/browser/sync/test/integration/session_hierarchy_match_checker.h" |
| #include "chrome/browser/sync/test/integration/sessions_helper.h" |
| #include "chrome/browser/sync/test/integration/sync_test.h" |
| #include "chrome/browser/sync/test/integration/typed_urls_helper.h" |
| #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/common/url_constants.h" |
| #include "components/history/core/browser/history_types.h" |
| #include "components/sessions/core/session_types.h" |
| #include "components/sync/base/time.h" |
| #include "components/sync/protocol/proto_value_conversions.h" |
| #include "components/sync/test/fake_server/sessions_hierarchy.h" |
| #include "components/sync_sessions/session_store.h" |
| #include "components/sync_sessions/session_sync_service.h" |
| #include "components/sync_sessions/session_sync_test_helper.h" |
| #include "components/sync_sessions/synced_session_tracker.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/mojo/window_open_disposition.mojom.h" |
| |
| namespace { |
| |
| using base::HistogramBase; |
| using base::HistogramSamples; |
| using base::HistogramTester; |
| using fake_server::SessionsHierarchy; |
| using sessions_helper::CheckInitialState; |
| using sessions_helper::CloseTab; |
| using sessions_helper::ExecJs; |
| using sessions_helper::GetLocalWindows; |
| using sessions_helper::GetSessionData; |
| using sessions_helper::MoveTab; |
| using sessions_helper::NavigateTab; |
| using sessions_helper::NavigateTabBack; |
| using sessions_helper::NavigateTabForward; |
| using sessions_helper::OpenTab; |
| using sessions_helper::OpenTabAtIndex; |
| using sessions_helper::OpenTabFromSourceIndex; |
| using sessions_helper::ScopedWindowMap; |
| using sessions_helper::SessionWindowMap; |
| using sessions_helper::SyncedSessionVector; |
| using sessions_helper::WaitForTabsToLoad; |
| using sessions_helper::WindowsMatch; |
| using sync_sessions::SessionSyncTestHelper; |
| using testing::IsEmpty; |
| using testing::UnorderedElementsAre; |
| using typed_urls_helper::GetUrlFromClient; |
| |
| static const char* kURL1 = "data:text/html,<html><title>Test</title></html>"; |
| static const char* kURL2 = "data:text/html,<html><title>Test2</title></html>"; |
| static const char* kURL3 = "data:text/html,<html><title>Test3</title></html>"; |
| static const char* kURL4 = "data:text/html,<html><title>Test4</title></html>"; |
| static const char* kBaseFragmentURL = |
| "data:text/html,<html><title>Fragment</title><body></body></html>"; |
| static const char* kSpecifiedFragmentURL = |
| "data:text/html,<html><title>Fragment</title><body></body></html>#fragment"; |
| |
| void ExpectUniqueSampleGE(const HistogramTester& histogram_tester, |
| const std::string& name, |
| HistogramBase::Sample sample, |
| HistogramBase::Count expected_inclusive_lower_bound) { |
| std::unique_ptr<HistogramSamples> samples = |
| histogram_tester.GetHistogramSamplesSinceCreation(name); |
| int sample_count = samples->GetCount(sample); |
| EXPECT_GE(sample_count, expected_inclusive_lower_bound); |
| EXPECT_EQ(sample_count, samples->TotalCount()); |
| } |
| |
| class IsHistoryURLSyncedChecker : public SingleClientStatusChangeChecker { |
| public: |
| IsHistoryURLSyncedChecker(const std::string& url, |
| fake_server::FakeServer* fake_server, |
| browser_sync::ProfileSyncService* service) |
| : SingleClientStatusChangeChecker(service), |
| url_(url), |
| fake_server_(fake_server) {} |
| |
| // StatusChangeChecker implementation. |
| bool IsExitConditionSatisfied() override { |
| return fake_server_->GetCommittedHistoryURLs().count(url_) != 0; |
| } |
| |
| std::string GetDebugMessage() const override { |
| return "Waiting for URLs to be commited to the server"; |
| } |
| |
| private: |
| const std::string url_; |
| fake_server::FakeServer* fake_server_; |
| }; |
| |
| class SingleClientSessionsSyncTest : public SyncTest { |
| public: |
| SingleClientSessionsSyncTest() : SyncTest(SINGLE_CLIENT) {} |
| ~SingleClientSessionsSyncTest() override {} |
| |
| void ExpectNavigationChain(const std::vector<GURL>& urls) { |
| ScopedWindowMap windows; |
| ASSERT_TRUE(GetLocalWindows(0, &windows)); |
| ASSERT_EQ(windows.begin()->second->wrapped_window.tabs.size(), 1u); |
| sessions::SessionTab* tab = |
| windows.begin()->second->wrapped_window.tabs[0].get(); |
| |
| int index = 0; |
| EXPECT_EQ(urls.size(), tab->navigations.size()); |
| for (auto it = tab->navigations.begin(); it != tab->navigations.end(); |
| ++it, ++index) { |
| EXPECT_EQ(urls[index], it->virtual_url()); |
| } |
| } |
| |
| // Block until the expected hierarchy is recorded on the FakeServer for |
| // profile 0. This will time out if the hierarchy is never |
| // recorded. |
| void WaitForHierarchyOnServer( |
| const fake_server::SessionsHierarchy& hierarchy) { |
| SessionHierarchyMatchChecker checker(hierarchy, GetSyncService(0), |
| GetFakeServer()); |
| EXPECT_TRUE(checker.Wait()); |
| } |
| |
| // Shortcut to call WaitForHierarchyOnServer for only |url| in a single |
| // window. |
| void WaitForURLOnServer(const GURL& url) { |
| WaitForHierarchyOnServer({{url.spec()}}); |
| } |
| |
| // Simulates receiving list of accounts in the cookie jar from ListAccounts |
| // endpoint. Adds |account_ids| into signed in accounts, notifies |
| // ProfileSyncService and waits for change to propagate to sync engine. |
| void UpdateCookieJarAccountsAndWait(std::vector<std::string> account_ids, |
| bool expected_cookie_jar_mismatch) { |
| std::vector<gaia::ListedAccount> accounts; |
| for (const auto& account_id : account_ids) { |
| gaia::ListedAccount signed_in_account; |
| signed_in_account.id = account_id; |
| accounts.push_back(signed_in_account); |
| } |
| base::RunLoop run_loop; |
| EXPECT_EQ(expected_cookie_jar_mismatch, |
| GetClient(0)->service()->HasCookieJarMismatch(accounts)); |
| GetClient(0)->service()->OnGaiaAccountsInCookieUpdatedWithCallback( |
| accounts, run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SingleClientSessionsSyncTest); |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| RequireProxyTabsForUiDelegate) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| sync_sessions::SessionSyncService* service = |
| SessionSyncServiceFactory::GetForProfile(GetProfile(0)); |
| |
| EXPECT_NE(nullptr, service->GetOpenTabsUIDelegate()); |
| ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::PROXY_TABS)); |
| EXPECT_EQ(nullptr, service->GetOpenTabsUIDelegate()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, Sanity) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| // Add a new session to client 0 and wait for it to sync. |
| ScopedWindowMap old_windows; |
| GURL url = GURL(kURL1); |
| ASSERT_TRUE(OpenTab(0, url)); |
| ASSERT_TRUE(GetLocalWindows(0, &old_windows)); |
| ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); |
| |
| // Get foreign session data from client 0. |
| SyncedSessionVector sessions; |
| ASSERT_FALSE(GetSessionData(0, &sessions)); |
| ASSERT_EQ(0U, sessions.size()); |
| |
| // Verify client didn't change. |
| ScopedWindowMap new_windows; |
| ASSERT_TRUE(GetLocalWindows(0, &new_windows)); |
| ASSERT_TRUE(WindowsMatch(old_windows, new_windows)); |
| |
| WaitForURLOnServer(url); |
| |
| EXPECT_THAT(GetFakeServer()->GetCommittedHistoryURLs(), |
| UnorderedElementsAre(kURL1)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, NavigateInTab) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| ASSERT_TRUE(OpenTab(0, GURL(kURL1))); |
| WaitForHierarchyOnServer(SessionsHierarchy({{kURL1}})); |
| |
| NavigateTab(0, GURL(kURL2)); |
| WaitForHierarchyOnServer(SessionsHierarchy({{kURL2}})); |
| |
| EXPECT_THAT(GetFakeServer()->GetCommittedHistoryURLs(), |
| UnorderedElementsAre(kURL1, kURL2)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| JavascriptHistoryReplaceState) { |
| // Executing Javascript requires HTTP pages with an origin. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| const std::string url1 = |
| embedded_test_server()->GetURL("/sync/simple.html").spec(); |
| const std::string url2 = |
| embedded_test_server()->GetURL("/replaced_history.html").spec(); |
| |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| ASSERT_TRUE(OpenTab(0, GURL(url1))); |
| WaitForHierarchyOnServer(SessionsHierarchy({{url1}})); |
| |
| ASSERT_TRUE( |
| ExecJs(/*browser_index=*/0, /*tab_index=*/0, |
| base::StringPrintf("history.replaceState({}, 'page 2', '%s')", |
| url2.c_str()))); |
| |
| WaitForHierarchyOnServer(SessionsHierarchy({{url2}})); |
| |
| // Fetch the tab from the server for further verification. |
| const std::vector<sync_pb::SyncEntity> entities = |
| GetFakeServer()->GetSyncEntitiesByModelType(syncer::SESSIONS); |
| const sync_pb::TabNavigation* tab_navigation = nullptr; |
| for (const sync_pb::SyncEntity& entity : entities) { |
| if (entity.specifics().session().tab().navigation_size() == 1 && |
| entity.specifics().session().tab().navigation(0).virtual_url() == |
| url2) { |
| tab_navigation = &entity.specifics().session().tab().navigation(0); |
| } |
| } |
| |
| ASSERT_NE(nullptr, tab_navigation); |
| EXPECT_TRUE(tab_navigation->has_replaced_navigation()); |
| EXPECT_EQ(url1, tab_navigation->replaced_navigation().first_committed_url()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| SessionsWithoutHistorySync) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| // If the user disables history sync on settings, but still enables tab sync, |
| // then sessions should be synced but the server should be able to tell the |
| // difference based on active datatypes. |
| ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::TYPED_URLS)); |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| ASSERT_TRUE(OpenTab(0, GURL(kURL1))); |
| WaitForHierarchyOnServer(SessionsHierarchy({{kURL1}})); |
| |
| NavigateTab(0, GURL(kURL2)); |
| WaitForHierarchyOnServer(SessionsHierarchy({{kURL2}})); |
| |
| EXPECT_THAT(GetFakeServer()->GetCommittedHistoryURLs(), IsEmpty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, NoSessions) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| WaitForHierarchyOnServer(SessionsHierarchy()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ChromeHistoryPage) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| ASSERT_TRUE(OpenTab(0, GURL(chrome::kChromeUIHistoryURL))); |
| WaitForURLOnServer(GURL(chrome::kChromeUIHistoryURL)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, NavigateThenCloseTab) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| // Two tabs are opened initially. |
| ASSERT_TRUE(OpenTab(0, GURL(kURL1))); |
| ASSERT_TRUE(OpenTab(0, GURL(kURL2))); |
| WaitForHierarchyOnServer(SessionsHierarchy({{kURL1, kURL2}})); |
| |
| // Close one of the two tabs immediately after issuing an navigation. We also |
| // issue another navigation to make sure association logic kicks in. |
| NavigateTab(0, GURL(kURL3)); |
| ASSERT_TRUE(WaitForTabsToLoad(0, {GURL(kURL1), GURL(kURL3)})); |
| CloseTab(/*index=*/0, /*tab_index=*/1); |
| NavigateTab(0, GURL(kURL4)); |
| |
| ASSERT_TRUE( |
| IsHistoryURLSyncedChecker(kURL4, GetFakeServer(), GetSyncService(0)) |
| .Wait()); |
| |
| // All URLs should be synced, for synced history to be complete. In |
| // particular, |kURL3| should be synced despite the tab being closed. |
| EXPECT_TRUE( |
| IsHistoryURLSyncedChecker(kURL3, GetFakeServer(), GetSyncService(0)) |
| .Wait()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| NavigateThenCloseTabThenOpenTab) { |
| base::test::ScopedFeatureList override_features; |
| override_features.InitAndEnableFeature( |
| sync_sessions::kDeferRecyclingOfSyncTabNodesIfUnsynced); |
| |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| // Two tabs are opened initially. |
| ASSERT_TRUE(OpenTab(0, GURL(kURL1))); |
| ASSERT_TRUE(OpenTab(0, GURL(kURL2))); |
| WaitForHierarchyOnServer(SessionsHierarchy({{kURL1, kURL2}})); |
| |
| // Close one of the two tabs immediately after issuing an navigation. In |
| // addition, a new tab is opened. |
| NavigateTab(0, GURL(kURL3)); |
| ASSERT_TRUE(WaitForTabsToLoad(0, {GURL(kURL1), GURL(kURL3)})); |
| CloseTab(/*index=*/0, /*tab_index=*/1); |
| ASSERT_TRUE(OpenTab(0, GURL(kURL4))); |
| |
| ASSERT_TRUE( |
| IsHistoryURLSyncedChecker(kURL4, GetFakeServer(), GetSyncService(0)) |
| .Wait()); |
| |
| // All URLs should be synced, for synced history to be complete. In |
| // particular, |kURL3| should be synced despite the tab being closed. |
| EXPECT_TRUE( |
| IsHistoryURLSyncedChecker(kURL3, GetFakeServer(), GetSyncService(0)) |
| .Wait()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, TimestampMatchesHistory) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| const GURL url(kURL1); |
| |
| ScopedWindowMap windows; |
| ASSERT_TRUE(OpenTab(0, url)); |
| ASSERT_TRUE(GetLocalWindows(0, &windows)); |
| |
| int found_navigations = 0; |
| for (auto it = windows.begin(); it != windows.end(); ++it) { |
| for (auto it2 = it->second->wrapped_window.tabs.begin(); |
| it2 != it->second->wrapped_window.tabs.end(); ++it2) { |
| for (auto it3 = (*it2)->navigations.begin(); |
| it3 != (*it2)->navigations.end(); ++it3) { |
| const base::Time timestamp = it3->timestamp(); |
| |
| history::URLRow virtual_row; |
| ASSERT_TRUE(GetUrlFromClient(0, it3->virtual_url(), &virtual_row)); |
| const base::Time history_timestamp = virtual_row.last_visit(); |
| // Propagated timestamps have millisecond-level resolution, so we avoid |
| // exact comparison here (i.e. usecs might differ). |
| ASSERT_EQ(0, (timestamp - history_timestamp).InMilliseconds()); |
| ++found_navigations; |
| } |
| } |
| } |
| ASSERT_EQ(1, found_navigations); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ResponseCodeIsPreserved) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| const GURL url(kURL1); |
| ScopedWindowMap windows; |
| ASSERT_TRUE(OpenTab(0, url)); |
| ASSERT_TRUE(GetLocalWindows(0, &windows)); |
| |
| int found_navigations = 0; |
| for (auto it = windows.begin(); it != windows.end(); ++it) { |
| for (auto it2 = it->second->wrapped_window.tabs.begin(); |
| it2 != it->second->wrapped_window.tabs.end(); ++it2) { |
| for (auto it3 = (*it2)->navigations.begin(); |
| it3 != (*it2)->navigations.end(); ++it3) { |
| EXPECT_EQ(200, it3->http_status_code()); |
| ++found_navigations; |
| } |
| } |
| } |
| ASSERT_EQ(1, found_navigations); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, FragmentURLNavigation) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| const GURL url(kBaseFragmentURL); |
| ASSERT_TRUE(OpenTab(0, url)); |
| WaitForURLOnServer(url); |
| |
| const GURL fragment_url(kSpecifiedFragmentURL); |
| NavigateTab(0, fragment_url); |
| WaitForURLOnServer(fragment_url); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| NavigationChainForwardBack) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| GURL first_url = GURL(kURL1); |
| ASSERT_TRUE(OpenTab(0, first_url)); |
| WaitForURLOnServer(first_url); |
| |
| GURL second_url = GURL(kURL2); |
| NavigateTab(0, second_url); |
| WaitForURLOnServer(second_url); |
| |
| NavigateTabBack(0); |
| WaitForURLOnServer(first_url); |
| |
| ExpectNavigationChain({first_url, second_url}); |
| |
| NavigateTabForward(0); |
| WaitForURLOnServer(second_url); |
| |
| ExpectNavigationChain({first_url, second_url}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| NavigationChainAlteredDestructively) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| GURL base_url = GURL(kURL1); |
| ASSERT_TRUE(OpenTab(0, base_url)); |
| WaitForURLOnServer(base_url); |
| |
| GURL first_url = GURL(kURL2); |
| NavigateTab(0, first_url); |
| WaitForURLOnServer(first_url); |
| |
| // Check that the navigation chain matches the above sequence of {base_url, |
| // first_url}. |
| ExpectNavigationChain({base_url, first_url}); |
| |
| NavigateTabBack(0); |
| WaitForURLOnServer(base_url); |
| |
| GURL second_url = GURL(kURL3); |
| NavigateTab(0, second_url); |
| WaitForURLOnServer(second_url); |
| |
| NavigateTabBack(0); |
| WaitForURLOnServer(base_url); |
| |
| // Check that the navigation chain contains second_url where first_url was |
| // before. |
| ExpectNavigationChain({base_url, second_url}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, OpenNewTab) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| GURL base_url = GURL(kURL1); |
| ASSERT_TRUE(OpenTabAtIndex(0, 0, base_url)); |
| |
| WaitForURLOnServer(base_url); |
| |
| GURL new_tab_url = GURL(kURL2); |
| ASSERT_TRUE(OpenTabAtIndex(0, 1, new_tab_url)); |
| |
| WaitForHierarchyOnServer( |
| SessionsHierarchy({{base_url.spec(), new_tab_url.spec()}})); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, OpenNewWindow) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| GURL base_url = GURL(kURL1); |
| ASSERT_TRUE(OpenTab(0, base_url)); |
| |
| WaitForURLOnServer(base_url); |
| |
| GURL new_window_url = GURL(kURL2); |
| AddBrowser(0); |
| ASSERT_TRUE(OpenTab(1, new_window_url)); |
| |
| WaitForHierarchyOnServer( |
| SessionsHierarchy({{base_url.spec()}, {new_window_url.spec()}})); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, |
| GarbageCollectionOfForeignSessions) { |
| const std::string kForeignSessionTag = "ForeignSessionTag"; |
| const SessionID kWindowId = SessionID::FromSerializedValue(5); |
| const SessionID kTabId1 = SessionID::FromSerializedValue(1); |
| const SessionID kTabId2 = SessionID::FromSerializedValue(2); |
| const base::Time kLastModifiedTime = |
| base::Time::Now() - base::TimeDelta::FromDays(100); |
| |
| SessionSyncTestHelper helper; |
| |
| sync_pb::EntitySpecifics tab1; |
| *tab1.mutable_session() = |
| helper.BuildTabSpecifics(kForeignSessionTag, kWindowId, kTabId1); |
| |
| sync_pb::EntitySpecifics tab2; |
| *tab2.mutable_session() = |
| helper.BuildTabSpecifics(kForeignSessionTag, kWindowId, kTabId2); |
| |
| // |tab2| is orphan, i.e. not referenced by the header. We do this to verify |
| // that such tabs are also subject to garbage collection. |
| sync_pb::EntitySpecifics header; |
| SessionSyncTestHelper::BuildSessionSpecifics(kForeignSessionTag, |
| header.mutable_session()); |
| SessionSyncTestHelper::AddWindowSpecifics(kWindowId, {kTabId1}, |
| header.mutable_session()); |
| |
| for (const sync_pb::EntitySpecifics& specifics : {tab1, tab2, header}) { |
| GetFakeServer()->InjectEntity( |
| syncer::PersistentUniqueClientEntity::CreateFromEntitySpecifics( |
| sync_sessions::SessionStore::GetClientTag(specifics.session()), |
| specifics, |
| /*creation_time=*/syncer::TimeToProtoTime(kLastModifiedTime), |
| /*last_modified_time=*/syncer::TimeToProtoTime(kLastModifiedTime))); |
| } |
| |
| base::HistogramTester histogram_tester; |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| // Verify that all entities have been deleted. |
| WaitForHierarchyOnServer(SessionsHierarchy()); |
| |
| std::vector<sync_pb::SyncEntity> entities = |
| fake_server_->GetSyncEntitiesByModelType(syncer::SESSIONS); |
| for (const sync_pb::SyncEntity& entity : entities) { |
| EXPECT_NE(kForeignSessionTag, entity.specifics().session().session_tag()); |
| } |
| |
| EXPECT_EQ( |
| 3, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.SESSION", |
| /*LOCAL_DELETION=*/0)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, TabMovedToOtherWindow) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| GURL base_url = GURL(kURL1); |
| GURL moved_tab_url = GURL(kURL2); |
| |
| ASSERT_TRUE(OpenTab(0, base_url)); |
| ASSERT_TRUE(OpenTabAtIndex(0, 1, moved_tab_url)); |
| |
| GURL new_window_url = GURL(kURL3); |
| AddBrowser(0); |
| ASSERT_TRUE(OpenTab(1, new_window_url)); |
| |
| WaitForHierarchyOnServer(SessionsHierarchy( |
| {{base_url.spec(), moved_tab_url.spec()}, {new_window_url.spec()}})); |
| |
| // Move tab 1 in browser 0 to browser 1. |
| MoveTab(0, 1, 1); |
| |
| WaitForHierarchyOnServer(SessionsHierarchy( |
| {{base_url.spec()}, {new_window_url.spec(), moved_tab_url.spec()}})); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, SourceTabIDSet) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| GURL base_url = GURL(kURL1); |
| ASSERT_TRUE(OpenTab(0, base_url)); |
| |
| WaitForURLOnServer(base_url); |
| |
| GURL new_tab_url = GURL(kURL2); |
| ASSERT_TRUE(OpenTabFromSourceIndex( |
| 0, 0, new_tab_url, WindowOpenDisposition::NEW_FOREGROUND_TAB)); |
| WaitForHierarchyOnServer( |
| SessionsHierarchy({{base_url.spec(), new_tab_url.spec()}})); |
| |
| content::WebContents* original_tab_contents = |
| GetBrowser(0)->tab_strip_model()->GetWebContentsAt(0); |
| content::WebContents* new_tab_contents = |
| GetBrowser(0)->tab_strip_model()->GetWebContentsAt(1); |
| |
| SessionID source_tab_id = SessionTabHelper::IdForTab(original_tab_contents); |
| sync_sessions::SyncSessionsRouterTabHelper* new_tab_helper = |
| sync_sessions::SyncSessionsRouterTabHelper::FromWebContents( |
| new_tab_contents); |
| EXPECT_EQ(new_tab_helper->source_tab_id(), source_tab_id); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, CookieJarMismatch) { |
| ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; |
| |
| ASSERT_TRUE(CheckInitialState(0)); |
| |
| // Simulate empty list of accounts in the cookie jar. This will record cookie |
| // jar mismatch. |
| UpdateCookieJarAccountsAndWait({}, |
| /*expected_cookie_jar_mismatch=*/true); |
| // The HistogramTester objects are scoped to allow more precise verification. |
| { |
| HistogramTester histogram_tester; |
| |
| // Add a new session to client 0 and wait for it to sync. |
| GURL url = GURL(kURL1); |
| ASSERT_TRUE(OpenTab(0, url)); |
| WaitForURLOnServer(url); |
| |
| sync_pb::ClientToServerMessage message; |
| ASSERT_TRUE(GetFakeServer()->GetLastCommitMessage(&message)); |
| ASSERT_TRUE(message.commit().config_params().cookie_jar_mismatch()); |
| |
| // It is possible that multiple sync cycles occurred during the call to |
| // OpenTab, which would cause multiple identical samples. |
| ExpectUniqueSampleGE(histogram_tester, "Sync.CookieJarMatchOnNavigation", |
| false, 1); |
| ExpectUniqueSampleGE(histogram_tester, "Sync.CookieJarEmptyOnMismatch", |
| true, 1); |
| } |
| |
| // Trigger a cookie jar change (user signing in to content area). |
| // Updating the cookie jar has to travel to the sync engine. It is possible |
| // something is already running or scheduled to run on the sync thread. We |
| // want to block here and not create the HistogramTester below until we know |
| // the cookie jar stats have been updated. |
| UpdateCookieJarAccountsAndWait( |
| {GetClient(0)->service()->GetAuthenticatedAccountInfo().account_id}, |
| /*expected_cookie_jar_mismatch=*/false); |
| |
| { |
| HistogramTester histogram_tester; |
| |
| // Trigger a sync and wait for it. |
| GURL url = GURL(kURL2); |
| NavigateTab(0, url); |
| WaitForURLOnServer(url); |
| |
| ASSERT_NE( |
| 0, histogram_tester.GetBucketCount("Sync.PostedClientToServerMessage", |
| /*COMMIT=*/1)); |
| |
| // Verify the cookie jar mismatch bool is set to false. |
| sync_pb::ClientToServerMessage message; |
| ASSERT_TRUE(GetFakeServer()->GetLastCommitMessage(&message)); |
| EXPECT_FALSE(message.commit().config_params().cookie_jar_mismatch()) |
| << *syncer::ClientToServerMessageToValue(message, true); |
| |
| // Verify the histograms were recorded properly. |
| ExpectUniqueSampleGE(histogram_tester, "Sync.CookieJarMatchOnNavigation", |
| true, 1); |
| histogram_tester.ExpectTotalCount("Sync.CookieJarEmptyOnMismatch", 0); |
| } |
| } |
| |
| } // namespace |