Home | History | Annotate | Download | only in geolocation
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/memory/scoped_vector.h"
      6 #include "chrome/browser/geolocation/geolocation_content_settings_map.h"
      7 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
      8 #include "chrome/test/testing_profile.h"
      9 #include "content/browser/browser_thread.h"
     10 #include "content/browser/geolocation/arbitrator_dependency_factories_for_test.h"
     11 #include "content/browser/geolocation/geolocation_permission_context.h"
     12 #include "content/browser/geolocation/location_arbitrator.h"
     13 #include "content/browser/geolocation/location_provider.h"
     14 #include "content/browser/geolocation/mock_location_provider.h"
     15 #include "content/browser/renderer_host/mock_render_process_host.h"
     16 #include "content/browser/renderer_host/test_render_view_host.h"
     17 #include "content/browser/tab_contents/test_tab_contents.h"
     18 #include "content/common/geolocation_messages.h"
     19 #include "content/common/notification_details.h"
     20 #include "content/common/notification_type.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 // TestTabContentsWithPendingInfoBar ------------------------------------------
     24 
     25 namespace {
     26 
     27 // TestTabContents short-circuits TAB_CONTENTS_INFOBAR_REMOVED to call
     28 // InfoBarClosed() directly. We need to observe it and call InfoBarClosed()
     29 // later.
     30 class TestTabContentsWithPendingInfoBar : public TestTabContents {
     31  public:
     32   TestTabContentsWithPendingInfoBar(Profile* profile, SiteInstance* instance);
     33   virtual ~TestTabContentsWithPendingInfoBar();
     34 
     35   // TestTabContents:
     36   virtual void Observe(NotificationType type,
     37                        const NotificationSource& source,
     38                        const NotificationDetails& details);
     39 
     40   InfoBarDelegate* removed_infobar_delegate_;
     41 };
     42 
     43 TestTabContentsWithPendingInfoBar::TestTabContentsWithPendingInfoBar(
     44     Profile* profile,
     45     SiteInstance* instance)
     46     : TestTabContents(profile, instance),
     47       removed_infobar_delegate_(NULL) {
     48 }
     49 
     50 TestTabContentsWithPendingInfoBar::~TestTabContentsWithPendingInfoBar() {
     51 }
     52 
     53 void TestTabContentsWithPendingInfoBar::Observe(
     54     NotificationType type,
     55     const NotificationSource& source,
     56     const NotificationDetails& details) {
     57   if (type.value == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED)
     58     removed_infobar_delegate_ = Details<InfoBarDelegate>(details).ptr();
     59   else
     60     TestTabContents::Observe(type, source, details);
     61 }
     62 
     63 }  // namespace
     64 
     65 
     66 // GeolocationPermissionContextTests ------------------------------------------
     67 
     68 // This class sets up GeolocationArbitrator.
     69 class GeolocationPermissionContextTests : public RenderViewHostTestHarness {
     70  public:
     71   GeolocationPermissionContextTests();
     72 
     73  protected:
     74   virtual ~GeolocationPermissionContextTests();
     75 
     76   int process_id() { return contents()->render_view_host()->process()->id(); }
     77   int process_id_for_tab(int tab) {
     78     return extra_tabs_[tab]->render_view_host()->process()->id();
     79   }
     80   int render_id() { return contents()->render_view_host()->routing_id(); }
     81   int render_id_for_tab(int tab) {
     82     return extra_tabs_[tab]->render_view_host()->routing_id();
     83   }
     84   int bridge_id() const { return 42; }  // Not relevant at this level.
     85 
     86   void CheckPermissionMessageSent(int bridge_id, bool allowed);
     87   void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed);
     88   void CheckPermissionMessageSentInternal(MockRenderProcessHost* process,
     89                                           int bridge_id,
     90                                           bool allowed);
     91   void AddNewTab(const GURL& url);
     92   void CheckTabContentsState(const GURL& requesting_frame,
     93                              ContentSetting expected_content_setting);
     94 
     95   TestTabContentsWithPendingInfoBar* tab_contents_with_pending_infobar_;
     96   scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_;
     97   ScopedVector<TestTabContentsWithPendingInfoBar> extra_tabs_;
     98 
     99  private:
    100   // RenderViewHostTestHarness:
    101   virtual void SetUp();
    102   virtual void TearDown();
    103 
    104   BrowserThread ui_thread_;
    105   scoped_refptr<GeolocationArbitratorDependencyFactory> dependency_factory_;
    106 };
    107 
    108 GeolocationPermissionContextTests::GeolocationPermissionContextTests()
    109     : RenderViewHostTestHarness(),
    110       tab_contents_with_pending_infobar_(NULL),
    111       ui_thread_(BrowserThread::UI, MessageLoop::current()),
    112       dependency_factory_(
    113           new GeolocationArbitratorDependencyFactoryWithLocationProvider(
    114               &NewAutoSuccessMockNetworkLocationProvider)) {
    115 }
    116 
    117 GeolocationPermissionContextTests::~GeolocationPermissionContextTests() {
    118 }
    119 
    120 void GeolocationPermissionContextTests::CheckPermissionMessageSent(
    121     int bridge_id,
    122     bool allowed) {
    123   CheckPermissionMessageSentInternal(process(), bridge_id, allowed);
    124 }
    125 
    126 void GeolocationPermissionContextTests::CheckPermissionMessageSentForTab(
    127     int tab,
    128     int bridge_id,
    129     bool allowed) {
    130   CheckPermissionMessageSentInternal(static_cast<MockRenderProcessHost*>(
    131       extra_tabs_[tab]->render_view_host()->process()), bridge_id, allowed);
    132 }
    133 
    134 void GeolocationPermissionContextTests::CheckPermissionMessageSentInternal(
    135     MockRenderProcessHost* process,
    136     int bridge_id,
    137     bool allowed) {
    138   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
    139   MessageLoop::current()->Run();
    140   const IPC::Message* message = process->sink().GetFirstMessageMatching(
    141       GeolocationMsg_PermissionSet::ID);
    142   ASSERT_TRUE(message);
    143   GeolocationMsg_PermissionSet::Param param;
    144   GeolocationMsg_PermissionSet::Read(message, &param);
    145   EXPECT_EQ(bridge_id, param.a);
    146   EXPECT_EQ(allowed, param.b);
    147   process->sink().ClearMessages();
    148 }
    149 
    150 void GeolocationPermissionContextTests::AddNewTab(const GURL& url) {
    151   TestTabContentsWithPendingInfoBar* new_tab =
    152       new TestTabContentsWithPendingInfoBar(profile(), NULL);
    153   new_tab->controller().LoadURL(url, GURL(), PageTransition::TYPED);
    154   static_cast<TestRenderViewHost*>(new_tab->render_manager()->current_host())->
    155       SendNavigate(extra_tabs_.size() + 1, url);
    156   extra_tabs_.push_back(new_tab);
    157 }
    158 
    159 void GeolocationPermissionContextTests::CheckTabContentsState(
    160     const GURL& requesting_frame,
    161     ContentSetting expected_content_setting) {
    162   TabSpecificContentSettings* content_settings =
    163       contents()->GetTabSpecificContentSettings();
    164   const GeolocationSettingsState::StateMap& state_map =
    165       content_settings->geolocation_settings_state().state_map();
    166   EXPECT_EQ(1U, state_map.count(requesting_frame.GetOrigin()));
    167   EXPECT_EQ(0U, state_map.count(requesting_frame));
    168   GeolocationSettingsState::StateMap::const_iterator settings =
    169       state_map.find(requesting_frame.GetOrigin());
    170   ASSERT_FALSE(settings == state_map.end())
    171       << "geolocation state not found " << requesting_frame;
    172   EXPECT_EQ(expected_content_setting, settings->second);
    173 }
    174 
    175 void GeolocationPermissionContextTests::SetUp() {
    176   RenderViewHostTestHarness::SetUp();
    177   GeolocationArbitrator::SetDependencyFactoryForTest(
    178       dependency_factory_.get());
    179   SiteInstance* site_instance = contents()->GetSiteInstance();
    180   tab_contents_with_pending_infobar_ =
    181       new TestTabContentsWithPendingInfoBar(profile_.get(), site_instance);
    182   SetContents(tab_contents_with_pending_infobar_);
    183   geolocation_permission_context_ =
    184       new GeolocationPermissionContext(profile());
    185 }
    186 
    187 void GeolocationPermissionContextTests::TearDown() {
    188   GeolocationArbitrator::SetDependencyFactoryForTest(NULL);
    189   RenderViewHostTestHarness::TearDown();
    190 }
    191 
    192 
    193 // Tests ----------------------------------------------------------------------
    194 
    195 TEST_F(GeolocationPermissionContextTests, SinglePermission) {
    196   GURL requesting_frame("http://www.example.com/geolocation");
    197   NavigateAndCommit(requesting_frame);
    198   EXPECT_EQ(0U, contents()->infobar_count());
    199   geolocation_permission_context_->RequestGeolocationPermission(
    200       process_id(), render_id(), bridge_id(), requesting_frame);
    201   EXPECT_EQ(1U, contents()->infobar_count());
    202 }
    203 
    204 TEST_F(GeolocationPermissionContextTests, QueuedPermission) {
    205   GURL requesting_frame_0("http://www.example.com/geolocation");
    206   GURL requesting_frame_1("http://www.example-2.com/geolocation");
    207   EXPECT_EQ(CONTENT_SETTING_ASK,
    208       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    209           requesting_frame_0, requesting_frame_0));
    210   EXPECT_EQ(CONTENT_SETTING_ASK,
    211       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    212           requesting_frame_1, requesting_frame_0));
    213 
    214   NavigateAndCommit(requesting_frame_0);
    215   EXPECT_EQ(0U, contents()->infobar_count());
    216   // Request permission for two frames.
    217   geolocation_permission_context_->RequestGeolocationPermission(
    218       process_id(), render_id(), bridge_id(), requesting_frame_0);
    219   geolocation_permission_context_->RequestGeolocationPermission(
    220       process_id(), render_id(), bridge_id() + 1, requesting_frame_1);
    221   // Ensure only one infobar is created.
    222   EXPECT_EQ(1U, contents()->infobar_count());
    223   ConfirmInfoBarDelegate* infobar_0 =
    224       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    225   ASSERT_TRUE(infobar_0);
    226   string16 text_0 = infobar_0->GetMessageText();
    227 
    228   // Accept the first frame.
    229   infobar_0->Accept();
    230   CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
    231   CheckPermissionMessageSent(bridge_id(), true);
    232 
    233   contents()->RemoveInfoBar(infobar_0);
    234   EXPECT_EQ(infobar_0,
    235             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
    236   infobar_0->InfoBarClosed();
    237   // Now we should have a new infobar for the second frame.
    238   EXPECT_EQ(1U, contents()->infobar_count());
    239 
    240   ConfirmInfoBarDelegate* infobar_1 =
    241       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    242   ASSERT_TRUE(infobar_1);
    243   string16 text_1 = infobar_1->GetMessageText();
    244   EXPECT_NE(text_0, text_1);
    245 
    246   // Cancel (block) this frame.
    247   infobar_1->Cancel();
    248   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_BLOCK);
    249   CheckPermissionMessageSent(bridge_id() + 1, false);
    250   contents()->RemoveInfoBar(infobar_1);
    251   EXPECT_EQ(infobar_1,
    252             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
    253   infobar_1->InfoBarClosed();
    254   EXPECT_EQ(0U, contents()->infobar_count());
    255   // Ensure the persisted permissions are ok.
    256   EXPECT_EQ(CONTENT_SETTING_ALLOW,
    257       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    258           requesting_frame_0, requesting_frame_0));
    259   EXPECT_EQ(CONTENT_SETTING_BLOCK,
    260       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    261           requesting_frame_1, requesting_frame_0));
    262 }
    263 
    264 TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) {
    265   GURL requesting_frame_0("http://www.example.com/geolocation");
    266   GURL requesting_frame_1("http://www.example-2.com/geolocation");
    267   EXPECT_EQ(CONTENT_SETTING_ASK,
    268       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    269           requesting_frame_0, requesting_frame_0));
    270   EXPECT_EQ(CONTENT_SETTING_ASK,
    271       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    272           requesting_frame_1, requesting_frame_0));
    273 
    274   NavigateAndCommit(requesting_frame_0);
    275   EXPECT_EQ(0U, contents()->infobar_count());
    276   // Request permission for two frames.
    277   geolocation_permission_context_->RequestGeolocationPermission(
    278       process_id(), render_id(), bridge_id(), requesting_frame_0);
    279   geolocation_permission_context_->RequestGeolocationPermission(
    280       process_id(), render_id(), bridge_id() + 1, requesting_frame_1);
    281   EXPECT_EQ(1U, contents()->infobar_count());
    282 
    283   ConfirmInfoBarDelegate* infobar_0 =
    284       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    285   ASSERT_TRUE(infobar_0);
    286   string16 text_0 = infobar_0->GetMessageText();
    287 
    288   // Simulate the frame going away, ensure the infobar for this frame
    289   // is removed and the next pending infobar is created.
    290   geolocation_permission_context_->CancelGeolocationPermissionRequest(
    291       process_id(), render_id(), bridge_id(), requesting_frame_0);
    292   EXPECT_EQ(infobar_0,
    293             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
    294   infobar_0->InfoBarClosed();
    295   EXPECT_EQ(1U, contents()->infobar_count());
    296 
    297   ConfirmInfoBarDelegate* infobar_1 =
    298       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    299   ASSERT_TRUE(infobar_1);
    300   string16 text_1 = infobar_1->GetMessageText();
    301   EXPECT_NE(text_0, text_1);
    302 
    303   // Allow this frame.
    304   infobar_1->Accept();
    305   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
    306   CheckPermissionMessageSent(bridge_id() + 1, true);
    307   contents()->RemoveInfoBar(infobar_1);
    308   EXPECT_EQ(infobar_1,
    309             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
    310   infobar_1->InfoBarClosed();
    311   EXPECT_EQ(0U, contents()->infobar_count());
    312   // Ensure the persisted permissions are ok.
    313   EXPECT_EQ(CONTENT_SETTING_ASK,
    314       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    315           requesting_frame_0, requesting_frame_0));
    316   EXPECT_EQ(CONTENT_SETTING_ALLOW,
    317       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    318           requesting_frame_1, requesting_frame_0));
    319 }
    320 
    321 TEST_F(GeolocationPermissionContextTests, InvalidURL) {
    322   GURL invalid_embedder;
    323   GURL requesting_frame("about:blank");
    324   NavigateAndCommit(invalid_embedder);
    325   EXPECT_EQ(0U, contents()->infobar_count());
    326   geolocation_permission_context_->RequestGeolocationPermission(
    327       process_id(), render_id(), bridge_id(), requesting_frame);
    328   EXPECT_EQ(0U, contents()->infobar_count());
    329   CheckPermissionMessageSent(bridge_id(), false);
    330 }
    331 
    332 TEST_F(GeolocationPermissionContextTests, SameOriginMultipleTabs) {
    333   GURL url_a("http://www.example.com/geolocation");
    334   GURL url_b("http://www.example-2.com/geolocation");
    335   NavigateAndCommit(url_a);
    336   AddNewTab(url_b);
    337   AddNewTab(url_a);
    338 
    339   EXPECT_EQ(0U, contents()->infobar_count());
    340   geolocation_permission_context_->RequestGeolocationPermission(
    341       process_id(), render_id(), bridge_id(), url_a);
    342   EXPECT_EQ(1U, contents()->infobar_count());
    343 
    344   geolocation_permission_context_->RequestGeolocationPermission(
    345       process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_b);
    346   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
    347 
    348   geolocation_permission_context_->RequestGeolocationPermission(
    349       process_id_for_tab(1), render_id_for_tab(1), bridge_id(), url_a);
    350   EXPECT_EQ(1U, extra_tabs_[1]->infobar_count());
    351 
    352   ConfirmInfoBarDelegate* removed_infobar =
    353       extra_tabs_[1]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    354 
    355   // Accept the first tab.
    356   ConfirmInfoBarDelegate* infobar_0 =
    357       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    358   ASSERT_TRUE(infobar_0);
    359   infobar_0->Accept();
    360   CheckPermissionMessageSent(bridge_id(), true);
    361   contents()->RemoveInfoBar(infobar_0);
    362   EXPECT_EQ(infobar_0,
    363             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
    364   infobar_0->InfoBarClosed();
    365   // Now the infobar for the tab with the same origin should have gone.
    366   EXPECT_EQ(0U, extra_tabs_[1]->infobar_count());
    367   CheckPermissionMessageSentForTab(1, bridge_id(), true);
    368   // Destroy the infobar that has just been removed.
    369   removed_infobar->InfoBarClosed();
    370 
    371   // But the other tab should still have the info bar...
    372   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
    373   extra_tabs_.reset();
    374 }
    375 
    376 TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) {
    377   GURL url_a("http://www.example.com/geolocation");
    378   GURL url_b("http://www.example-2.com/geolocation");
    379   NavigateAndCommit(url_a);
    380   AddNewTab(url_a);
    381 
    382   EXPECT_EQ(0U, contents()->infobar_count());
    383   geolocation_permission_context_->RequestGeolocationPermission(
    384       process_id(), render_id(), bridge_id(), url_a);
    385   EXPECT_EQ(1U, contents()->infobar_count());
    386 
    387   geolocation_permission_context_->RequestGeolocationPermission(
    388       process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_a);
    389   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
    390 
    391   geolocation_permission_context_->RequestGeolocationPermission(
    392       process_id_for_tab(0), render_id_for_tab(0), bridge_id() + 1, url_b);
    393   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
    394 
    395   ConfirmInfoBarDelegate* removed_infobar =
    396       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    397 
    398   // Accept the second tab.
    399   ConfirmInfoBarDelegate* infobar_0 =
    400       extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    401   ASSERT_TRUE(infobar_0);
    402   infobar_0->Accept();
    403   CheckPermissionMessageSentForTab(0, bridge_id(), true);
    404   extra_tabs_[0]->RemoveInfoBar(infobar_0);
    405   EXPECT_EQ(infobar_0,
    406             extra_tabs_[0]->removed_infobar_delegate_);
    407   infobar_0->InfoBarClosed();
    408   // Now the infobar for the tab with the same origin should have gone.
    409   EXPECT_EQ(0U, contents()->infobar_count());
    410   CheckPermissionMessageSent(bridge_id(), true);
    411   // Destroy the infobar that has just been removed.
    412   removed_infobar->InfoBarClosed();
    413 
    414   // And we should have the queued infobar displayed now.
    415   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
    416 
    417   // Accept the second infobar.
    418   ConfirmInfoBarDelegate* infobar_1 =
    419       extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    420   ASSERT_TRUE(infobar_1);
    421   infobar_1->Accept();
    422   CheckPermissionMessageSentForTab(0, bridge_id() + 1, true);
    423   extra_tabs_[0]->RemoveInfoBar(infobar_1);
    424   EXPECT_EQ(infobar_1,
    425             extra_tabs_[0]->removed_infobar_delegate_);
    426   infobar_1->InfoBarClosed();
    427 
    428   extra_tabs_.reset();
    429 }
    430 
    431 TEST_F(GeolocationPermissionContextTests, TabDestroyed) {
    432   GURL requesting_frame_0("http://www.example.com/geolocation");
    433   GURL requesting_frame_1("http://www.example-2.com/geolocation");
    434   EXPECT_EQ(
    435       CONTENT_SETTING_ASK,
    436       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    437           requesting_frame_0, requesting_frame_0));
    438   EXPECT_EQ(
    439       CONTENT_SETTING_ASK,
    440       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
    441           requesting_frame_1, requesting_frame_0));
    442 
    443   NavigateAndCommit(requesting_frame_0);
    444   EXPECT_EQ(0U, contents()->infobar_count());
    445   // Request permission for two frames.
    446   geolocation_permission_context_->RequestGeolocationPermission(
    447       process_id(), render_id(), bridge_id(), requesting_frame_0);
    448   geolocation_permission_context_->RequestGeolocationPermission(
    449       process_id(), render_id(), bridge_id() + 1, requesting_frame_1);
    450   // Ensure only one infobar is created.
    451   EXPECT_EQ(1U, contents()->infobar_count());
    452   ConfirmInfoBarDelegate* infobar_0 =
    453       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
    454   ASSERT_TRUE(infobar_0);
    455   string16 text_0 = infobar_0->GetMessageText();
    456 
    457   // Delete the tab contents.
    458   DeleteContents();
    459 }
    460