diff options
Diffstat (limited to 'chrome/browser/sync/sessions2/sessions_sync_manager_unittest.cc')
-rw-r--r-- | chrome/browser/sync/sessions2/sessions_sync_manager_unittest.cc | 222 |
1 files changed, 183 insertions, 39 deletions
diff --git a/chrome/browser/sync/sessions2/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions2/sessions_sync_manager_unittest.cc index 3f21000..c0e284f 100644 --- a/chrome/browser/sync/sessions2/sessions_sync_manager_unittest.cc +++ b/chrome/browser/sync/sessions2/sessions_sync_manager_unittest.cc @@ -12,6 +12,7 @@ #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/sessions2/notification_service_sessions_router.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" @@ -42,8 +43,15 @@ class TestSyncProcessorStub : public syncer::SyncChangeProcessor { 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_->assign(change_list.begin(), change_list.end()); + output_->insert(output_->end(), change_list.begin(), change_list.end()); + return syncer::SyncError(); } @@ -51,7 +59,13 @@ class TestSyncProcessorStub : public syncer::SyncChangeProcessor { const OVERRIDE { return syncer::SyncDataList(); } + + void FailProcessSyncChangesWith(const syncer::SyncError& error) { + error_ = error; + } + private: + syncer::SyncError error_; syncer::SyncChangeList* output_; }; @@ -92,20 +106,36 @@ void AddTabsToSyncDataList(const std::vector<sync_pb::SessionSpecifics> tabs, } } +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()); +} + } // namespace class SessionsSyncManagerTest : public BrowserWithTestWindowTest, public SessionsSyncManager::SyncInternalApiDelegate { public: - SessionsSyncManagerTest() {} + SessionsSyncManagerTest() : test_processor_(NULL) {} virtual void SetUp() OVERRIDE { BrowserWithTestWindowTest::SetUp(); - manager_.reset(new SessionsSyncManager(profile(), this)); + 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(); @@ -129,10 +159,10 @@ class SessionsSyncManagerTest 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>( - new TestSyncProcessorStub(output)), + scoped_ptr<syncer::SyncChangeProcessor>(test_processor_), scoped_ptr<syncer::SyncErrorFactory>( new syncer::SyncErrorFactoryMock())); EXPECT_FALSE(result.error().IsSet()); @@ -142,6 +172,12 @@ class SessionsSyncManagerTest InitWithSyncDataTakeOutput(syncer::SyncDataList(), NULL); } + void TriggerProcessSyncChangesError() { + test_processor_->FailProcessSyncChangesWith(syncer::SyncError( + FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "Error", + syncer::SESSIONS)); + } + syncer::SyncChangeList* FilterOutLocalHeaderChanges( syncer::SyncChangeList* list) { syncer::SyncChangeList::iterator it = list->begin(); @@ -163,6 +199,7 @@ class SessionsSyncManagerTest private: scoped_ptr<SessionsSyncManager> manager_; SessionSyncTestHelper helper_; + TestSyncProcessorStub* test_processor_; }; TEST_F(SessionsSyncManagerTest, PopulateSessionHeader) { @@ -519,7 +556,7 @@ TEST_F(SessionsSyncManagerTest, MergeLocalSessionNoTabs) { SyncData d(SyncData::CreateRemoteData(1, data.GetSpecifics(), base::Time())); syncer::SyncDataList in(&d, &d + 1); out.clear(); - SessionsSyncManager manager2(profile(), this); + SessionsSyncManager manager2(profile(), this, NewDummyRouter()); syncer::SyncMergeResult result = manager2.MergeDataAndStartSyncing( syncer::SESSIONS, in, scoped_ptr<syncer::SyncChangeProcessor>( @@ -912,7 +949,7 @@ TEST_F(SessionsSyncManagerTest, SaveUnassociatedNodesForReassociation) { SyncData d(SyncData::CreateRemoteData(1, entity, base::Time())); syncer::SyncDataList in(&d, &d + 1); changes.clear(); - SessionsSyncManager manager2(profile(), this); + SessionsSyncManager manager2(profile(), this, NewDummyRouter()); syncer::SyncMergeResult result = manager2.MergeDataAndStartSyncing( syncer::SESSIONS, in, scoped_ptr<syncer::SyncChangeProcessor>( @@ -942,12 +979,13 @@ TEST_F(SessionsSyncManagerTest, MergeDeletesCorruptNode) { changes[0].sync_data().GetTag()); } +// Test that things work if a tab is initially ignored. TEST_F(SessionsSyncManagerTest, AssociateWindowsDontReloadTabs) { syncer::SyncChangeList out; // Go to a URL that is ignored by session syncing. AddTab(browser(), GURL("chrome://preferences/")); InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out); - ASSERT_EQ(2U, out.size()); + ASSERT_EQ(2U, out.size()); // Header add and update. EXPECT_EQ( 0, out[1].sync_data().GetSpecifics().session().header().window_size()); @@ -956,12 +994,7 @@ TEST_F(SessionsSyncManagerTest, AssociateWindowsDontReloadTabs) { // Go to a sync-interesting URL. NavigateAndCommitActiveTab(GURL("http://foo2")); - // Simulate a selective association (e.g in response to tab event) as - // would occur in practice from ProcessSyncChanges. - content::WebContents* c = - browser()->tab_strip_model()->GetActiveWebContents(); - manager()->AssociateTab(SyncedTabDelegate::ImplFromWebContents(c), &out); - ASSERT_EQ(2U, out.size()); + EXPECT_EQ(3U, out.size()); // Tab add, update, and header update. EXPECT_TRUE(StartsWithASCII(out[0].sync_data().GetTag(), manager()->current_machine_tag(), true)); @@ -976,14 +1009,9 @@ TEST_F(SessionsSyncManagerTest, AssociateWindowsDontReloadTabs) { EXPECT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab()); EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type()); - out.clear(); - manager()->AssociateWindows(SessionsSyncManager::DONT_RELOAD_TABS, - &out); - - EXPECT_EQ(1U, out.size()); - EXPECT_TRUE(out[0].IsValid()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type()); - const SyncData data(out[0].sync_data()); + 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(), data.GetTag()); const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session()); EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag()); @@ -993,12 +1021,107 @@ TEST_F(SessionsSyncManagerTest, AssociateWindowsDontReloadTabs) { EXPECT_EQ(1, header_s.window(0).tab_size()); } +TEST_F(SessionsSyncManagerTest, OnLocalTabModified) { + syncer::SyncChangeList out; + // Init with no local data, relies on MergeLocalSessionNoTabs. + InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out); + ASSERT_FALSE(manager()->current_machine_tag().empty()); + ASSERT_EQ(2U, out.size()); + + // Copy the original header. + 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); + + // One add, one update for each AddTab. + // One update for each NavigateAndCommit. + // = 6 total tab updates. + // One header update corresponding to each of those. + // = 6 total header updates. + // 12 total updates. + ASSERT_EQ(12U, out.size()); + + // Verify the tab node creations and updates to ensure the SyncProcessor + // sees the right operations. + 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(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) { + // First thing on an AddTab is a no-op header update for parented tab. + EXPECT_EQ(header.SerializeAsString(), + data.GetSpecifics().SerializeAsString()); + } else if (i % 6 == 1) { + // Next, the TabNodePool should create the tab node. + EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type()); + } else if (i % 6 == 2) { + // Then we see the tab update to the URL. + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); + ASSERT_TRUE(specifics.has_tab()); + } else if (i % 6 == 3) { + // The header needs to be updated to reflect the new window state. + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); + EXPECT_TRUE(specifics.has_header()); + } else if (i % 6 == 4) { + // Now we move on to NavigateAndCommit. Update the tab. + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); + ASSERT_TRUE(specifics.has_tab()); + } else if (i % 6 == 5) { + // The header needs to be updated to reflect the new window state. + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); + ASSERT_TRUE(specifics.has_header()); + header = data.GetSpecifics(); + } + } + + // Verify the actual content to ensure sync sees the right data. + // When it's all said and done, the header should reflect two tabs. + 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()); + + // ASSERT_TRUEs above allow us to dive in freely here. + // Verify first tab. + 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()); + + // Verify second tab. + 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()); +} + // Ensure model association associates the pre-existing tabs. TEST_F(SessionsSyncManagerTest, MergeLocalSessionExistingTabs) { AddTab(browser(), GURL("http://foo1")); - NavigateAndCommitActiveTab(GURL("http://foo2")); + NavigateAndCommitActiveTab(GURL("http://foo2")); // Adds back entry. AddTab(browser(), GURL("http://bar1")); - NavigateAndCommitActiveTab(GURL("http://bar2")); + NavigateAndCommitActiveTab(GURL("http://bar2")); // Adds back entry. syncer::SyncChangeList out; InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out); @@ -1077,8 +1200,8 @@ TEST_F(SessionsSyncManagerTest, CheckPrerenderedWebContentsSwap) { // To simulate WebContents swap during prerendering, create new WebContents // and swap with old WebContents. - content::WebContents* old_web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); + scoped_ptr<content::WebContents> old_web_contents; + old_web_contents.reset(browser()->tab_strip_model()->GetActiveWebContents()); // Create new WebContents, with the required tab helpers. WebContents* new_web_contents = WebContents::CreateWithSessionStorage( @@ -1090,42 +1213,39 @@ TEST_F(SessionsSyncManagerTest, CheckPrerenderedWebContentsSwap) { .CopyStateFrom(old_web_contents->GetController()); // Swap the WebContents. - int index = - browser()->tab_strip_model()->GetIndexOfWebContents(old_web_contents); + int index = browser()->tab_strip_model()->GetIndexOfWebContents( + old_web_contents.get()); browser()->tab_strip_model()->ReplaceWebContentsAt(index, new_web_contents); - manager()->AssociateWindows(SessionsSyncManager::RELOAD_TABS, &out); - ASSERT_EQ(7U, out.size()); + ASSERT_EQ(9U, out.size()); EXPECT_EQ(SyncChange::ACTION_ADD, out[4].change_type()); EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type()); // Navigate away. NavigateAndCommitActiveTab(GURL("http://bar2")); - manager()->AssociateWindows(SessionsSyncManager::RELOAD_TABS, &out); // Delete old WebContents. This should not crash. - delete old_web_contents; - manager()->AssociateWindows(SessionsSyncManager::RELOAD_TABS, &out); + old_web_contents.reset(); // Try more navigations and verify output size. This can also reveal // bugs (leaks) on memcheck bots if the SessionSyncManager // didn't properly clean up the tab pool or session tracker. NavigateAndCommitActiveTab(GURL("http://bar3")); - manager()->AssociateWindows(SessionsSyncManager::RELOAD_TABS, &out); AddTab(browser(), GURL("http://bar4")); - manager()->AssociateWindows(SessionsSyncManager::RELOAD_TABS, &out); NavigateAndCommitActiveTab(GURL("http://bar5")); - manager()->AssociateWindows(SessionsSyncManager::RELOAD_TABS, &out); - ASSERT_EQ(20U, out.size()); + ASSERT_EQ(19U, out.size()); } namespace { class SessionNotificationObserver : public content::NotificationObserver { public: - SessionNotificationObserver() : notified_of_update_(false) { + 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, @@ -1134,21 +1254,30 @@ class SessionNotificationObserver : public content::NotificationObserver { 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_; } - void Reset() { notified_of_update_ = false; } + 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_; }; } // namespace TEST_F(SessionsSyncManagerTest, NotifiedOfUpdates) { SessionNotificationObserver observer; + ASSERT_FALSE(observer.notified_of_update()); InitWithNoSyncData(); SessionID::id_type n[] = {5}; @@ -1175,4 +1304,19 @@ TEST_F(SessionsSyncManagerTest, NotifiedOfUpdates) { EXPECT_TRUE(observer.notified_of_update()); } +#if defined(OS_ANDROID) || defined(OS_IOS) +// Tests that opening the other devices page triggers a session sync refresh. +// This page only exists on mobile platforms today; desktop has a +// search-enhanced NTP without other devices. +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 // defined(OS_ANDROID) || defined(OS_IOS) + } // namespace browser_sync |