| // Copyright (c) 2011 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/memory/scoped_vector.h" |
| #include "chrome/browser/geolocation/geolocation_content_settings_map.h" |
| #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" |
| #include "chrome/test/testing_profile.h" |
| #include "content/browser/browser_thread.h" |
| #include "content/browser/geolocation/arbitrator_dependency_factories_for_test.h" |
| #include "content/browser/geolocation/geolocation_permission_context.h" |
| #include "content/browser/geolocation/location_arbitrator.h" |
| #include "content/browser/geolocation/location_provider.h" |
| #include "content/browser/geolocation/mock_location_provider.h" |
| #include "content/browser/renderer_host/mock_render_process_host.h" |
| #include "content/browser/renderer_host/test_render_view_host.h" |
| #include "content/browser/tab_contents/test_tab_contents.h" |
| #include "content/common/geolocation_messages.h" |
| #include "content/common/notification_details.h" |
| #include "content/common/notification_type.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| // TestTabContentsWithPendingInfoBar ------------------------------------------ |
| |
| namespace { |
| |
| // TestTabContents short-circuits TAB_CONTENTS_INFOBAR_REMOVED to call |
| // InfoBarClosed() directly. We need to observe it and call InfoBarClosed() |
| // later. |
| class TestTabContentsWithPendingInfoBar : public TestTabContents { |
| public: |
| TestTabContentsWithPendingInfoBar(Profile* profile, SiteInstance* instance); |
| virtual ~TestTabContentsWithPendingInfoBar(); |
| |
| // TestTabContents: |
| virtual void Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details); |
| |
| InfoBarDelegate* removed_infobar_delegate_; |
| }; |
| |
| TestTabContentsWithPendingInfoBar::TestTabContentsWithPendingInfoBar( |
| Profile* profile, |
| SiteInstance* instance) |
| : TestTabContents(profile, instance), |
| removed_infobar_delegate_(NULL) { |
| } |
| |
| TestTabContentsWithPendingInfoBar::~TestTabContentsWithPendingInfoBar() { |
| } |
| |
| void TestTabContentsWithPendingInfoBar::Observe( |
| NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (type.value == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED) |
| removed_infobar_delegate_ = Details<InfoBarDelegate>(details).ptr(); |
| else |
| TestTabContents::Observe(type, source, details); |
| } |
| |
| } // namespace |
| |
| |
| // GeolocationPermissionContextTests ------------------------------------------ |
| |
| // This class sets up GeolocationArbitrator. |
| class GeolocationPermissionContextTests : public RenderViewHostTestHarness { |
| public: |
| GeolocationPermissionContextTests(); |
| |
| protected: |
| virtual ~GeolocationPermissionContextTests(); |
| |
| int process_id() { return contents()->render_view_host()->process()->id(); } |
| int process_id_for_tab(int tab) { |
| return extra_tabs_[tab]->render_view_host()->process()->id(); |
| } |
| int render_id() { return contents()->render_view_host()->routing_id(); } |
| int render_id_for_tab(int tab) { |
| return extra_tabs_[tab]->render_view_host()->routing_id(); |
| } |
| int bridge_id() const { return 42; } // Not relevant at this level. |
| |
| void CheckPermissionMessageSent(int bridge_id, bool allowed); |
| void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed); |
| void CheckPermissionMessageSentInternal(MockRenderProcessHost* process, |
| int bridge_id, |
| bool allowed); |
| void AddNewTab(const GURL& url); |
| void CheckTabContentsState(const GURL& requesting_frame, |
| ContentSetting expected_content_setting); |
| |
| TestTabContentsWithPendingInfoBar* tab_contents_with_pending_infobar_; |
| scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_; |
| ScopedVector<TestTabContentsWithPendingInfoBar> extra_tabs_; |
| |
| private: |
| // RenderViewHostTestHarness: |
| virtual void SetUp(); |
| virtual void TearDown(); |
| |
| BrowserThread ui_thread_; |
| scoped_refptr<GeolocationArbitratorDependencyFactory> dependency_factory_; |
| }; |
| |
| GeolocationPermissionContextTests::GeolocationPermissionContextTests() |
| : RenderViewHostTestHarness(), |
| tab_contents_with_pending_infobar_(NULL), |
| ui_thread_(BrowserThread::UI, MessageLoop::current()), |
| dependency_factory_( |
| new GeolocationArbitratorDependencyFactoryWithLocationProvider( |
| &NewAutoSuccessMockNetworkLocationProvider)) { |
| } |
| |
| GeolocationPermissionContextTests::~GeolocationPermissionContextTests() { |
| } |
| |
| void GeolocationPermissionContextTests::CheckPermissionMessageSent( |
| int bridge_id, |
| bool allowed) { |
| CheckPermissionMessageSentInternal(process(), bridge_id, allowed); |
| } |
| |
| void GeolocationPermissionContextTests::CheckPermissionMessageSentForTab( |
| int tab, |
| int bridge_id, |
| bool allowed) { |
| CheckPermissionMessageSentInternal(static_cast<MockRenderProcessHost*>( |
| extra_tabs_[tab]->render_view_host()->process()), bridge_id, allowed); |
| } |
| |
| void GeolocationPermissionContextTests::CheckPermissionMessageSentInternal( |
| MockRenderProcessHost* process, |
| int bridge_id, |
| bool allowed) { |
| MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| MessageLoop::current()->Run(); |
| const IPC::Message* message = process->sink().GetFirstMessageMatching( |
| GeolocationMsg_PermissionSet::ID); |
| ASSERT_TRUE(message); |
| GeolocationMsg_PermissionSet::Param param; |
| GeolocationMsg_PermissionSet::Read(message, ¶m); |
| EXPECT_EQ(bridge_id, param.a); |
| EXPECT_EQ(allowed, param.b); |
| process->sink().ClearMessages(); |
| } |
| |
| void GeolocationPermissionContextTests::AddNewTab(const GURL& url) { |
| TestTabContentsWithPendingInfoBar* new_tab = |
| new TestTabContentsWithPendingInfoBar(profile(), NULL); |
| new_tab->controller().LoadURL(url, GURL(), PageTransition::TYPED); |
| static_cast<TestRenderViewHost*>(new_tab->render_manager()->current_host())-> |
| SendNavigate(extra_tabs_.size() + 1, url); |
| extra_tabs_.push_back(new_tab); |
| } |
| |
| void GeolocationPermissionContextTests::CheckTabContentsState( |
| const GURL& requesting_frame, |
| ContentSetting expected_content_setting) { |
| TabSpecificContentSettings* content_settings = |
| contents()->GetTabSpecificContentSettings(); |
| const GeolocationSettingsState::StateMap& state_map = |
| content_settings->geolocation_settings_state().state_map(); |
| EXPECT_EQ(1U, state_map.count(requesting_frame.GetOrigin())); |
| EXPECT_EQ(0U, state_map.count(requesting_frame)); |
| GeolocationSettingsState::StateMap::const_iterator settings = |
| state_map.find(requesting_frame.GetOrigin()); |
| ASSERT_FALSE(settings == state_map.end()) |
| << "geolocation state not found " << requesting_frame; |
| EXPECT_EQ(expected_content_setting, settings->second); |
| } |
| |
| void GeolocationPermissionContextTests::SetUp() { |
| RenderViewHostTestHarness::SetUp(); |
| GeolocationArbitrator::SetDependencyFactoryForTest( |
| dependency_factory_.get()); |
| SiteInstance* site_instance = contents()->GetSiteInstance(); |
| tab_contents_with_pending_infobar_ = |
| new TestTabContentsWithPendingInfoBar(profile_.get(), site_instance); |
| SetContents(tab_contents_with_pending_infobar_); |
| geolocation_permission_context_ = |
| new GeolocationPermissionContext(profile()); |
| } |
| |
| void GeolocationPermissionContextTests::TearDown() { |
| GeolocationArbitrator::SetDependencyFactoryForTest(NULL); |
| RenderViewHostTestHarness::TearDown(); |
| } |
| |
| |
| // Tests ---------------------------------------------------------------------- |
| |
| TEST_F(GeolocationPermissionContextTests, SinglePermission) { |
| GURL requesting_frame("http://www.example.com/geolocation"); |
| NavigateAndCommit(requesting_frame); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), requesting_frame); |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| } |
| |
| TEST_F(GeolocationPermissionContextTests, QueuedPermission) { |
| GURL requesting_frame_0("http://www.example.com/geolocation"); |
| GURL requesting_frame_1("http://www.example-2.com/geolocation"); |
| EXPECT_EQ(CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_0, requesting_frame_0)); |
| EXPECT_EQ(CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_1, requesting_frame_0)); |
| |
| NavigateAndCommit(requesting_frame_0); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| // Request permission for two frames. |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), requesting_frame_0); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id() + 1, requesting_frame_1); |
| // Ensure only one infobar is created. |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| ConfirmInfoBarDelegate* infobar_0 = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_0); |
| string16 text_0 = infobar_0->GetMessageText(); |
| |
| // Accept the first frame. |
| infobar_0->Accept(); |
| CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW); |
| CheckPermissionMessageSent(bridge_id(), true); |
| |
| contents()->RemoveInfoBar(infobar_0); |
| EXPECT_EQ(infobar_0, |
| tab_contents_with_pending_infobar_->removed_infobar_delegate_); |
| infobar_0->InfoBarClosed(); |
| // Now we should have a new infobar for the second frame. |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| |
| ConfirmInfoBarDelegate* infobar_1 = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_1); |
| string16 text_1 = infobar_1->GetMessageText(); |
| EXPECT_NE(text_0, text_1); |
| |
| // Cancel (block) this frame. |
| infobar_1->Cancel(); |
| CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_BLOCK); |
| CheckPermissionMessageSent(bridge_id() + 1, false); |
| contents()->RemoveInfoBar(infobar_1); |
| EXPECT_EQ(infobar_1, |
| tab_contents_with_pending_infobar_->removed_infobar_delegate_); |
| infobar_1->InfoBarClosed(); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| // Ensure the persisted permissions are ok. |
| EXPECT_EQ(CONTENT_SETTING_ALLOW, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_0, requesting_frame_0)); |
| EXPECT_EQ(CONTENT_SETTING_BLOCK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_1, requesting_frame_0)); |
| } |
| |
| TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) { |
| GURL requesting_frame_0("http://www.example.com/geolocation"); |
| GURL requesting_frame_1("http://www.example-2.com/geolocation"); |
| EXPECT_EQ(CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_0, requesting_frame_0)); |
| EXPECT_EQ(CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_1, requesting_frame_0)); |
| |
| NavigateAndCommit(requesting_frame_0); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| // Request permission for two frames. |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), requesting_frame_0); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id() + 1, requesting_frame_1); |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| |
| ConfirmInfoBarDelegate* infobar_0 = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_0); |
| string16 text_0 = infobar_0->GetMessageText(); |
| |
| // Simulate the frame going away, ensure the infobar for this frame |
| // is removed and the next pending infobar is created. |
| geolocation_permission_context_->CancelGeolocationPermissionRequest( |
| process_id(), render_id(), bridge_id(), requesting_frame_0); |
| EXPECT_EQ(infobar_0, |
| tab_contents_with_pending_infobar_->removed_infobar_delegate_); |
| infobar_0->InfoBarClosed(); |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| |
| ConfirmInfoBarDelegate* infobar_1 = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_1); |
| string16 text_1 = infobar_1->GetMessageText(); |
| EXPECT_NE(text_0, text_1); |
| |
| // Allow this frame. |
| infobar_1->Accept(); |
| CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW); |
| CheckPermissionMessageSent(bridge_id() + 1, true); |
| contents()->RemoveInfoBar(infobar_1); |
| EXPECT_EQ(infobar_1, |
| tab_contents_with_pending_infobar_->removed_infobar_delegate_); |
| infobar_1->InfoBarClosed(); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| // Ensure the persisted permissions are ok. |
| EXPECT_EQ(CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_0, requesting_frame_0)); |
| EXPECT_EQ(CONTENT_SETTING_ALLOW, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_1, requesting_frame_0)); |
| } |
| |
| TEST_F(GeolocationPermissionContextTests, InvalidURL) { |
| GURL invalid_embedder; |
| GURL requesting_frame("about:blank"); |
| NavigateAndCommit(invalid_embedder); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), requesting_frame); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| CheckPermissionMessageSent(bridge_id(), false); |
| } |
| |
| TEST_F(GeolocationPermissionContextTests, SameOriginMultipleTabs) { |
| GURL url_a("http://www.example.com/geolocation"); |
| GURL url_b("http://www.example-2.com/geolocation"); |
| NavigateAndCommit(url_a); |
| AddNewTab(url_b); |
| AddNewTab(url_a); |
| |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), url_a); |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_b); |
| EXPECT_EQ(1U, extra_tabs_[0]->infobar_count()); |
| |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id_for_tab(1), render_id_for_tab(1), bridge_id(), url_a); |
| EXPECT_EQ(1U, extra_tabs_[1]->infobar_count()); |
| |
| ConfirmInfoBarDelegate* removed_infobar = |
| extra_tabs_[1]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| |
| // Accept the first tab. |
| ConfirmInfoBarDelegate* infobar_0 = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_0); |
| infobar_0->Accept(); |
| CheckPermissionMessageSent(bridge_id(), true); |
| contents()->RemoveInfoBar(infobar_0); |
| EXPECT_EQ(infobar_0, |
| tab_contents_with_pending_infobar_->removed_infobar_delegate_); |
| infobar_0->InfoBarClosed(); |
| // Now the infobar for the tab with the same origin should have gone. |
| EXPECT_EQ(0U, extra_tabs_[1]->infobar_count()); |
| CheckPermissionMessageSentForTab(1, bridge_id(), true); |
| // Destroy the infobar that has just been removed. |
| removed_infobar->InfoBarClosed(); |
| |
| // But the other tab should still have the info bar... |
| EXPECT_EQ(1U, extra_tabs_[0]->infobar_count()); |
| extra_tabs_.reset(); |
| } |
| |
| TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) { |
| GURL url_a("http://www.example.com/geolocation"); |
| GURL url_b("http://www.example-2.com/geolocation"); |
| NavigateAndCommit(url_a); |
| AddNewTab(url_a); |
| |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), url_a); |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_a); |
| EXPECT_EQ(1U, extra_tabs_[0]->infobar_count()); |
| |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id_for_tab(0), render_id_for_tab(0), bridge_id() + 1, url_b); |
| EXPECT_EQ(1U, extra_tabs_[0]->infobar_count()); |
| |
| ConfirmInfoBarDelegate* removed_infobar = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| |
| // Accept the second tab. |
| ConfirmInfoBarDelegate* infobar_0 = |
| extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_0); |
| infobar_0->Accept(); |
| CheckPermissionMessageSentForTab(0, bridge_id(), true); |
| extra_tabs_[0]->RemoveInfoBar(infobar_0); |
| EXPECT_EQ(infobar_0, |
| extra_tabs_[0]->removed_infobar_delegate_); |
| infobar_0->InfoBarClosed(); |
| // Now the infobar for the tab with the same origin should have gone. |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| CheckPermissionMessageSent(bridge_id(), true); |
| // Destroy the infobar that has just been removed. |
| removed_infobar->InfoBarClosed(); |
| |
| // And we should have the queued infobar displayed now. |
| EXPECT_EQ(1U, extra_tabs_[0]->infobar_count()); |
| |
| // Accept the second infobar. |
| ConfirmInfoBarDelegate* infobar_1 = |
| extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_1); |
| infobar_1->Accept(); |
| CheckPermissionMessageSentForTab(0, bridge_id() + 1, true); |
| extra_tabs_[0]->RemoveInfoBar(infobar_1); |
| EXPECT_EQ(infobar_1, |
| extra_tabs_[0]->removed_infobar_delegate_); |
| infobar_1->InfoBarClosed(); |
| |
| extra_tabs_.reset(); |
| } |
| |
| TEST_F(GeolocationPermissionContextTests, TabDestroyed) { |
| GURL requesting_frame_0("http://www.example.com/geolocation"); |
| GURL requesting_frame_1("http://www.example-2.com/geolocation"); |
| EXPECT_EQ( |
| CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_0, requesting_frame_0)); |
| EXPECT_EQ( |
| CONTENT_SETTING_ASK, |
| profile()->GetGeolocationContentSettingsMap()->GetContentSetting( |
| requesting_frame_1, requesting_frame_0)); |
| |
| NavigateAndCommit(requesting_frame_0); |
| EXPECT_EQ(0U, contents()->infobar_count()); |
| // Request permission for two frames. |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id(), requesting_frame_0); |
| geolocation_permission_context_->RequestGeolocationPermission( |
| process_id(), render_id(), bridge_id() + 1, requesting_frame_1); |
| // Ensure only one infobar is created. |
| EXPECT_EQ(1U, contents()->infobar_count()); |
| ConfirmInfoBarDelegate* infobar_0 = |
| contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); |
| ASSERT_TRUE(infobar_0); |
| string16 text_0 = infobar_0->GetMessageText(); |
| |
| // Delete the tab contents. |
| DeleteContents(); |
| } |