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
TestTabContentsWithPendingInfoBar(Profile * profile,SiteInstance * instance)43 TestTabContentsWithPendingInfoBar::TestTabContentsWithPendingInfoBar(
44 Profile* profile,
45 SiteInstance* instance)
46 : TestTabContents(profile, instance),
47 removed_infobar_delegate_(NULL) {
48 }
49
~TestTabContentsWithPendingInfoBar()50 TestTabContentsWithPendingInfoBar::~TestTabContentsWithPendingInfoBar() {
51 }
52
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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
process_id()76 int process_id() { return contents()->render_view_host()->process()->id(); }
process_id_for_tab(int tab)77 int process_id_for_tab(int tab) {
78 return extra_tabs_[tab]->render_view_host()->process()->id();
79 }
render_id()80 int render_id() { return contents()->render_view_host()->routing_id(); }
render_id_for_tab(int tab)81 int render_id_for_tab(int tab) {
82 return extra_tabs_[tab]->render_view_host()->routing_id();
83 }
bridge_id() const84 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
GeolocationPermissionContextTests()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
~GeolocationPermissionContextTests()117 GeolocationPermissionContextTests::~GeolocationPermissionContextTests() {
118 }
119
CheckPermissionMessageSent(int bridge_id,bool allowed)120 void GeolocationPermissionContextTests::CheckPermissionMessageSent(
121 int bridge_id,
122 bool allowed) {
123 CheckPermissionMessageSentInternal(process(), bridge_id, allowed);
124 }
125
CheckPermissionMessageSentForTab(int tab,int bridge_id,bool allowed)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
CheckPermissionMessageSentInternal(MockRenderProcessHost * process,int bridge_id,bool allowed)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, ¶m);
145 EXPECT_EQ(bridge_id, param.a);
146 EXPECT_EQ(allowed, param.b);
147 process->sink().ClearMessages();
148 }
149
AddNewTab(const GURL & url)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
CheckTabContentsState(const GURL & requesting_frame,ContentSetting expected_content_setting)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
SetUp()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
TearDown()187 void GeolocationPermissionContextTests::TearDown() {
188 GeolocationArbitrator::SetDependencyFactoryForTest(NULL);
189 RenderViewHostTestHarness::TearDown();
190 }
191
192
193 // Tests ----------------------------------------------------------------------
194
TEST_F(GeolocationPermissionContextTests,SinglePermission)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
TEST_F(GeolocationPermissionContextTests,QueuedPermission)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
TEST_F(GeolocationPermissionContextTests,CancelGeolocationPermissionRequest)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
TEST_F(GeolocationPermissionContextTests,InvalidURL)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
TEST_F(GeolocationPermissionContextTests,SameOriginMultipleTabs)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
TEST_F(GeolocationPermissionContextTests,QueuedOriginMultipleTabs)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
TEST_F(GeolocationPermissionContextTests,TabDestroyed)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