Commit 629b3084 authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

Add sync integration tests for closed tabs

There are certain requirements wrt. how sync should behave when a tab
is closed. This patch introduces the first related integration tests,
which reflect current behavior and most notably include the need to sync
history for navigations issued immediately before closing a tab.

Bug: 882489
Change-Id: I255a5082f4a75a24d91ef4be443324094427bd1e
Reviewed-on: https://chromium-review.googlesource.com/c/1355127
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612372}
parent d973a55b
...@@ -30,21 +30,21 @@ using ScopedWindowMap = ...@@ -30,21 +30,21 @@ using ScopedWindowMap =
// Copies the local session windows of profile at |index| to |local_windows|. // Copies the local session windows of profile at |index| to |local_windows|.
// Returns true if successful. // Returns true if successful.
bool GetLocalWindows(int index, ScopedWindowMap* local_windows); bool GetLocalWindows(int browser_index, ScopedWindowMap* local_windows);
// Checks that window count and foreign session count are 0. // Checks that window count and foreign session count are 0.
bool CheckInitialState(int index); bool CheckInitialState(int browser_index);
// Returns number of open windows for a profile. // Returns number of open windows for a profile.
int GetNumWindows(int index); int GetNumWindows(int browser_index);
// Returns number of foreign sessions for a profile. // Returns number of foreign sessions for a profile.
int GetNumForeignSessions(int index); int GetNumForeignSessions(int browser_index);
// Fills the sessions vector with the SyncableService's foreign session data. // Fills the sessions vector with the SyncableService's foreign session data.
// Caller owns |sessions|, but not SyncedSessions objects within. // Caller owns |sessions|, but not SyncedSessions objects within.
// Returns true if foreign sessions were found, false otherwise. // Returns true if foreign sessions were found, false otherwise.
bool GetSessionData(int index, SyncedSessionVector* sessions); bool GetSessionData(int browser_index, SyncedSessionVector* sessions);
// Compares a foreign session based on the first session window. // Compares a foreign session based on the first session window.
// Returns true based on the comparison of the session windows. // Returns true based on the comparison of the session windows.
...@@ -74,75 +74,70 @@ bool WindowsMatch(const SessionWindowMap& win1, const ScopedWindowMap& win2); ...@@ -74,75 +74,70 @@ bool WindowsMatch(const SessionWindowMap& win1, const ScopedWindowMap& win2);
// with a reference SessionWindow list. // with a reference SessionWindow list.
// Returns true if the session windows of the foreign session matches the // Returns true if the session windows of the foreign session matches the
// reference. // reference.
bool CheckForeignSessionsAgainst(int index, bool CheckForeignSessionsAgainst(int browser_index,
const std::vector<ScopedWindowMap>& windows); const std::vector<ScopedWindowMap>& windows);
// Open a single tab in the browser at |index| and block until the // Opens (appends) a single tab in the browser at |index| and block until the
// session SyncableService is aware of it. Returns true upon success, false // sessions bridge is aware of it. Returns true upon success, false otherwise.
// otherwise. bool OpenTab(int browser_index, const GURL& url);
bool OpenTab(int index, const GURL& url);
// See OpenTab, except that the tab is opened in position |tab_index|. // See OpenTab, except that the tab is opened in position |tab_index|.
// If |tab_index| is -1 or greater than the number of tabs, the tab will be // If |tab_index| is -1 or greater than the number of tabs, the tab will be
// appended to the end of the strip. i.e. if tab_index is 3 for a tab strip of // appended to the end of the strip. i.e. if tab_index is 3 for a tab strip of
// size 1, the new tab will be in position 1. // size 1, the new tab will be in position 1.
bool OpenTabAtIndex(int index, int tab_index, const GURL& url); bool OpenTabAtIndex(int browser_index, int tab_index, const GURL& url);
// Like OpenTab, but opens |url| from the tab at |index_of_source_tab| using // Like OpenTab, but opens |url| from the tab at |index_of_source_tab| using
// |disposition|. // |disposition|.
bool OpenTabFromSourceIndex(int index, bool OpenTabFromSourceIndex(int browser_index,
int index_of_source_tab, int index_of_source_tab,
const GURL& url, const GURL& url,
WindowOpenDisposition disposition); WindowOpenDisposition disposition);
// Open multiple tabs and block until the session SyncableService is aware // Opens multiple tabs and blocks until the sessions bridge is aware of all of
// of all of them. Returns true on success, false on failure. // them. Returns true on success, false on failure.
bool OpenMultipleTabs(int index, const std::vector<GURL>& urls); bool OpenMultipleTabs(int browser_index, const std::vector<GURL>& urls);
// Closes the tab |tab_index| in the browser at |index|.
void CloseTab(int browser_index, int tab_index);
// Moves the tab in position |tab_index| in the TabStrip for browser at // Moves the tab in position |tab_index| in the TabStrip for browser at
// |from_index| to the TabStrip for browser at |to_index|. // |from_browser_index| to the TabStrip for browser at |to_browser_index|.
void MoveTab(int from_index, int to_index, int tab_index); void MoveTab(int from_browser_index, int to_browser_index, int tab_index);
// Navigate the active tab for browser in position |index| to the given // Navigate the active tab for browser in position |index| to the given
// url, and blocks until the session SyncableService is aware of it. // URL.
// WARNING: it's dangerous to assume this will return for any arbitrary URL. void NavigateTab(int browser_index, const GURL& url);
// For URLs that don't resolve to a valid server response, this can block
// indefinitely. Use a data uri or the embedded_test_server to ensure that this
// doesn't happen.
bool NavigateTab(int index, const GURL& url);
// Navigate the active tab for browser in position |index| back by one; // Navigate the active tab for browser in position |index| back by one;
// if this isn't possible, does nothing // if this isn't possible, does nothing
void NavigateTabBack(int index); void NavigateTabBack(int browser_index);
// Navigate the active tab for browser in position |index| forward by // Navigate the active tab for browser in position |index| forward by
// one; if this isn't possible, does nothing // one; if this isn't possible, does nothing
void NavigateTabForward(int index); void NavigateTabForward(int browser_index);
// Wait for a session change to |web_contents| to propagate to the model // Wait for a session change to |web_contents| to propagate to the model
// associator. Will return true once |url| has been found, or false if it times // associator. Will return true once |url| has been found, or false if it times
// out while waiting. // out while waiting.
bool WaitForTabToLoad(int index, bool WaitForTabToLoad(int browser_index,
const GURL& url, const GURL& url,
content::WebContents* web_contents); content::WebContents* web_contents);
// Wait for each url in |urls| to load. The ordering of |urls| is assumed to // Wait for each url in |urls| to load. The ordering of |urls| is assumed to
// match the ordering of the corresponding tabs. // match the ordering of the corresponding tabs.
bool WaitForTabsToLoad(int index, const std::vector<GURL>& urls); bool WaitForTabsToLoad(int browser_index, const std::vector<GURL>& urls);
// Check if the session SyncableService knows that the current open tab
// has this url.
bool SessionsSyncManagerHasTabWithURL(int index, const GURL& url);
// Stores a pointer to the local session for a given profile in |session|. // Stores a pointer to the local session for a given profile in |session|.
// Returns true on success, false on failure. // Returns true on success, false on failure.
bool GetLocalSession(int index, const sync_sessions::SyncedSession** session); bool GetLocalSession(int browser_index,
const sync_sessions::SyncedSession** session);
// Deletes the foreign session with tag |session_tag| from the profile specified // Deletes the foreign session with tag |session_tag| from the profile specified
// by |index|. This will affect all synced clients. // by |index|. This will affect all synced clients.
// Note: We pass the session_tag in by value to ensure it's not a reference // Note: We pass the session_tag in by value to ensure it's not a reference
// to the session tag within the SyncedSession we plan to delete. // to the session tag within the SyncedSession we plan to delete.
void DeleteForeignSession(int index, std::string session_tag); void DeleteForeignSession(int browser_index, std::string session_tag);
} // namespace sessions_helper } // namespace sessions_helper
...@@ -151,7 +146,7 @@ void DeleteForeignSession(int index, std::string session_tag); ...@@ -151,7 +146,7 @@ void DeleteForeignSession(int index, std::string session_tag);
class ForeignSessionsMatchChecker : public MultiClientStatusChangeChecker { class ForeignSessionsMatchChecker : public MultiClientStatusChangeChecker {
public: public:
ForeignSessionsMatchChecker( ForeignSessionsMatchChecker(
int index, int browser_index,
const std::vector<sessions_helper::ScopedWindowMap>& windows); const std::vector<sessions_helper::ScopedWindowMap>& windows);
// StatusChangeChecker implementation. // StatusChangeChecker implementation.
...@@ -159,7 +154,7 @@ class ForeignSessionsMatchChecker : public MultiClientStatusChangeChecker { ...@@ -159,7 +154,7 @@ class ForeignSessionsMatchChecker : public MultiClientStatusChangeChecker {
std::string GetDebugMessage() const override; std::string GetDebugMessage() const override;
private: private:
int index_; int browser_index_;
const std::vector<sessions_helper::ScopedWindowMap>& windows_; const std::vector<sessions_helper::ScopedWindowMap>& windows_;
}; };
......
...@@ -34,9 +34,9 @@ using base::HistogramSamples; ...@@ -34,9 +34,9 @@ using base::HistogramSamples;
using base::HistogramTester; using base::HistogramTester;
using fake_server::SessionsHierarchy; using fake_server::SessionsHierarchy;
using sessions_helper::CheckInitialState; using sessions_helper::CheckInitialState;
using sessions_helper::CloseTab;
using sessions_helper::GetLocalWindows; using sessions_helper::GetLocalWindows;
using sessions_helper::GetSessionData; using sessions_helper::GetSessionData;
using sessions_helper::SessionsSyncManagerHasTabWithURL;
using sessions_helper::MoveTab; using sessions_helper::MoveTab;
using sessions_helper::NavigateTab; using sessions_helper::NavigateTab;
using sessions_helper::NavigateTabBack; using sessions_helper::NavigateTabBack;
...@@ -53,6 +53,7 @@ using typed_urls_helper::GetUrlFromClient; ...@@ -53,6 +53,7 @@ using typed_urls_helper::GetUrlFromClient;
static const char* kURL1 = "data:text/html,<html><title>Test</title></html>"; 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* kURL2 = "data:text/html,<html><title>Test2</title></html>";
static const char* kURL3 = "data:text/html,<html><title>Test3</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 = static const char* kBaseFragmentURL =
"data:text/html,<html><title>Fragment</title><body></body></html>"; "data:text/html,<html><title>Fragment</title><body></body></html>";
static const char* kSpecifiedFragmentURL = static const char* kSpecifiedFragmentURL =
...@@ -69,6 +70,39 @@ void ExpectUniqueSampleGE(const HistogramTester& histogram_tester, ...@@ -69,6 +70,39 @@ void ExpectUniqueSampleGE(const HistogramTester& histogram_tester,
EXPECT_EQ(sample_count, samples->TotalCount()); EXPECT_EQ(sample_count, samples->TotalCount());
} }
class IsUrlSyncedChecker : public SingleClientStatusChangeChecker {
public:
IsUrlSyncedChecker(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 {
std::vector<sync_pb::SyncEntity> entities =
fake_server_->GetSyncEntitiesByModelType(syncer::SESSIONS);
for (const sync_pb::SyncEntity& entity : entities) {
for (const auto& navigation :
entity.specifics().session().tab().navigation()) {
if (navigation.virtual_url() == url_) {
return true;
}
}
}
return false;
}
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 { class SingleClientSessionsSyncTest : public SyncTest {
public: public:
SingleClientSessionsSyncTest() : SyncTest(SINGLE_CLIENT) {} SingleClientSessionsSyncTest() : SyncTest(SINGLE_CLIENT) {}
...@@ -181,6 +215,30 @@ IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ChromeHistory) { ...@@ -181,6 +215,30 @@ IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ChromeHistory) {
WaitForURLOnServer(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));
CloseTab(/*index=*/0, /*tab_index=*/1);
NavigateTab(0, GURL(kURL4));
ASSERT_TRUE(
IsUrlSyncedChecker(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(
IsUrlSyncedChecker(kURL3, GetFakeServer(), GetSyncService(0)).Wait());
}
IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, TimestampMatchesHistory) { IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, TimestampMatchesHistory) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
...@@ -284,7 +342,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ...@@ -284,7 +342,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
WaitForURLOnServer(base_url); WaitForURLOnServer(base_url);
GURL first_url = GURL(kURL2); GURL first_url = GURL(kURL2);
ASSERT_TRUE(NavigateTab(0, first_url)); NavigateTab(0, first_url);
WaitForURLOnServer(first_url); WaitForURLOnServer(first_url);
// Check that the navigation chain matches the above sequence of {base_url, // Check that the navigation chain matches the above sequence of {base_url,
...@@ -448,7 +506,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ...@@ -448,7 +506,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
// Trigger a sync and wait for it. // Trigger a sync and wait for it.
GURL url = GURL(kURL2); GURL url = GURL(kURL2);
ASSERT_TRUE(NavigateTab(0, url)); NavigateTab(0, url);
WaitForURLOnServer(url); WaitForURLOnServer(url);
// Verify the cookie jar mismatch bool is set to false. // Verify the cookie jar mismatch bool is set to false.
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
namespace { namespace {
using sessions_helper::CheckInitialState; using sessions_helper::CheckInitialState;
using sessions_helper::CloseTab;
using sessions_helper::DeleteForeignSession; using sessions_helper::DeleteForeignSession;
using sessions_helper::GetLocalWindows; using sessions_helper::GetLocalWindows;
using sessions_helper::GetSessionData; using sessions_helper::GetSessionData;
...@@ -75,6 +76,30 @@ IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, ...@@ -75,6 +76,30 @@ IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest,
WaitForForeignSessionsToSync(0, 1); WaitForForeignSessionsToSync(0, 1);
} }
IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, SingleClientClosed) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Open two tabs on client 0.
OpenTab(0, GURL(kURL1));
OpenTab(0, GURL(kURL2));
WaitForForeignSessionsToSync(0, 1);
// Close one of the two tabs. We also issue another navigation to make sure
// association logic kicks in.
CloseTab(/*index=*/0, /*tab_index=*/1);
NavigateTab(0, GURL(kURL3));
WaitForForeignSessionsToSync(0, 1);
std::vector<sync_pb::SyncEntity> entities =
GetFakeServer()->GetSyncEntitiesByModelType(syncer::SESSIONS);
// Two header entities and two tab entities (one of the two has been closed
// but considered "free" for future recycling, i.e. not deleted).
ASSERT_EQ(4U, entities.size());
for (const auto& entity : entities) {
EXPECT_FALSE(entity.deleted());
}
}
IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, E2E_ENABLED(AllChanged)) { IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, E2E_ENABLED(AllChanged)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
......
...@@ -932,12 +932,20 @@ TEST_F(SessionSyncBridgeTest, ShouldRestoreLocalSessionWithFreedTab) { ...@@ -932,12 +932,20 @@ TEST_F(SessionSyncBridgeTest, ShouldRestoreLocalSessionWithFreedTab) {
InitializeBridge(); InitializeBridge();
StartSyncing(); StartSyncing();
ASSERT_THAT(GetData(header_storage_key), // One tab node de should be free at this point. In the current implementation
EntityDataHasSpecifics( // (subject to change), this is |kTabNodeId1|. This is because |kTabId3| is
MatchesHeader(kLocalSessionTag, {kWindowId2}, {kTabId3}))); // assigned |kTabNodeId2|.
ASSERT_THAT(
GetAllData(),
UnorderedElementsAre(
Pair(header_storage_key,
EntityDataHasSpecifics(
MatchesHeader(kLocalSessionTag, {kWindowId2}, {kTabId3}))),
Pair(tab_storage_key2, EntityDataHasSpecifics(MatchesTab(
kLocalSessionTag, kWindowId2, kTabId3,
kTabNodeId2, {"http://qux.com/"})))));
// |kTabNodeId1| should be free at this point. When a new tab is opened // When a new tab is opened (|kTabId4|), |kTabNodeId1| should be reused.
// (|kTabId4|), it should be reused.
AddTab(kWindowId2, "http://quux.com/", kTabId4); AddTab(kWindowId2, "http://quux.com/", kTabId4);
EXPECT_THAT( EXPECT_THAT(
GetAllData(), GetAllData(),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment