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/compiler_specific.h"
6#include "base/string_number_conversions.h"
7#include "base/string_util.h"
8#include "base/utf_string_conversions.h"
9#include "chrome/browser/dom_operation_notification_details.h"
10#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
11#include "chrome/browser/geolocation/geolocation_settings_state.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
14#include "chrome/browser/ui/browser.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/common/chrome_paths.h"
17#include "chrome/test/in_process_browser_test.h"
18#include "chrome/test/ui_test_utils.h"
19#include "content/browser/geolocation/arbitrator_dependency_factories_for_test.h"
20#include "content/browser/geolocation/location_arbitrator.h"
21#include "content/browser/geolocation/mock_location_provider.h"
22#include "content/browser/renderer_host/render_view_host.h"
23#include "content/browser/tab_contents/tab_contents.h"
24#include "content/common/geoposition.h"
25#include "content/common/notification_details.h"
26#include "content/common/notification_service.h"
27#include "content/common/notification_type.h"
28#include "net/base/net_util.h"
29#include "net/test/test_server.h"
30
31namespace {
32
33// Used to block until an iframe is loaded via a javascript call.
34// Note: NavigateToURLBlockUntilNavigationsComplete doesn't seem to work for
35// multiple embedded iframes, as notifications seem to be 'batched'. Instead, we
36// load and wait one single frame here by calling a javascript function.
37class IFrameLoader : public NotificationObserver {
38 public:
39  IFrameLoader(Browser* browser, int iframe_id, const GURL& url)
40      : navigation_completed_(false),
41        javascript_completed_(false) {
42    NavigationController* controller =
43        &browser->GetSelectedTabContents()->controller();
44    registrar_.Add(this, NotificationType::LOAD_STOP,
45                   Source<NavigationController>(controller));
46    registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE,
47                   NotificationService::AllSources());
48    std::string script = StringPrintf(
49        "window.domAutomationController.setAutomationId(0);"
50        "window.domAutomationController.send(addIFrame(%d, \"%s\"));",
51        iframe_id,
52        url.spec().c_str());
53    browser->GetSelectedTabContents()->render_view_host()->
54        ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(script));
55    ui_test_utils::RunMessageLoop();
56
57    EXPECT_EQ(StringPrintf("\"%d\"", iframe_id), javascript_response_);
58    registrar_.RemoveAll();
59    // Now that we loaded the iframe, let's fetch its src.
60    script = StringPrintf(
61        "window.domAutomationController.send(getIFrameSrc(%d))", iframe_id);
62    std::string iframe_src;
63    EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
64        browser->GetSelectedTabContents()->render_view_host(),
65        L"", UTF8ToWide(script), &iframe_src));
66    iframe_url_ = GURL(iframe_src);
67  }
68
69  GURL iframe_url() const { return iframe_url_; }
70
71  virtual void Observe(NotificationType type,
72                       const NotificationSource& source,
73                       const NotificationDetails& details) {
74    if (type == NotificationType::LOAD_STOP) {
75      navigation_completed_ = true;
76    } else if (type == NotificationType::DOM_OPERATION_RESPONSE) {
77      Details<DomOperationNotificationDetails> dom_op_details(details);
78      javascript_response_ = dom_op_details->json();
79      javascript_completed_ = true;
80    }
81    if (javascript_completed_ && navigation_completed_)
82      MessageLoopForUI::current()->Quit();
83  }
84
85 private:
86  NotificationRegistrar registrar_;
87
88  // If true the navigation has completed.
89  bool navigation_completed_;
90
91  // If true the javascript call has completed.
92  bool javascript_completed_;
93
94  std::string javascript_response_;
95
96  // The URL for the iframe we just loaded.
97  GURL iframe_url_;
98
99  DISALLOW_COPY_AND_ASSIGN(IFrameLoader);
100};
101
102class GeolocationNotificationObserver : public NotificationObserver {
103 public:
104  // If |wait_for_infobar| is true, AddWatchAndWaitForNotification will block
105  // until the infobar has been displayed; otherwise it will block until the
106  // navigation is completed.
107  explicit GeolocationNotificationObserver(bool wait_for_infobar)
108    : wait_for_infobar_(wait_for_infobar),
109      infobar_(NULL),
110      navigation_started_(false),
111      navigation_completed_(false) {
112    registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE,
113                   NotificationService::AllSources());
114    if (wait_for_infobar) {
115      registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED,
116                     NotificationService::AllSources());
117    } else {
118      registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
119                     NotificationService::AllSources());
120      registrar_.Add(this, NotificationType::LOAD_START,
121                     NotificationService::AllSources());
122      registrar_.Add(this, NotificationType::LOAD_STOP,
123                     NotificationService::AllSources());
124    }
125  }
126
127  void AddWatchAndWaitForNotification(RenderViewHost* render_view_host,
128                                      const std::wstring& iframe_xpath) {
129    LOG(WARNING) << "will add geolocation watch";
130    std::string script =
131        "window.domAutomationController.setAutomationId(0);"
132        "window.domAutomationController.send(geoStart());";
133    render_view_host->ExecuteJavascriptInWebFrame(WideToUTF16Hack(iframe_xpath),
134                                                  UTF8ToUTF16(script));
135    ui_test_utils::RunMessageLoop();
136    registrar_.RemoveAll();
137    LOG(WARNING) << "got geolocation watch" << javascript_response_;
138    EXPECT_NE("\"0\"", javascript_response_);
139    if (wait_for_infobar_) {
140      EXPECT_TRUE(infobar_);
141    } else {
142      EXPECT_TRUE(navigation_completed_);
143    }
144  }
145
146  // NotificationObserver
147  virtual void Observe(NotificationType type,
148                       const NotificationSource& source,
149                       const NotificationDetails& details) {
150    if (type.value == NotificationType::TAB_CONTENTS_INFOBAR_ADDED) {
151      infobar_ = Details<InfoBarDelegate>(details).ptr();
152      ASSERT_TRUE(infobar_->GetIcon());
153      ASSERT_TRUE(infobar_->AsConfirmInfoBarDelegate());
154    } else if (type == NotificationType::DOM_OPERATION_RESPONSE) {
155      Details<DomOperationNotificationDetails> dom_op_details(details);
156      javascript_response_ = dom_op_details->json();
157      LOG(WARNING) << "javascript_response " << javascript_response_;
158    } else if (type == NotificationType::NAV_ENTRY_COMMITTED ||
159               type == NotificationType::LOAD_START) {
160      navigation_started_ = true;
161    } else if (type == NotificationType::LOAD_STOP) {
162      if (navigation_started_) {
163        navigation_started_ = false;
164        navigation_completed_ = true;
165      }
166    }
167
168    // We're either waiting for just the inforbar, or for both a javascript
169    // prompt and response.
170    if (wait_for_infobar_ && infobar_)
171      MessageLoopForUI::current()->Quit();
172    else if (navigation_completed_ && !javascript_response_.empty())
173      MessageLoopForUI::current()->Quit();
174  }
175
176  NotificationRegistrar registrar_;
177  bool wait_for_infobar_;
178  InfoBarDelegate* infobar_;
179  bool navigation_started_;
180  bool navigation_completed_;
181  std::string javascript_response_;
182};
183
184void NotifyGeoposition(const Geoposition& geoposition) {
185  DCHECK(MockLocationProvider::instance_);
186  MockLocationProvider::instance_->HandlePositionChanged(geoposition);
187  LOG(WARNING) << "MockLocationProvider listeners updated";
188}
189
190// This is a browser test for Geolocation.
191// It exercises various integration points from javascript <-> browser:
192// 1. Infobar is displayed when a geolocation is requested from an unauthorized
193// origin.
194// 2. Denying the infobar triggers the correct error callback.
195// 3. Allowing the infobar does not trigger an error, and allow a geoposition to
196// be passed to javascript.
197// 4. Permissions persisted in disk are respected.
198// 5. Incognito profiles don't use saved permissions.
199class GeolocationBrowserTest : public InProcessBrowserTest {
200 public:
201  GeolocationBrowserTest()
202    : infobar_(NULL),
203      current_browser_(NULL),
204      html_for_tests_("files/geolocation/simple.html"),
205      started_test_server_(false),
206      dependency_factory_(
207          new GeolocationArbitratorDependencyFactoryWithLocationProvider(
208              &NewAutoSuccessMockNetworkLocationProvider)) {
209    EnableDOMAutomation();
210  }
211
212  // InProcessBrowserTest
213  virtual void SetUpInProcessBrowserTestFixture() {
214    GeolocationArbitrator::SetDependencyFactoryForTest(
215        dependency_factory_.get());
216  }
217
218  // InProcessBrowserTest
219  virtual void TearDownInProcessBrowserTestFixture() {
220    LOG(WARNING) << "TearDownInProcessBrowserTestFixture. Test Finished.";
221    GeolocationArbitrator::SetDependencyFactoryForTest(NULL);
222  }
223
224  enum InitializationOptions {
225    INITIALIZATION_NONE,
226    INITIALIZATION_OFFTHERECORD,
227    INITIALIZATION_NEWTAB,
228    INITIALIZATION_IFRAMES,
229  };
230
231  bool Initialize(InitializationOptions options) WARN_UNUSED_RESULT {
232    if (!started_test_server_)
233      started_test_server_ = test_server()->Start();
234    EXPECT_TRUE(started_test_server_);
235    if (!started_test_server_)
236      return false;
237
238    current_url_ = test_server()->GetURL(html_for_tests_);
239    LOG(WARNING) << "before navigate";
240    if (options == INITIALIZATION_OFFTHERECORD) {
241      ui_test_utils::OpenURLOffTheRecord(browser()->profile(), current_url_);
242      current_browser_ = BrowserList::FindBrowserWithType(
243          browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
244          false);
245    } else if (options == INITIALIZATION_NEWTAB) {
246      current_browser_ = browser();
247      current_browser_->NewTab();
248      ui_test_utils::NavigateToURL(current_browser_, current_url_);
249    } else if (options == INITIALIZATION_IFRAMES) {
250      current_browser_ = browser();
251      ui_test_utils::NavigateToURL(current_browser_, current_url_);
252    } else {
253      current_browser_ = browser();
254      ui_test_utils::NavigateToURL(current_browser_, current_url_);
255    }
256    LOG(WARNING) << "after navigate";
257
258    EXPECT_TRUE(current_browser_);
259    if (!current_browser_)
260      return false;
261
262    return true;
263  }
264
265  void LoadIFrames(int number_iframes) {
266      // Limit to 3 iframes.
267      DCHECK(0 < number_iframes && number_iframes <= 3);
268      iframe_urls_.resize(number_iframes);
269      for (int i = 0; i < number_iframes; ++i) {
270        IFrameLoader loader(current_browser_, i, GURL());
271        iframe_urls_[i] = loader.iframe_url();
272      }
273  }
274
275  void AddGeolocationWatch(bool wait_for_infobar) {
276    GeolocationNotificationObserver notification_observer(wait_for_infobar);
277    notification_observer.AddWatchAndWaitForNotification(
278        current_browser_->GetSelectedTabContents()->render_view_host(),
279        iframe_xpath_);
280    if (wait_for_infobar) {
281      EXPECT_TRUE(notification_observer.infobar_);
282      infobar_ = notification_observer.infobar_;
283    }
284  }
285
286  Geoposition GeopositionFromLatLong(double latitude, double longitude) {
287    Geoposition geoposition;
288    geoposition.latitude = latitude;
289    geoposition.longitude = longitude;
290    geoposition.accuracy = 0;
291    geoposition.error_code = Geoposition::ERROR_CODE_NONE;
292    // Webkit compares the timestamp to wall clock time, so we need
293    // it to be contemporary.
294    geoposition.timestamp = base::Time::Now();
295    EXPECT_TRUE(geoposition.IsValidFix());
296    return geoposition;
297  }
298
299  void CheckGeoposition(const Geoposition& geoposition) {
300    // Checks we have no error.
301    CheckStringValueFromJavascript("0", "geoGetLastError()");
302    CheckStringValueFromJavascript(base::DoubleToString(geoposition.latitude),
303                                   "geoGetLastPositionLatitude()");
304    CheckStringValueFromJavascript(base::DoubleToString(geoposition.longitude),
305                                   "geoGetLastPositionLongitude()");
306  }
307
308  void SetInfobarResponse(const GURL& requesting_url, bool allowed) {
309    TabContents* tab_contents = current_browser_->GetSelectedTabContents();
310    TabSpecificContentSettings* content_settings =
311        tab_contents->GetTabSpecificContentSettings();
312    const GeolocationSettingsState& settings_state =
313        content_settings->geolocation_settings_state();
314    size_t state_map_size = settings_state.state_map().size();
315    ASSERT_TRUE(infobar_);
316    LOG(WARNING) << "will set infobar response";
317    if (allowed)
318      infobar_->AsConfirmInfoBarDelegate()->Accept();
319    else
320      infobar_->AsConfirmInfoBarDelegate()->Cancel();
321    WaitForNavigation();
322    tab_contents->RemoveInfoBar(infobar_);
323    LOG(WARNING) << "infobar response set";
324    infobar_ = NULL;
325    EXPECT_GT(settings_state.state_map().size(), state_map_size);
326    GURL requesting_origin = requesting_url.GetOrigin();
327    EXPECT_EQ(1U, settings_state.state_map().count(requesting_origin));
328    ContentSetting expected_setting =
329          allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
330    EXPECT_EQ(expected_setting,
331              settings_state.state_map().find(requesting_origin)->second);
332  }
333
334  void WaitForNavigation() {
335    LOG(WARNING) << "will block for navigation";
336    NavigationController* controller =
337        &current_browser_->GetSelectedTabContents()->controller();
338    ui_test_utils::WaitForNavigation(controller);
339    LOG(WARNING) << "navigated";
340  }
341
342  void CheckStringValueFromJavascriptForTab(
343      const std::string& expected, const std::string& function,
344      TabContents* tab_contents) {
345    std::string script = StringPrintf(
346        "window.domAutomationController.send(%s)", function.c_str());
347    std::string result;
348    ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
349        tab_contents->render_view_host(),
350        iframe_xpath_, UTF8ToWide(script), &result));
351    EXPECT_EQ(expected, result);
352  }
353
354  void CheckStringValueFromJavascript(
355      const std::string& expected, const std::string& function) {
356    CheckStringValueFromJavascriptForTab(
357        expected, function, current_browser_->GetSelectedTabContents());
358  }
359
360  InfoBarDelegate* infobar_;
361  Browser* current_browser_;
362  // path element of a URL referencing the html content for this test.
363  std::string html_for_tests_;
364  // This member defines the iframe (or top-level page, if empty) where the
365  // javascript calls will run.
366  std::wstring iframe_xpath_;
367  // The current url for the top level page.
368  GURL current_url_;
369  // If not empty, the GURLs for the iframes loaded by LoadIFrames().
370  std::vector<GURL> iframe_urls_;
371
372  // TODO(phajdan.jr): Remove after we can ask TestServer whether it is started.
373  bool started_test_server_;
374
375  scoped_refptr<GeolocationArbitratorDependencyFactory> dependency_factory_;
376};
377
378IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DisplaysPermissionBar) {
379  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
380  AddGeolocationWatch(true);
381}
382
383IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, Geoposition) {
384  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
385  AddGeolocationWatch(true);
386  SetInfobarResponse(current_url_, true);
387  CheckGeoposition(MockLocationProvider::instance_->position_);
388}
389
390// Crashy, http://crbug.com/70585.
391IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
392                       DISABLED_ErrorOnPermissionDenied) {
393  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
394  AddGeolocationWatch(true);
395  // Infobar was displayed, deny access and check for error code.
396  SetInfobarResponse(current_url_, false);
397  CheckStringValueFromJavascript("1", "geoGetLastError()");
398}
399
400// http://crbug.com/44589. Hangs on Mac, crashes on Windows
401#if defined(OS_MACOSX) || defined(OS_WINDOWS)
402#define MAYBE_NoInfobarForSecondTab DISABLED_NoInfobarForSecondTab
403#else
404#define MAYBE_NoInfobarForSecondTab NoInfobarForSecondTab
405#endif
406IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForSecondTab) {
407  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
408  AddGeolocationWatch(true);
409  SetInfobarResponse(current_url_, true);
410  // Disables further prompts from this tab.
411  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
412
413  // Checks infobar will not be created a second tab.
414  ASSERT_TRUE(Initialize(INITIALIZATION_NEWTAB));
415  AddGeolocationWatch(false);
416  CheckGeoposition(MockLocationProvider::instance_->position_);
417}
418
419// http://crbug.com/44589. Hangs on Mac, crashes on Windows
420#if defined(OS_MACOSX) || defined(OS_WINDOWS)
421#define MAYBE_NoInfobarForDeniedOrigin DISABLED_NoInfobarForDeniedOrigin
422#else
423#define MAYBE_NoInfobarForDeniedOrigin NoInfobarForDeniedOrigin
424#endif
425IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForDeniedOrigin) {
426  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
427  current_browser_->profile()->GetGeolocationContentSettingsMap()->
428      SetContentSetting(current_url_, current_url_, CONTENT_SETTING_BLOCK);
429  AddGeolocationWatch(false);
430  // Checks we have an error for this denied origin.
431  CheckStringValueFromJavascript("1", "geoGetLastError()");
432  // Checks infobar will not be created a second tab.
433  ASSERT_TRUE(Initialize(INITIALIZATION_NEWTAB));
434  AddGeolocationWatch(false);
435  CheckStringValueFromJavascript("1", "geoGetLastError()");
436}
437
438IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForAllowedOrigin) {
439  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
440  current_browser_->profile()->GetGeolocationContentSettingsMap()->
441      SetContentSetting(current_url_, current_url_, CONTENT_SETTING_ALLOW);
442  // Checks no infobar will be created and there's no error callback.
443  AddGeolocationWatch(false);
444  CheckGeoposition(MockLocationProvider::instance_->position_);
445}
446
447IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForOffTheRecord) {
448  // First, check infobar will be created for regular profile
449  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
450  AddGeolocationWatch(true);
451  // Response will be persisted
452  SetInfobarResponse(current_url_, true);
453  CheckGeoposition(MockLocationProvider::instance_->position_);
454  // Disables further prompts from this tab.
455  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
456  // Go incognito, and checks no infobar will be created.
457  ASSERT_TRUE(Initialize(INITIALIZATION_OFFTHERECORD));
458  AddGeolocationWatch(false);
459  CheckGeoposition(MockLocationProvider::instance_->position_);
460}
461
462IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithFreshPosition) {
463  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
464  ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
465  LoadIFrames(2);
466  LOG(WARNING) << "frames loaded";
467
468  iframe_xpath_ = L"//iframe[@id='iframe_0']";
469  AddGeolocationWatch(true);
470  SetInfobarResponse(iframe_urls_[0], true);
471  CheckGeoposition(MockLocationProvider::instance_->position_);
472  // Disables further prompts from this iframe.
473  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
474
475  // Test second iframe from a different origin with a cached geoposition will
476  // create the infobar.
477  iframe_xpath_ = L"//iframe[@id='iframe_1']";
478  AddGeolocationWatch(true);
479
480  // Back to the first frame, enable navigation and refresh geoposition.
481  iframe_xpath_ = L"//iframe[@id='iframe_0']";
482  CheckStringValueFromJavascript("1", "geoSetMaxNavigateCount(1)");
483  // MockLocationProvider must have been created.
484  ASSERT_TRUE(MockLocationProvider::instance_);
485  Geoposition fresh_position = GeopositionFromLatLong(3.17, 4.23);
486  NotifyGeoposition(fresh_position);
487  WaitForNavigation();
488  CheckGeoposition(fresh_position);
489
490  // Disable navigation for this frame.
491  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
492
493  // Now go ahead an authorize the second frame.
494  iframe_xpath_ = L"//iframe[@id='iframe_1']";
495  // Infobar was displayed, allow access and check there's no error code.
496  SetInfobarResponse(iframe_urls_[1], true);
497  LOG(WARNING) << "Checking position...";
498  CheckGeoposition(fresh_position);
499  LOG(WARNING) << "...done.";
500}
501
502IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithCachedPosition) {
503  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
504  ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
505  LoadIFrames(2);
506
507  iframe_xpath_ = L"//iframe[@id='iframe_0']";
508  AddGeolocationWatch(true);
509  SetInfobarResponse(iframe_urls_[0], true);
510  CheckGeoposition(MockLocationProvider::instance_->position_);
511
512  // Refresh geoposition, but let's not yet create the watch on the second frame
513  // so that it'll fetch from cache.
514  // MockLocationProvider must have been created.
515  ASSERT_TRUE(MockLocationProvider::instance_);
516  Geoposition cached_position = GeopositionFromLatLong(5.67, 8.09);
517  NotifyGeoposition(cached_position);
518  WaitForNavigation();
519  CheckGeoposition(cached_position);
520
521  // Disable navigation for this frame.
522  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
523
524  // Now go ahead an authorize the second frame.
525  iframe_xpath_ = L"//iframe[@id='iframe_1']";
526  AddGeolocationWatch(true);
527  // WebKit will use its cache, but we also broadcast a position shortly
528  // afterwards. We're only interested in the first navigation for the success
529  // callback from the cached position.
530  CheckStringValueFromJavascript("1", "geoSetMaxNavigateCount(1)");
531  SetInfobarResponse(iframe_urls_[1], true);
532  CheckGeoposition(cached_position);
533}
534
535// See http://crbug.com/56033
536IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
537                       DISABLED_CancelPermissionForFrame) {
538  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
539  ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
540  LoadIFrames(2);
541  LOG(WARNING) << "frames loaded";
542
543  iframe_xpath_ = L"//iframe[@id='iframe_0']";
544  AddGeolocationWatch(true);
545  SetInfobarResponse(iframe_urls_[0], true);
546  CheckGeoposition(MockLocationProvider::instance_->position_);
547  // Disables further prompts from this iframe.
548  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
549
550  // Test second iframe from a different origin with a cached geoposition will
551  // create the infobar.
552  iframe_xpath_ = L"//iframe[@id='iframe_1']";
553  AddGeolocationWatch(true);
554
555  size_t num_infobars_before_cancel =
556      current_browser_->GetSelectedTabContents()->infobar_count();
557  // Change the iframe, and ensure the infobar is gone.
558  IFrameLoader change_iframe_1(current_browser_, 1, current_url_);
559  size_t num_infobars_after_cancel =
560      current_browser_->GetSelectedTabContents()->infobar_count();
561  EXPECT_EQ(num_infobars_before_cancel, num_infobars_after_cancel + 1);
562}
563
564// Disabled, http://crbug.com/66959.
565IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_InvalidUrlRequest) {
566  // Tests that an invalid URL (e.g. from a popup window) is rejected
567  // correctly. Also acts as a regression test for http://crbug.com/40478
568  html_for_tests_ = "files/geolocation/invalid_request_url.html";
569  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
570  TabContents* original_tab = current_browser_->GetSelectedTabContents();
571  CheckStringValueFromJavascript("1", "requestGeolocationFromInvalidUrl()");
572  CheckStringValueFromJavascriptForTab("1", "isAlive()", original_tab);
573}
574
575// Crashy, http://crbug.com/66400.
576IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_NoInfoBarBeforeStart) {
577  // See http://crbug.com/42789
578  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
579  ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
580  LoadIFrames(2);
581  LOG(WARNING) << "frames loaded";
582
583  // Access navigator.geolocation, but ensure it won't request permission.
584  iframe_xpath_ = L"//iframe[@id='iframe_1']";
585  CheckStringValueFromJavascript("object", "geoAccessNavigatorGeolocation()");
586
587  iframe_xpath_ = L"//iframe[@id='iframe_0']";
588  AddGeolocationWatch(true);
589  SetInfobarResponse(iframe_urls_[0], true);
590  CheckGeoposition(MockLocationProvider::instance_->position_);
591  CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)");
592
593  // Permission should be requested after adding a watch.
594  iframe_xpath_ = L"//iframe[@id='iframe_1']";
595  AddGeolocationWatch(true);
596  SetInfobarResponse(iframe_urls_[1], true);
597  CheckGeoposition(MockLocationProvider::instance_->position_);
598}
599
600IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TwoWatchesInOneFrame) {
601  html_for_tests_ = "files/geolocation/two_watches.html";
602  ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
603  // First, set the JavaScript to navigate when it receives |final_position|.
604  const Geoposition final_position = GeopositionFromLatLong(3.17, 4.23);
605  std::string script = StringPrintf(
606      "window.domAutomationController.send(geoSetFinalPosition(%f, %f))",
607      final_position.latitude, final_position.longitude);
608  std::string js_result;
609  EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
610      current_browser_->GetSelectedTabContents()->render_view_host(),
611      L"", UTF8ToWide(script), &js_result));
612  EXPECT_EQ(js_result, "ok");
613
614  // Send a position which both geolocation watches will receive.
615  AddGeolocationWatch(true);
616  SetInfobarResponse(current_url_, true);
617  CheckGeoposition(MockLocationProvider::instance_->position_);
618
619  // The second watch will now have cancelled. Ensure an update still makes
620  // its way through to the first watcher.
621  NotifyGeoposition(final_position);
622  WaitForNavigation();
623  CheckGeoposition(final_position);
624}
625
626// Hangs flakily, http://crbug.com/70588.
627IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_TabDestroyed) {
628  html_for_tests_ = "files/geolocation/tab_destroyed.html";
629  ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
630  LoadIFrames(3);
631
632  iframe_xpath_ = L"//iframe[@id='iframe_0']";
633  AddGeolocationWatch(true);
634
635  iframe_xpath_ = L"//iframe[@id='iframe_1']";
636  AddGeolocationWatch(false);
637
638  iframe_xpath_ = L"//iframe[@id='iframe_2']";
639  AddGeolocationWatch(false);
640
641  std::string script =
642      "window.domAutomationController.setAutomationId(0);"
643      "window.domAutomationController.send(window.close());";
644  bool result =
645      ui_test_utils::ExecuteJavaScript(
646      current_browser_->GetSelectedTabContents()->render_view_host(),
647      L"", UTF8ToWide(script));
648  EXPECT_EQ(result, true);
649}
650
651}  // namespace
652