1 // Copyright (c) 2012 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.
5 #include "base/logging.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/frame_host/cross_site_transferring_request.h"
8 #include "content/browser/frame_host/interstitial_page_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.h"
10 #include "content/browser/media/audio_stream_monitor.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/site_instance_impl.h"
13 #include "content/browser/webui/web_ui_controller_factory_registry.h"
14 #include "content/common/frame_messages.h"
15 #include "content/common/input/synthetic_web_input_event_builders.h"
16 #include "content/common/view_messages.h"
17 #include "content/public/browser/global_request_id.h"
18 #include "content/public/browser/interstitial_page_delegate.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_source.h"
22 #include "content/public/browser/render_widget_host_view.h"
23 #include "content/public/browser/web_contents_delegate.h"
24 #include "content/public/browser/web_contents_observer.h"
25 #include "content/public/browser/web_ui_controller.h"
26 #include "content/public/common/bindings_policy.h"
27 #include "content/public/common/content_constants.h"
28 #include "content/public/common/url_constants.h"
29 #include "content/public/common/url_utils.h"
30 #include "content/public/test/mock_render_process_host.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/test/test_content_browser_client.h"
33 #include "content/test/test_content_client.h"
34 #include "content/test/test_render_frame_host.h"
35 #include "content/test/test_render_view_host.h"
36 #include "content/test/test_web_contents.h"
37 #include "testing/gtest/include/gtest/gtest.h"
42 const char kTestWebUIUrl[] = "chrome://blah";
44 class WebContentsImplTestWebUIControllerFactory
45 : public WebUIControllerFactory {
47 virtual WebUIController* CreateWebUIControllerForURL(
48 WebUI* web_ui, const GURL& url) const OVERRIDE {
51 return new WebUIController(web_ui);
54 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
55 const GURL& url) const OVERRIDE {
56 return WebUI::kNoWebUI;
59 virtual bool UseWebUIForURL(BrowserContext* browser_context,
60 const GURL& url) const OVERRIDE {
64 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
65 const GURL& url) const OVERRIDE {
70 bool UseWebUI(const GURL& url) const {
71 return url == GURL(kTestWebUIUrl);
75 class TestInterstitialPage;
77 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
79 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
80 : interstitial_page_(interstitial_page) {}
81 virtual void CommandReceived(const std::string& command) OVERRIDE;
82 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
83 virtual void OnDontProceed() OVERRIDE;
84 virtual void OnProceed() OVERRIDE;
86 TestInterstitialPage* interstitial_page_;
89 class TestInterstitialPage : public InterstitialPageImpl {
91 enum InterstitialState {
92 INVALID = 0, // Hasn't yet been initialized.
93 UNDECIDED, // Initialized, but no decision taken yet.
94 OKED, // Proceed was called.
95 CANCELED // DontProceed was called.
100 virtual void TestInterstitialPageDeleted(
101 TestInterstitialPage* interstitial) = 0;
104 virtual ~Delegate() {}
107 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
108 // |deleted| (like all interstitial related tests do at this point), make sure
109 // to create an instance of the TestInterstitialPageStateGuard class on the
110 // stack in your test. This will ensure that the TestInterstitialPage states
111 // are cleared when the test finishes.
112 // Not doing so will cause stack trashing if your test does not hide the
113 // interstitial, as in such a case it will be destroyed in the test TearDown
114 // method and will dereference the |deleted| local variable which by then is
116 TestInterstitialPage(WebContentsImpl* contents,
119 InterstitialState* state,
121 : InterstitialPageImpl(
123 static_cast<RenderWidgetHostDelegate*>(contents),
124 new_navigation, url, new TestInterstitialPageDelegate(this)),
127 command_received_count_(0),
133 virtual ~TestInterstitialPage() {
137 delegate_->TestInterstitialPageDeleted(this);
140 void OnDontProceed() {
149 int command_received_count() const {
150 return command_received_count_;
153 void TestDomOperationResponse(const std::string& json_string) {
158 void TestDidNavigate(int page_id, const GURL& url) {
159 FrameHostMsg_DidCommitProvisionalLoad_Params params;
160 InitNavigateParams(¶ms, page_id, url, ui::PAGE_TRANSITION_TYPED);
161 DidNavigate(GetRenderViewHostForTesting(), params);
164 void TestRenderViewTerminated(base::TerminationStatus status,
166 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
169 bool is_showing() const {
170 return static_cast<TestRenderWidgetHostView*>(
171 GetRenderViewHostForTesting()->GetView())->is_showing();
180 void CommandReceived() {
181 command_received_count_++;
184 void set_delegate(Delegate* delegate) {
185 delegate_ = delegate;
189 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
194 InterstitialState* state_;
196 int command_received_count_;
200 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
201 interstitial_page_->CommandReceived();
204 void TestInterstitialPageDelegate::OnDontProceed() {
205 interstitial_page_->OnDontProceed();
208 void TestInterstitialPageDelegate::OnProceed() {
209 interstitial_page_->OnProceed();
212 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
214 explicit TestInterstitialPageStateGuard(
215 TestInterstitialPage* interstitial_page)
216 : interstitial_page_(interstitial_page) {
217 DCHECK(interstitial_page_);
218 interstitial_page_->set_delegate(this);
220 virtual ~TestInterstitialPageStateGuard() {
221 if (interstitial_page_)
222 interstitial_page_->ClearStates();
225 virtual void TestInterstitialPageDeleted(
226 TestInterstitialPage* interstitial) OVERRIDE {
227 DCHECK(interstitial_page_ == interstitial);
228 interstitial_page_ = NULL;
232 TestInterstitialPage* interstitial_page_;
235 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
237 WebContentsImplTestBrowserClient()
238 : assign_site_for_url_(false) {}
240 virtual ~WebContentsImplTestBrowserClient() {}
242 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
243 return assign_site_for_url_;
246 void set_assign_site_for_url(bool assign) {
247 assign_site_for_url_ = assign;
251 bool assign_site_for_url_;
254 class WebContentsImplTest : public RenderViewHostImplTestHarness {
256 virtual void SetUp() {
257 RenderViewHostImplTestHarness::SetUp();
258 WebUIControllerFactory::RegisterFactory(&factory_);
261 virtual void TearDown() {
262 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
263 RenderViewHostImplTestHarness::TearDown();
267 WebContentsImplTestWebUIControllerFactory factory_;
270 class TestWebContentsObserver : public WebContentsObserver {
272 explicit TestWebContentsObserver(WebContents* contents)
273 : WebContentsObserver(contents) {
275 virtual ~TestWebContentsObserver() {}
277 virtual void DidFinishLoad(RenderFrameHost* render_frame_host,
278 const GURL& validated_url) OVERRIDE {
279 last_url_ = validated_url;
281 virtual void DidFailLoad(RenderFrameHost* render_frame_host,
282 const GURL& validated_url,
284 const base::string16& error_description) OVERRIDE {
285 last_url_ = validated_url;
288 const GURL& last_url() const { return last_url_; }
293 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
296 // Pretends to be a normal browser that receives toggles and transitions to/from
297 // a fullscreened state.
298 class FakeFullscreenDelegate : public WebContentsDelegate {
300 FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
301 virtual ~FakeFullscreenDelegate() {}
303 virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
304 bool enter_fullscreen) OVERRIDE {
305 fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
308 virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
310 return fullscreened_contents_ && web_contents == fullscreened_contents_;
314 WebContents* fullscreened_contents_;
316 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
319 class FakeValidationMessageDelegate : public WebContentsDelegate {
321 FakeValidationMessageDelegate()
322 : hide_validation_message_was_called_(false) {}
323 virtual ~FakeValidationMessageDelegate() {}
325 virtual void HideValidationMessage(WebContents* web_contents) OVERRIDE {
326 hide_validation_message_was_called_ = true;
329 bool hide_validation_message_was_called() const {
330 return hide_validation_message_was_called_;
334 bool hide_validation_message_was_called_;
336 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate);
341 // Test to make sure that title updates get stripped of whitespace.
342 TEST_F(WebContentsImplTest, UpdateTitle) {
343 NavigationControllerImpl& cont =
344 static_cast<NavigationControllerImpl&>(controller());
345 FrameHostMsg_DidCommitProvisionalLoad_Params params;
347 ¶ms, 0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED);
349 LoadCommittedDetails details;
350 cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
352 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
353 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
354 base::i18n::LEFT_TO_RIGHT);
355 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
358 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
359 const GURL kGURL("chrome://blah");
360 controller().LoadURL(
361 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
362 EXPECT_EQ(base::string16(), contents()->GetTitle());
365 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
366 const GURL kGURL("chrome://blah");
367 const base::string16 title = base::ASCIIToUTF16("My Title");
368 controller().LoadURL(
369 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
371 NavigationEntry* entry = controller().GetVisibleEntry();
372 ASSERT_EQ(kGURL, entry->GetURL());
373 entry->SetTitle(title);
375 EXPECT_EQ(title, contents()->GetTitle());
378 // Test view source mode for a webui page.
379 TEST_F(WebContentsImplTest, NTPViewSource) {
380 NavigationControllerImpl& cont =
381 static_cast<NavigationControllerImpl&>(controller());
382 const char kUrl[] = "view-source:chrome://blah";
383 const GURL kGURL(kUrl);
385 process()->sink().ClearMessages();
388 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
389 rvh()->GetDelegate()->RenderViewCreated(rvh());
390 // Did we get the expected message?
391 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
392 ViewMsg_EnableViewSourceMode::ID));
394 FrameHostMsg_DidCommitProvisionalLoad_Params params;
395 InitNavigateParams(¶ms, 0, kGURL, ui::PAGE_TRANSITION_TYPED);
396 LoadCommittedDetails details;
397 cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
398 // Also check title and url.
399 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
402 // Test to ensure UpdateMaxPageID is working properly.
403 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
404 SiteInstance* instance1 = contents()->GetSiteInstance();
405 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
408 EXPECT_EQ(-1, contents()->GetMaxPageID());
409 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
410 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
412 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
413 contents()->UpdateMaxPageID(3);
414 contents()->UpdateMaxPageID(1);
415 EXPECT_EQ(3, contents()->GetMaxPageID());
416 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
417 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
419 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
420 EXPECT_EQ(3, contents()->GetMaxPageID());
421 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
422 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
425 // Test simple same-SiteInstance navigation.
426 TEST_F(WebContentsImplTest, SimpleNavigation) {
427 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
428 SiteInstance* instance1 = contents()->GetSiteInstance();
429 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
432 const GURL url("http://www.google.com");
433 controller().LoadURL(
434 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
435 EXPECT_FALSE(contents()->cross_navigation_pending());
436 EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
437 // Controller's pending entry will have a NULL site instance until we assign
438 // it in DidNavigate.
440 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
441 site_instance() == NULL);
443 // DidNavigate from the page
444 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
445 EXPECT_FALSE(contents()->cross_navigation_pending());
446 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
447 EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
448 // Controller's entry should now have the SiteInstance, or else we won't be
449 // able to find it later.
452 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
456 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
457 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
458 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
459 const GURL url(std::string("http://example.org/").append(
460 GetMaxURLChars() + 1, 'a'));
462 controller().LoadURL(
463 url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
464 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
467 // Test that navigating across a site boundary creates a new RenderViewHost
468 // with a new SiteInstance. Going back should do the same.
469 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
470 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
471 int orig_rvh_delete_count = 0;
472 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
473 SiteInstance* instance1 = contents()->GetSiteInstance();
475 // Navigate to URL. First URL should use first RenderViewHost.
476 const GURL url("http://www.google.com");
477 controller().LoadURL(
478 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
479 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
481 // Keep the number of active views in orig_rfh's SiteInstance non-zero so that
482 // orig_rfh doesn't get deleted when it gets swapped out.
483 static_cast<SiteInstanceImpl*>(orig_rfh->GetSiteInstance())->
484 increment_active_view_count();
486 EXPECT_FALSE(contents()->cross_navigation_pending());
487 EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
488 EXPECT_EQ(url, contents()->GetLastCommittedURL());
489 EXPECT_EQ(url, contents()->GetVisibleURL());
491 // Navigate to new site
492 const GURL url2("http://www.yahoo.com");
493 controller().LoadURL(
494 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
495 EXPECT_TRUE(contents()->cross_navigation_pending());
496 EXPECT_EQ(url, contents()->GetLastCommittedURL());
497 EXPECT_EQ(url2, contents()->GetVisibleURL());
498 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
499 int pending_rvh_delete_count = 0;
500 pending_rfh->GetRenderViewHost()->set_delete_counter(
501 &pending_rvh_delete_count);
503 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
504 EXPECT_TRUE(pending_rfh->are_navigations_suspended());
505 orig_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
506 EXPECT_FALSE(pending_rfh->are_navigations_suspended());
508 // DidNavigate from the pending page
509 contents()->TestDidNavigate(
510 pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
511 SiteInstance* instance2 = contents()->GetSiteInstance();
513 // Keep the number of active views in pending_rfh's SiteInstance
514 // non-zero so that orig_rfh doesn't get deleted when it gets
516 static_cast<SiteInstanceImpl*>(pending_rfh->GetSiteInstance())->
517 increment_active_view_count();
519 EXPECT_FALSE(contents()->cross_navigation_pending());
520 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
521 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
522 EXPECT_EQ(url2, contents()->GetVisibleURL());
523 EXPECT_NE(instance1, instance2);
524 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
525 // We keep the original RFH around, swapped out.
526 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
528 EXPECT_EQ(orig_rvh_delete_count, 0);
530 // Going back should switch SiteInstances again. The first SiteInstance is
531 // stored in the NavigationEntry, so it should be the same as at the start.
532 // We should use the same RFH as before, swapping it back in.
533 controller().GoBack();
534 TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
535 EXPECT_EQ(orig_rfh, goback_rfh);
536 EXPECT_TRUE(contents()->cross_navigation_pending());
538 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
539 EXPECT_TRUE(goback_rfh->are_navigations_suspended());
540 pending_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
541 EXPECT_FALSE(goback_rfh->are_navigations_suspended());
543 // DidNavigate from the back action
544 contents()->TestDidNavigate(goback_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
545 EXPECT_FALSE(contents()->cross_navigation_pending());
546 EXPECT_EQ(goback_rfh, contents()->GetMainFrame());
547 EXPECT_EQ(instance1, contents()->GetSiteInstance());
548 // The pending RFH should now be swapped out, not deleted.
549 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
550 IsOnSwappedOutList(pending_rfh));
551 EXPECT_EQ(pending_rvh_delete_count, 0);
552 pending_rfh->OnSwappedOut(false);
554 // Close contents and ensure RVHs are deleted.
556 EXPECT_EQ(orig_rvh_delete_count, 1);
557 EXPECT_EQ(pending_rvh_delete_count, 1);
560 // Test that navigating across a site boundary after a crash creates a new
561 // RFH without requiring a cross-site transition (i.e., PENDING state).
562 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
563 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
565 int orig_rvh_delete_count = 0;
566 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
567 SiteInstance* instance1 = contents()->GetSiteInstance();
569 // Navigate to URL. First URL should use first RenderViewHost.
570 const GURL url("http://www.google.com");
571 controller().LoadURL(
572 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
573 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
575 EXPECT_FALSE(contents()->cross_navigation_pending());
576 EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
578 // Simulate a renderer crash.
579 orig_rfh->GetRenderViewHost()->set_render_view_created(false);
580 orig_rfh->set_render_frame_created(false);
582 // Navigate to new site. We should not go into PENDING.
583 const GURL url2("http://www.yahoo.com");
584 controller().LoadURL(
585 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
586 TestRenderFrameHost* new_rfh = contents()->GetMainFrame();
587 EXPECT_FALSE(contents()->cross_navigation_pending());
588 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
589 EXPECT_NE(orig_rfh, new_rfh);
590 EXPECT_EQ(orig_rvh_delete_count, 1);
592 // DidNavigate from the new page
593 contents()->TestDidNavigate(new_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
594 SiteInstance* instance2 = contents()->GetSiteInstance();
596 EXPECT_FALSE(contents()->cross_navigation_pending());
597 EXPECT_EQ(new_rfh, main_rfh());
598 EXPECT_NE(instance1, instance2);
599 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
601 // Close contents and ensure RVHs are deleted.
603 EXPECT_EQ(orig_rvh_delete_count, 1);
606 // Test that opening a new contents in the same SiteInstance and then navigating
607 // both contentses to a new site will place both contentses in a single
609 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
610 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
611 SiteInstance* instance1 = contents()->GetSiteInstance();
613 // Navigate to URL. First URL should use first RenderViewHost.
614 const GURL url("http://www.google.com");
615 controller().LoadURL(
616 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
617 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
619 // Open a new contents with the same SiteInstance, navigated to the same site.
620 scoped_ptr<TestWebContents> contents2(
621 TestWebContents::Create(browser_context(), instance1));
622 contents2->GetController().LoadURL(url, Referrer(),
623 ui::PAGE_TRANSITION_TYPED,
625 // Need this page id to be 2 since the site instance is the same (which is the
626 // scope of page IDs) and we want to consider this a new page.
627 contents2->TestDidNavigate(
628 contents2->GetMainFrame(), 2, url, ui::PAGE_TRANSITION_TYPED);
630 // Navigate first contents to a new site.
631 const GURL url2a("http://www.yahoo.com");
632 controller().LoadURL(
633 url2a, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
634 orig_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
635 TestRenderFrameHost* pending_rfh_a = contents()->GetPendingMainFrame();
636 contents()->TestDidNavigate(
637 pending_rfh_a, 1, url2a, ui::PAGE_TRANSITION_TYPED);
638 SiteInstance* instance2a = contents()->GetSiteInstance();
639 EXPECT_NE(instance1, instance2a);
641 // Navigate second contents to the same site as the first tab.
642 const GURL url2b("http://mail.yahoo.com");
643 contents2->GetController().LoadURL(url2b, Referrer(),
644 ui::PAGE_TRANSITION_TYPED,
646 TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
647 rfh2->GetRenderViewHost()->SendBeforeUnloadACK(true);
648 TestRenderFrameHost* pending_rfh_b = contents2->GetPendingMainFrame();
649 EXPECT_TRUE(pending_rfh_b != NULL);
650 EXPECT_TRUE(contents2->cross_navigation_pending());
652 // NOTE(creis): We used to be in danger of showing a crash page here if the
653 // second contents hadn't navigated somewhere first (bug 1145430). That case
654 // is now covered by the CrossSiteBoundariesAfterCrash test.
655 contents2->TestDidNavigate(
656 pending_rfh_b, 2, url2b, ui::PAGE_TRANSITION_TYPED);
657 SiteInstance* instance2b = contents2->GetSiteInstance();
658 EXPECT_NE(instance1, instance2b);
660 // Both contentses should now be in the same SiteInstance.
661 EXPECT_EQ(instance2a, instance2b);
664 // The embedder can request sites for certain urls not be be assigned to the
665 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
666 // allowing to reuse the renderer backing certain chrome urls for subsequent
667 // navigation. The test verifies that the override is honored.
668 TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
669 WebContentsImplTestBrowserClient browser_client;
670 SetBrowserClientForTesting(&browser_client);
672 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
673 int orig_rvh_delete_count = 0;
674 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
675 SiteInstanceImpl* orig_instance =
676 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
678 browser_client.set_assign_site_for_url(false);
679 // Navigate to an URL that will not assign a new SiteInstance.
680 const GURL native_url("non-site-url://stuffandthings");
681 controller().LoadURL(
682 native_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
683 contents()->TestDidNavigate(
684 orig_rfh, 1, native_url, ui::PAGE_TRANSITION_TYPED);
686 EXPECT_FALSE(contents()->cross_navigation_pending());
687 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
688 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
689 EXPECT_EQ(native_url, contents()->GetVisibleURL());
690 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
691 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
692 EXPECT_FALSE(orig_instance->HasSite());
694 browser_client.set_assign_site_for_url(true);
695 // Navigate to new site (should keep same site instance).
696 const GURL url("http://www.google.com");
697 controller().LoadURL(
698 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
699 EXPECT_FALSE(contents()->cross_navigation_pending());
700 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
701 EXPECT_EQ(url, contents()->GetVisibleURL());
702 EXPECT_FALSE(contents()->GetPendingMainFrame());
703 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
705 // Keep the number of active views in orig_rfh's SiteInstance
706 // non-zero so that orig_rfh doesn't get deleted when it gets
708 static_cast<SiteInstanceImpl*>(orig_rfh->GetSiteInstance())->
709 increment_active_view_count();
711 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
713 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
714 EXPECT_EQ(url, contents()->GetLastCommittedURL());
716 // Navigate to another new site (should create a new site instance).
717 const GURL url2("http://www.yahoo.com");
718 controller().LoadURL(
719 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
720 EXPECT_TRUE(contents()->cross_navigation_pending());
721 EXPECT_EQ(url, contents()->GetLastCommittedURL());
722 EXPECT_EQ(url2, contents()->GetVisibleURL());
723 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
724 int pending_rvh_delete_count = 0;
725 pending_rfh->GetRenderViewHost()->set_delete_counter(
726 &pending_rvh_delete_count);
728 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
729 EXPECT_TRUE(pending_rfh->are_navigations_suspended());
730 orig_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
731 EXPECT_FALSE(pending_rfh->are_navigations_suspended());
733 // DidNavigate from the pending page.
734 contents()->TestDidNavigate(
735 pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
736 SiteInstance* new_instance = contents()->GetSiteInstance();
738 EXPECT_FALSE(contents()->cross_navigation_pending());
739 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
740 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
741 EXPECT_EQ(url2, contents()->GetVisibleURL());
742 EXPECT_NE(new_instance, orig_instance);
743 EXPECT_FALSE(contents()->GetPendingMainFrame());
744 // We keep the original RFH around, swapped out.
745 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
747 EXPECT_EQ(orig_rvh_delete_count, 0);
748 orig_rfh->OnSwappedOut(false);
750 // Close contents and ensure RVHs are deleted.
752 EXPECT_EQ(orig_rvh_delete_count, 1);
753 EXPECT_EQ(pending_rvh_delete_count, 1);
756 // Regression test for http://crbug.com/386542 - variation of
757 // NavigateFromSitelessUrl in which the original navigation is a session
759 TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
760 WebContentsImplTestBrowserClient browser_client;
761 SetBrowserClientForTesting(&browser_client);
762 SiteInstanceImpl* orig_instance =
763 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
764 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
766 // Restore a navigation entry for URL that should not assign site to the
768 browser_client.set_assign_site_for_url(false);
769 const GURL native_url("non-site-url://stuffandthings");
770 std::vector<NavigationEntry*> entries;
771 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
772 native_url, Referrer(), ui::PAGE_TRANSITION_LINK, false, std::string(),
775 entries.push_back(entry);
776 controller().Restore(
778 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
780 ASSERT_EQ(0u, entries.size());
781 ASSERT_EQ(1, controller().GetEntryCount());
782 controller().GoToIndex(0);
783 contents()->TestDidNavigate(
784 orig_rfh, 0, native_url, ui::PAGE_TRANSITION_RELOAD);
785 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
786 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
787 EXPECT_FALSE(orig_instance->HasSite());
789 // Navigate to a regular site and verify that the SiteInstance was kept.
790 browser_client.set_assign_site_for_url(true);
791 const GURL url("http://www.google.com");
792 controller().LoadURL(
793 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
794 contents()->TestDidNavigate(orig_rfh, 2, url, ui::PAGE_TRANSITION_TYPED);
795 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
801 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
802 // tab is restored, the SiteInstance will change upon navigation.
803 TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
804 WebContentsImplTestBrowserClient browser_client;
805 SetBrowserClientForTesting(&browser_client);
806 SiteInstanceImpl* orig_instance =
807 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
808 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
810 // Restore a navigation entry for a regular URL ensuring that the embedder
811 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
812 browser_client.set_assign_site_for_url(true);
813 const GURL regular_url("http://www.yahoo.com");
814 std::vector<NavigationEntry*> entries;
815 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
816 regular_url, Referrer(), ui::PAGE_TRANSITION_LINK, false, std::string(),
819 entries.push_back(entry);
820 controller().Restore(
822 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
824 ASSERT_EQ(0u, entries.size());
825 ASSERT_EQ(1, controller().GetEntryCount());
826 controller().GoToIndex(0);
827 contents()->TestDidNavigate(
828 orig_rfh, 0, regular_url, ui::PAGE_TRANSITION_RELOAD);
829 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
830 EXPECT_TRUE(orig_instance->HasSite());
832 // Navigate to another site and verify that a new SiteInstance was created.
833 const GURL url("http://www.google.com");
834 controller().LoadURL(
835 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
836 contents()->TestDidNavigate(
837 contents()->GetPendingMainFrame(), 2, url, ui::PAGE_TRANSITION_TYPED);
838 EXPECT_NE(orig_instance, contents()->GetSiteInstance());
844 // Test that we can find an opener RVH even if it's pending.
845 // http://crbug.com/176252.
846 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
847 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
849 // Navigate to a URL.
850 const GURL url("http://www.google.com");
851 controller().LoadURL(
852 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
853 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
855 // Start to navigate first tab to a new site, so that it has a pending RVH.
856 const GURL url2("http://www.yahoo.com");
857 controller().LoadURL(
858 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
859 orig_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
860 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
862 // While it is still pending, simulate opening a new tab with the first tab
863 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
864 // on the opener to ensure that an RVH exists.
865 int opener_routing_id =
866 contents()->CreateOpenerRenderViews(pending_rfh->GetSiteInstance());
868 // We should find the pending RVH and not create a new one.
869 EXPECT_EQ(pending_rfh->GetRenderViewHost()->GetRoutingID(),
873 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
874 // to determine whether a navigation is cross-site.
875 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
876 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
877 SiteInstance* instance1 = contents()->GetSiteInstance();
880 const GURL url("http://www.google.com");
881 controller().LoadURL(
882 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
883 contents()->TestDidNavigate(
884 orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
886 // Open a related contents to a second site.
887 scoped_ptr<TestWebContents> contents2(
888 TestWebContents::Create(browser_context(), instance1));
889 const GURL url2("http://www.yahoo.com");
890 contents2->GetController().LoadURL(url2, Referrer(),
891 ui::PAGE_TRANSITION_TYPED,
893 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
895 TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
896 EXPECT_FALSE(contents2->cross_navigation_pending());
897 contents2->TestDidNavigate(rfh2, 2, url2, ui::PAGE_TRANSITION_TYPED);
898 SiteInstance* instance2 = contents2->GetSiteInstance();
899 EXPECT_NE(instance1, instance2);
900 EXPECT_FALSE(contents2->cross_navigation_pending());
902 // Simulate a link click in first contents to second site. Doesn't switch
903 // SiteInstances, because we don't intercept WebKit navigations.
904 contents()->TestDidNavigate(
905 orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
906 SiteInstance* instance3 = contents()->GetSiteInstance();
907 EXPECT_EQ(instance1, instance3);
908 EXPECT_FALSE(contents()->cross_navigation_pending());
910 // Navigate to the new site. Doesn't switch SiteInstancees, because we
911 // compare against the current URL, not the SiteInstance's site.
912 const GURL url3("http://mail.yahoo.com");
913 controller().LoadURL(
914 url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
915 EXPECT_FALSE(contents()->cross_navigation_pending());
916 contents()->TestDidNavigate(
917 orig_rfh, 3, url3, ui::PAGE_TRANSITION_TYPED);
918 SiteInstance* instance4 = contents()->GetSiteInstance();
919 EXPECT_EQ(instance1, instance4);
922 // Test that the onbeforeunload and onunload handlers run when navigating
923 // across site boundaries.
924 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
925 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
926 SiteInstance* instance1 = contents()->GetSiteInstance();
928 // Navigate to URL. First URL should use first RenderViewHost.
929 const GURL url("http://www.google.com");
930 controller().LoadURL(
931 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
932 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
933 EXPECT_FALSE(contents()->cross_navigation_pending());
934 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
936 // Navigate to new site, but simulate an onbeforeunload denial.
937 const GURL url2("http://www.yahoo.com");
938 controller().LoadURL(
939 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
940 EXPECT_TRUE(orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
941 base::TimeTicks now = base::TimeTicks::Now();
942 orig_rfh->OnMessageReceived(
943 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
945 orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
946 EXPECT_FALSE(contents()->cross_navigation_pending());
947 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
949 // Navigate again, but simulate an onbeforeunload approval.
950 controller().LoadURL(
951 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
952 EXPECT_TRUE(orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
953 now = base::TimeTicks::Now();
954 orig_rfh->OnMessageReceived(
955 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
957 orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
958 EXPECT_TRUE(contents()->cross_navigation_pending());
959 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
961 // We won't hear DidNavigate until the onunload handler has finished running.
963 // DidNavigate from the pending page.
964 contents()->TestDidNavigate(
965 pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
966 SiteInstance* instance2 = contents()->GetSiteInstance();
967 EXPECT_FALSE(contents()->cross_navigation_pending());
968 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
969 EXPECT_NE(instance1, instance2);
970 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
973 // Test that during a slow cross-site navigation, the original renderer can
974 // navigate to a different URL and have it displayed, canceling the slow
976 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
977 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
978 SiteInstance* instance1 = contents()->GetSiteInstance();
980 // Navigate to URL. First URL should use first RenderFrameHost.
981 const GURL url("http://www.google.com");
982 controller().LoadURL(
983 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
984 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
985 EXPECT_FALSE(contents()->cross_navigation_pending());
986 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
988 // Navigate to new site, simulating an onbeforeunload approval.
989 const GURL url2("http://www.yahoo.com");
990 controller().LoadURL(
991 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
992 EXPECT_TRUE(orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
993 base::TimeTicks now = base::TimeTicks::Now();
994 orig_rfh->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
995 EXPECT_TRUE(contents()->cross_navigation_pending());
997 // Suppose the original renderer navigates before the new one is ready.
998 orig_rfh->SendNavigate(2, GURL("http://www.google.com/foo"));
1000 // Verify that the pending navigation is cancelled.
1002 orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1003 SiteInstance* instance2 = contents()->GetSiteInstance();
1004 EXPECT_FALSE(contents()->cross_navigation_pending());
1005 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1006 EXPECT_EQ(instance1, instance2);
1007 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
1010 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
1011 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1012 const GURL url1("chrome://blah");
1013 controller().LoadURL(
1014 url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1015 TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
1016 contents()->TestDidNavigate(ntp_rfh, 1, url1, ui::PAGE_TRANSITION_TYPED);
1017 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
1018 SiteInstance* instance1 = contents()->GetSiteInstance();
1020 EXPECT_FALSE(contents()->cross_navigation_pending());
1021 EXPECT_EQ(ntp_rfh, contents()->GetMainFrame());
1022 EXPECT_EQ(url1, entry1->GetURL());
1023 EXPECT_EQ(instance1,
1024 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1025 EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->GetEnabledBindings() &
1026 BINDINGS_POLICY_WEB_UI);
1028 // Navigate to new site.
1029 const GURL url2("http://www.google.com");
1030 controller().LoadURL(
1031 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1032 EXPECT_TRUE(contents()->cross_navigation_pending());
1033 TestRenderFrameHost* google_rfh = contents()->GetPendingMainFrame();
1035 // Simulate beforeunload approval.
1036 EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1037 base::TimeTicks now = base::TimeTicks::Now();
1038 ntp_rfh->OnMessageReceived(
1039 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1041 // DidNavigate from the pending page.
1042 contents()->TestDidNavigate(
1043 google_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
1044 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
1045 SiteInstance* instance2 = contents()->GetSiteInstance();
1047 EXPECT_FALSE(contents()->cross_navigation_pending());
1048 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1049 EXPECT_NE(instance1, instance2);
1050 EXPECT_FALSE(contents()->GetPendingMainFrame());
1051 EXPECT_EQ(url2, entry2->GetURL());
1052 EXPECT_EQ(instance2,
1053 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1054 EXPECT_FALSE(google_rfh->GetRenderViewHost()->GetEnabledBindings() &
1055 BINDINGS_POLICY_WEB_UI);
1057 // Navigate to third page on same site.
1058 const GURL url3("http://news.google.com");
1059 controller().LoadURL(
1060 url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1061 EXPECT_FALSE(contents()->cross_navigation_pending());
1062 contents()->TestDidNavigate(
1063 google_rfh, 2, url3, ui::PAGE_TRANSITION_TYPED);
1064 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
1065 SiteInstance* instance3 = contents()->GetSiteInstance();
1067 EXPECT_FALSE(contents()->cross_navigation_pending());
1068 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1069 EXPECT_EQ(instance2, instance3);
1070 EXPECT_FALSE(contents()->GetPendingMainFrame());
1071 EXPECT_EQ(url3, entry3->GetURL());
1072 EXPECT_EQ(instance3,
1073 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1075 // Go back within the site.
1076 controller().GoBack();
1077 EXPECT_FALSE(contents()->cross_navigation_pending());
1078 EXPECT_EQ(entry2, controller().GetPendingEntry());
1080 // Before that commits, go back again.
1081 controller().GoBack();
1082 EXPECT_TRUE(contents()->cross_navigation_pending());
1083 EXPECT_TRUE(contents()->GetPendingMainFrame());
1084 EXPECT_EQ(entry1, controller().GetPendingEntry());
1086 // Simulate beforeunload approval.
1088 google_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1089 now = base::TimeTicks::Now();
1090 google_rfh->OnMessageReceived(
1091 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1093 // DidNavigate from the first back. This aborts the second back's pending RFH.
1094 contents()->TestDidNavigate(google_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
1096 // We should commit this page and forget about the second back.
1097 EXPECT_FALSE(contents()->cross_navigation_pending());
1098 EXPECT_FALSE(controller().GetPendingEntry());
1099 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1100 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1102 // We should not have corrupted the NTP entry.
1103 EXPECT_EQ(instance3,
1104 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1105 EXPECT_EQ(instance2,
1106 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1107 EXPECT_EQ(instance1,
1108 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1109 EXPECT_EQ(url1, entry1->GetURL());
1112 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1113 // original renderer will not cancel the slow navigation (bug 42029).
1114 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1115 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1117 // Navigate to URL. First URL should use the original RenderFrameHost.
1118 const GURL url("http://www.google.com");
1119 controller().LoadURL(
1120 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1121 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1122 EXPECT_FALSE(contents()->cross_navigation_pending());
1123 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1125 // Start navigating to new site.
1126 const GURL url2("http://www.yahoo.com");
1127 controller().LoadURL(
1128 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1130 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1131 // waiting for a before unload response.
1132 TestRenderFrameHost* child_rfh = orig_rfh->AppendChild("subframe");
1133 child_rfh->SendNavigateWithTransition(
1134 1, GURL("http://google.com/frame"), ui::PAGE_TRANSITION_AUTO_SUBFRAME);
1135 EXPECT_TRUE(orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1137 // Now simulate the onbeforeunload approval and verify the navigation is
1139 base::TimeTicks now = base::TimeTicks::Now();
1140 orig_rfh->OnMessageReceived(
1141 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1143 orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1144 EXPECT_TRUE(contents()->cross_navigation_pending());
1147 // Test that a cross-site navigation is not preempted if the previous
1148 // renderer sends a FrameNavigate message just before being told to stop.
1149 // We should only preempt the cross-site navigation if the previous renderer
1150 // has started a new navigation. See http://crbug.com/79176.
1151 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1152 // Navigate to NTP URL.
1153 const GURL url("chrome://blah");
1154 controller().LoadURL(
1155 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1156 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1157 EXPECT_FALSE(contents()->cross_navigation_pending());
1159 // Navigate to new site, with the beforeunload request in flight.
1160 const GURL url2("http://www.yahoo.com");
1161 controller().LoadURL(
1162 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1163 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
1164 EXPECT_TRUE(contents()->cross_navigation_pending());
1165 EXPECT_TRUE(orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1167 // Suppose the first navigation tries to commit now, with a
1168 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1169 // but it should act as if the beforeunload ack arrived.
1170 orig_rfh->SendNavigate(1, GURL("chrome://blah"));
1171 EXPECT_TRUE(contents()->cross_navigation_pending());
1172 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1174 orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1176 // The pending navigation should be able to commit successfully.
1177 contents()->TestDidNavigate(pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
1178 EXPECT_FALSE(contents()->cross_navigation_pending());
1179 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
1182 // Test that a cross-site navigation that doesn't commit after the unload
1183 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1184 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1185 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1186 SiteInstance* instance1 = contents()->GetSiteInstance();
1188 // Navigate to URL. First URL should use original RenderFrameHost.
1189 const GURL url("http://www.google.com");
1190 controller().LoadURL(
1191 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1192 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1193 EXPECT_FALSE(contents()->cross_navigation_pending());
1194 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1196 // Navigate to new site, simulating an onbeforeunload approval.
1197 const GURL url2("http://www.yahoo.com");
1198 controller().LoadURL(
1199 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1200 EXPECT_TRUE(orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1201 base::TimeTicks now = base::TimeTicks::Now();
1202 orig_rfh->OnMessageReceived(
1203 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1204 EXPECT_TRUE(contents()->cross_navigation_pending());
1206 // Simulate swap out message when the response arrives.
1207 orig_rfh->OnSwappedOut(false);
1209 // Suppose the navigation doesn't get a chance to commit, and the user
1210 // navigates in the current RFH's SiteInstance.
1211 controller().LoadURL(
1212 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1214 // Verify that the pending navigation is cancelled and the renderer is no
1215 // longer swapped out.
1217 orig_rfh->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1218 SiteInstance* instance2 = contents()->GetSiteInstance();
1219 EXPECT_FALSE(contents()->cross_navigation_pending());
1220 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1221 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
1222 orig_rfh->GetRenderViewHost()->rvh_state());
1223 EXPECT_EQ(instance1, instance2);
1224 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
1227 // Test that NavigationEntries have the correct page state after going
1228 // forward and back. Prevents regression for bug 1116137.
1229 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1230 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1232 // Navigate to URL. There should be no committed entry yet.
1233 const GURL url("http://www.google.com");
1234 controller().LoadURL(
1235 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1236 NavigationEntry* entry = controller().GetLastCommittedEntry();
1237 EXPECT_TRUE(entry == NULL);
1239 // Committed entry should have page state after DidNavigate.
1240 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1241 entry = controller().GetLastCommittedEntry();
1242 EXPECT_TRUE(entry->GetPageState().IsValid());
1244 // Navigate to same site.
1245 const GURL url2("http://images.google.com");
1246 controller().LoadURL(
1247 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1248 entry = controller().GetLastCommittedEntry();
1249 EXPECT_TRUE(entry->GetPageState().IsValid());
1251 // Committed entry should have page state after DidNavigate.
1252 contents()->TestDidNavigate(orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
1253 entry = controller().GetLastCommittedEntry();
1254 EXPECT_TRUE(entry->GetPageState().IsValid());
1256 // Now go back. Committed entry should still have page state.
1257 controller().GoBack();
1258 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1259 entry = controller().GetLastCommittedEntry();
1260 EXPECT_TRUE(entry->GetPageState().IsValid());
1263 // Test that NavigationEntries have the correct page state and SiteInstance
1264 // state after opening a new window to about:blank. Prevents regression for
1265 // bugs b/1116137 and http://crbug.com/111975.
1266 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1267 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1269 // When opening a new window, it is navigated to about:blank internally.
1270 // Currently, this results in two DidNavigate events.
1271 const GURL url(url::kAboutBlankURL);
1272 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1273 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1275 // Should have a page state here.
1276 NavigationEntry* entry = controller().GetLastCommittedEntry();
1277 EXPECT_TRUE(entry->GetPageState().IsValid());
1279 // The SiteInstance should be available for other navigations to use.
1280 NavigationEntryImpl* entry_impl =
1281 NavigationEntryImpl::FromNavigationEntry(entry);
1282 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1283 int32 site_instance_id = entry_impl->site_instance()->GetId();
1285 // Navigating to a normal page should not cause a process swap.
1286 const GURL new_url("http://www.google.com");
1287 controller().LoadURL(new_url, Referrer(),
1288 ui::PAGE_TRANSITION_TYPED, std::string());
1289 EXPECT_FALSE(contents()->cross_navigation_pending());
1290 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1291 contents()->TestDidNavigate(orig_rfh, 1, new_url, ui::PAGE_TRANSITION_TYPED);
1292 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1293 controller().GetLastCommittedEntry());
1294 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1295 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1298 // Tests that fullscreen is exited throughout the object hierarchy when
1299 // navigating to a new page.
1300 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1301 FakeFullscreenDelegate fake_delegate;
1302 contents()->SetDelegate(&fake_delegate);
1303 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1304 TestRenderViewHost* orig_rvh = orig_rfh->GetRenderViewHost();
1306 // Navigate to a site.
1307 const GURL url("http://www.google.com");
1308 controller().LoadURL(
1309 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1310 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1311 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1313 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1314 EXPECT_FALSE(orig_rvh->IsFullscreen());
1315 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1316 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1317 orig_rvh->OnMessageReceived(
1318 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1319 EXPECT_TRUE(orig_rvh->IsFullscreen());
1320 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1321 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1323 // Navigate to a new site.
1324 const GURL url2("http://www.yahoo.com");
1325 controller().LoadURL(
1326 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1327 TestRenderFrameHost* const pending_rfh = contents()->GetPendingMainFrame();
1328 contents()->TestDidNavigate(
1329 pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
1331 // Confirm fullscreen has exited.
1332 EXPECT_FALSE(orig_rvh->IsFullscreen());
1333 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1334 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1336 contents()->SetDelegate(NULL);
1339 // Tests that fullscreen is exited throughout the object hierarchy when
1340 // instructing NavigationController to GoBack() or GoForward().
1341 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1342 FakeFullscreenDelegate fake_delegate;
1343 contents()->SetDelegate(&fake_delegate);
1344 TestRenderFrameHost* const orig_rfh = contents()->GetMainFrame();
1345 TestRenderViewHost* const orig_rvh = orig_rfh->GetRenderViewHost();
1347 // Navigate to a site.
1348 const GURL url("http://www.google.com");
1349 controller().LoadURL(
1350 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1351 contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
1352 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1354 // Now, navigate to another page on the same site.
1355 const GURL url2("http://www.google.com/search?q=kittens");
1356 controller().LoadURL(
1357 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1358 EXPECT_FALSE(contents()->cross_navigation_pending());
1359 contents()->TestDidNavigate(orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
1360 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1362 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1363 EXPECT_FALSE(orig_rvh->IsFullscreen());
1364 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1365 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1367 for (int i = 0; i < 2; ++i) {
1368 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1369 orig_rvh->OnMessageReceived(
1370 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1371 EXPECT_TRUE(orig_rvh->IsFullscreen());
1372 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1373 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1375 // Navigate backward (or forward).
1377 controller().GoBack();
1379 controller().GoForward();
1380 EXPECT_FALSE(contents()->cross_navigation_pending());
1381 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1382 contents()->TestDidNavigate(
1383 orig_rfh, i + 1, url, ui::PAGE_TRANSITION_FORWARD_BACK);
1385 // Confirm fullscreen has exited.
1386 EXPECT_FALSE(orig_rvh->IsFullscreen());
1387 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1388 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1391 contents()->SetDelegate(NULL);
1394 TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
1395 FakeValidationMessageDelegate fake_delegate;
1396 contents()->SetDelegate(&fake_delegate);
1397 EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
1399 // Crash the renderer.
1400 contents()->GetMainFrame()->GetRenderViewHost()->OnMessageReceived(
1401 ViewHostMsg_RenderProcessGone(
1402 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1404 // Confirm HideValidationMessage was called.
1405 EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
1407 contents()->SetDelegate(NULL);
1410 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1412 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1413 FakeFullscreenDelegate fake_delegate;
1414 contents()->SetDelegate(&fake_delegate);
1416 // Navigate to a site.
1417 const GURL url("http://www.google.com");
1418 controller().LoadURL(
1419 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1420 contents()->TestDidNavigate(
1421 contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
1423 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1424 EXPECT_FALSE(test_rvh()->IsFullscreen());
1425 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1426 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1427 test_rvh()->OnMessageReceived(
1428 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1429 EXPECT_TRUE(test_rvh()->IsFullscreen());
1430 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1431 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1433 // Crash the renderer.
1434 test_rvh()->OnMessageReceived(
1435 ViewHostMsg_RenderProcessGone(
1436 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1438 // Confirm fullscreen has exited.
1439 EXPECT_FALSE(test_rvh()->IsFullscreen());
1440 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1441 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1443 contents()->SetDelegate(NULL);
1446 ////////////////////////////////////////////////////////////////////////////////
1447 // Interstitial Tests
1448 ////////////////////////////////////////////////////////////////////////////////
1450 // Test navigating to a page (with the navigation initiated from the browser,
1451 // as when a URL is typed in the location bar) that shows an interstitial and
1452 // creates a new navigation entry, then hiding it without proceeding.
1453 TEST_F(WebContentsImplTest,
1454 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1455 // Navigate to a page.
1456 GURL url1("http://www.google.com");
1457 contents()->GetMainFrame()->SendNavigate(1, url1);
1458 EXPECT_EQ(1, controller().GetEntryCount());
1460 // Initiate a browser navigation that will trigger the interstitial
1461 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1462 ui::PAGE_TRANSITION_TYPED, std::string());
1464 // Show an interstitial.
1465 TestInterstitialPage::InterstitialState state =
1466 TestInterstitialPage::INVALID;
1467 bool deleted = false;
1468 GURL url2("http://interstitial");
1469 TestInterstitialPage* interstitial =
1470 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1471 TestInterstitialPageStateGuard state_guard(interstitial);
1472 interstitial->Show();
1473 // The interstitial should not show until its navigation has committed.
1474 EXPECT_FALSE(interstitial->is_showing());
1475 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1476 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1477 // Let's commit the interstitial navigation.
1478 interstitial->TestDidNavigate(1, url2);
1479 EXPECT_TRUE(interstitial->is_showing());
1480 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1481 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1482 NavigationEntry* entry = controller().GetVisibleEntry();
1483 ASSERT_TRUE(entry != NULL);
1484 EXPECT_TRUE(entry->GetURL() == url2);
1486 // Now don't proceed.
1487 interstitial->DontProceed();
1488 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1489 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1490 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1491 entry = controller().GetVisibleEntry();
1492 ASSERT_TRUE(entry != NULL);
1493 EXPECT_TRUE(entry->GetURL() == url1);
1494 EXPECT_EQ(1, controller().GetEntryCount());
1496 RunAllPendingInMessageLoop();
1497 EXPECT_TRUE(deleted);
1500 // Test navigating to a page (with the navigation initiated from the renderer,
1501 // as when clicking on a link in the page) that shows an interstitial and
1502 // creates a new navigation entry, then hiding it without proceeding.
1503 TEST_F(WebContentsImplTest,
1504 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1505 // Navigate to a page.
1506 GURL url1("http://www.google.com");
1507 contents()->GetMainFrame()->SendNavigate(1, url1);
1508 EXPECT_EQ(1, controller().GetEntryCount());
1510 // Show an interstitial (no pending entry, the interstitial would have been
1511 // triggered by clicking on a link).
1512 TestInterstitialPage::InterstitialState state =
1513 TestInterstitialPage::INVALID;
1514 bool deleted = false;
1515 GURL url2("http://interstitial");
1516 TestInterstitialPage* interstitial =
1517 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1518 TestInterstitialPageStateGuard state_guard(interstitial);
1519 interstitial->Show();
1520 // The interstitial should not show until its navigation has committed.
1521 EXPECT_FALSE(interstitial->is_showing());
1522 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1523 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1524 // Let's commit the interstitial navigation.
1525 interstitial->TestDidNavigate(1, url2);
1526 EXPECT_TRUE(interstitial->is_showing());
1527 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1528 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1529 NavigationEntry* entry = controller().GetVisibleEntry();
1530 ASSERT_TRUE(entry != NULL);
1531 EXPECT_TRUE(entry->GetURL() == url2);
1533 // Now don't proceed.
1534 interstitial->DontProceed();
1535 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1536 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1537 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1538 entry = controller().GetVisibleEntry();
1539 ASSERT_TRUE(entry != NULL);
1540 EXPECT_TRUE(entry->GetURL() == url1);
1541 EXPECT_EQ(1, controller().GetEntryCount());
1543 RunAllPendingInMessageLoop();
1544 EXPECT_TRUE(deleted);
1547 // Test navigating to a page that shows an interstitial without creating a new
1548 // navigation entry (this happens when the interstitial is triggered by a
1549 // sub-resource in the page), then hiding it without proceeding.
1550 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1551 // Navigate to a page.
1552 GURL url1("http://www.google.com");
1553 contents()->GetMainFrame()->SendNavigate(1, url1);
1554 EXPECT_EQ(1, controller().GetEntryCount());
1556 // Show an interstitial.
1557 TestInterstitialPage::InterstitialState state =
1558 TestInterstitialPage::INVALID;
1559 bool deleted = false;
1560 GURL url2("http://interstitial");
1561 TestInterstitialPage* interstitial =
1562 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1563 TestInterstitialPageStateGuard state_guard(interstitial);
1564 interstitial->Show();
1565 // The interstitial should not show until its navigation has committed.
1566 EXPECT_FALSE(interstitial->is_showing());
1567 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1568 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1569 // Let's commit the interstitial navigation.
1570 interstitial->TestDidNavigate(1, url2);
1571 EXPECT_TRUE(interstitial->is_showing());
1572 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1573 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1574 NavigationEntry* entry = controller().GetVisibleEntry();
1575 ASSERT_TRUE(entry != NULL);
1576 // The URL specified to the interstitial should have been ignored.
1577 EXPECT_TRUE(entry->GetURL() == url1);
1579 // Now don't proceed.
1580 interstitial->DontProceed();
1581 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1582 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1583 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1584 entry = controller().GetVisibleEntry();
1585 ASSERT_TRUE(entry != NULL);
1586 EXPECT_TRUE(entry->GetURL() == url1);
1587 EXPECT_EQ(1, controller().GetEntryCount());
1589 RunAllPendingInMessageLoop();
1590 EXPECT_TRUE(deleted);
1593 // Test navigating to a page (with the navigation initiated from the browser,
1594 // as when a URL is typed in the location bar) that shows an interstitial and
1595 // creates a new navigation entry, then proceeding.
1596 TEST_F(WebContentsImplTest,
1597 ShowInterstitialFromBrowserNewNavigationProceed) {
1598 // Navigate to a page.
1599 GURL url1("http://www.google.com");
1600 contents()->GetMainFrame()->SendNavigate(1, url1);
1601 EXPECT_EQ(1, controller().GetEntryCount());
1603 // Initiate a browser navigation that will trigger the interstitial
1604 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1605 ui::PAGE_TRANSITION_TYPED, std::string());
1607 // Show an interstitial.
1608 TestInterstitialPage::InterstitialState state =
1609 TestInterstitialPage::INVALID;
1610 bool deleted = false;
1611 GURL url2("http://interstitial");
1612 TestInterstitialPage* interstitial =
1613 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1614 TestInterstitialPageStateGuard state_guard(interstitial);
1615 interstitial->Show();
1616 // The interstitial should not show until its navigation has committed.
1617 EXPECT_FALSE(interstitial->is_showing());
1618 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1619 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1620 // Let's commit the interstitial navigation.
1621 interstitial->TestDidNavigate(1, url2);
1622 EXPECT_TRUE(interstitial->is_showing());
1623 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1624 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1625 NavigationEntry* entry = controller().GetVisibleEntry();
1626 ASSERT_TRUE(entry != NULL);
1627 EXPECT_TRUE(entry->GetURL() == url2);
1630 interstitial->Proceed();
1631 // The interstitial should show until the new navigation commits.
1632 RunAllPendingInMessageLoop();
1633 ASSERT_FALSE(deleted);
1634 EXPECT_EQ(TestInterstitialPage::OKED, state);
1635 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1636 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1638 // Simulate the navigation to the page, that's when the interstitial gets
1640 GURL url3("http://www.thepage.com");
1641 contents()->GetMainFrame()->SendNavigate(2, url3);
1643 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1644 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1645 entry = controller().GetVisibleEntry();
1646 ASSERT_TRUE(entry != NULL);
1647 EXPECT_TRUE(entry->GetURL() == url3);
1649 EXPECT_EQ(2, controller().GetEntryCount());
1651 RunAllPendingInMessageLoop();
1652 EXPECT_TRUE(deleted);
1655 // Test navigating to a page (with the navigation initiated from the renderer,
1656 // as when clicking on a link in the page) that shows an interstitial and
1657 // creates a new navigation entry, then proceeding.
1658 TEST_F(WebContentsImplTest,
1659 ShowInterstitialFromRendererNewNavigationProceed) {
1660 // Navigate to a page.
1661 GURL url1("http://www.google.com");
1662 contents()->GetMainFrame()->SendNavigate(1, url1);
1663 EXPECT_EQ(1, controller().GetEntryCount());
1665 // Show an interstitial.
1666 TestInterstitialPage::InterstitialState state =
1667 TestInterstitialPage::INVALID;
1668 bool deleted = false;
1669 GURL url2("http://interstitial");
1670 TestInterstitialPage* interstitial =
1671 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1672 TestInterstitialPageStateGuard state_guard(interstitial);
1673 interstitial->Show();
1674 // The interstitial should not show until its navigation has committed.
1675 EXPECT_FALSE(interstitial->is_showing());
1676 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1677 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1678 // Let's commit the interstitial navigation.
1679 interstitial->TestDidNavigate(1, url2);
1680 EXPECT_TRUE(interstitial->is_showing());
1681 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1682 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1683 NavigationEntry* entry = controller().GetVisibleEntry();
1684 ASSERT_TRUE(entry != NULL);
1685 EXPECT_TRUE(entry->GetURL() == url2);
1688 interstitial->Proceed();
1689 // The interstitial should show until the new navigation commits.
1690 RunAllPendingInMessageLoop();
1691 ASSERT_FALSE(deleted);
1692 EXPECT_EQ(TestInterstitialPage::OKED, state);
1693 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1694 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1696 // Simulate the navigation to the page, that's when the interstitial gets
1698 GURL url3("http://www.thepage.com");
1699 contents()->GetMainFrame()->SendNavigate(2, url3);
1701 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1702 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1703 entry = controller().GetVisibleEntry();
1704 ASSERT_TRUE(entry != NULL);
1705 EXPECT_TRUE(entry->GetURL() == url3);
1707 EXPECT_EQ(2, controller().GetEntryCount());
1709 RunAllPendingInMessageLoop();
1710 EXPECT_TRUE(deleted);
1713 // Test navigating to a page that shows an interstitial without creating a new
1714 // navigation entry (this happens when the interstitial is triggered by a
1715 // sub-resource in the page), then proceeding.
1716 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1717 // Navigate to a page so we have a navigation entry in the controller.
1718 GURL url1("http://www.google.com");
1719 contents()->GetMainFrame()->SendNavigate(1, url1);
1720 EXPECT_EQ(1, controller().GetEntryCount());
1722 // Show an interstitial.
1723 TestInterstitialPage::InterstitialState state =
1724 TestInterstitialPage::INVALID;
1725 bool deleted = false;
1726 GURL url2("http://interstitial");
1727 TestInterstitialPage* interstitial =
1728 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1729 TestInterstitialPageStateGuard state_guard(interstitial);
1730 interstitial->Show();
1731 // The interstitial should not show until its navigation has committed.
1732 EXPECT_FALSE(interstitial->is_showing());
1733 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1734 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1735 // Let's commit the interstitial navigation.
1736 interstitial->TestDidNavigate(1, url2);
1737 EXPECT_TRUE(interstitial->is_showing());
1738 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1739 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1740 NavigationEntry* entry = controller().GetVisibleEntry();
1741 ASSERT_TRUE(entry != NULL);
1742 // The URL specified to the interstitial should have been ignored.
1743 EXPECT_TRUE(entry->GetURL() == url1);
1746 interstitial->Proceed();
1747 // Since this is not a new navigation, the previous page is dismissed right
1748 // away and shows the original page.
1749 EXPECT_EQ(TestInterstitialPage::OKED, state);
1750 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1751 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1752 entry = controller().GetVisibleEntry();
1753 ASSERT_TRUE(entry != NULL);
1754 EXPECT_TRUE(entry->GetURL() == url1);
1756 EXPECT_EQ(1, controller().GetEntryCount());
1758 RunAllPendingInMessageLoop();
1759 EXPECT_TRUE(deleted);
1762 // Test navigating to a page that shows an interstitial, then navigating away.
1763 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1764 // Show interstitial.
1765 TestInterstitialPage::InterstitialState state =
1766 TestInterstitialPage::INVALID;
1767 bool deleted = false;
1768 GURL url("http://interstitial");
1769 TestInterstitialPage* interstitial =
1770 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1771 TestInterstitialPageStateGuard state_guard(interstitial);
1772 interstitial->Show();
1773 interstitial->TestDidNavigate(1, url);
1775 // While interstitial showing, navigate to a new URL.
1776 const GURL url2("http://www.yahoo.com");
1777 contents()->GetMainFrame()->SendNavigate(1, url2);
1779 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1781 RunAllPendingInMessageLoop();
1782 EXPECT_TRUE(deleted);
1785 // Test navigating to a page that shows an interstitial, then going back.
1786 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1787 // Navigate to a page so we have a navigation entry in the controller.
1788 GURL url1("http://www.google.com");
1789 contents()->GetMainFrame()->SendNavigate(1, url1);
1790 EXPECT_EQ(1, controller().GetEntryCount());
1792 // Show interstitial.
1793 TestInterstitialPage::InterstitialState state =
1794 TestInterstitialPage::INVALID;
1795 bool deleted = false;
1796 GURL interstitial_url("http://interstitial");
1797 TestInterstitialPage* interstitial =
1798 new TestInterstitialPage(contents(), true, interstitial_url,
1800 TestInterstitialPageStateGuard state_guard(interstitial);
1801 interstitial->Show();
1802 interstitial->TestDidNavigate(2, interstitial_url);
1804 // While the interstitial is showing, go back.
1805 controller().GoBack();
1806 contents()->GetMainFrame()->SendNavigate(1, url1);
1808 // Make sure we are back to the original page and that the interstitial is
1810 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1811 NavigationEntry* entry = controller().GetVisibleEntry();
1813 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1815 RunAllPendingInMessageLoop();
1816 EXPECT_TRUE(deleted);
1819 // Test navigating to a page that shows an interstitial, has a renderer crash,
1820 // and then goes back.
1821 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1822 // Navigate to a page so we have a navigation entry in the controller.
1823 GURL url1("http://www.google.com");
1824 contents()->GetMainFrame()->SendNavigate(1, url1);
1825 EXPECT_EQ(1, controller().GetEntryCount());
1827 // Show interstitial.
1828 TestInterstitialPage::InterstitialState state =
1829 TestInterstitialPage::INVALID;
1830 bool deleted = false;
1831 GURL interstitial_url("http://interstitial");
1832 TestInterstitialPage* interstitial =
1833 new TestInterstitialPage(contents(), true, interstitial_url,
1835 TestInterstitialPageStateGuard state_guard(interstitial);
1836 interstitial->Show();
1837 interstitial->TestDidNavigate(2, interstitial_url);
1839 // Crash the renderer
1840 test_rvh()->OnMessageReceived(
1841 ViewHostMsg_RenderProcessGone(
1842 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1844 // While the interstitial is showing, go back.
1845 controller().GoBack();
1846 contents()->GetMainFrame()->SendNavigate(1, url1);
1848 // Make sure we are back to the original page and that the interstitial is
1850 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1851 NavigationEntry* entry = controller().GetVisibleEntry();
1853 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1855 RunAllPendingInMessageLoop();
1856 EXPECT_TRUE(deleted);
1859 // Test navigating to a page that shows an interstitial, has the renderer crash,
1860 // and then navigates to the interstitial.
1861 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1862 // Navigate to a page so we have a navigation entry in the controller.
1863 GURL url1("http://www.google.com");
1864 contents()->GetMainFrame()->SendNavigate(1, url1);
1865 EXPECT_EQ(1, controller().GetEntryCount());
1867 // Show interstitial.
1868 TestInterstitialPage::InterstitialState state =
1869 TestInterstitialPage::INVALID;
1870 bool deleted = false;
1871 GURL interstitial_url("http://interstitial");
1872 TestInterstitialPage* interstitial =
1873 new TestInterstitialPage(contents(), true, interstitial_url,
1875 TestInterstitialPageStateGuard state_guard(interstitial);
1876 interstitial->Show();
1878 // Crash the renderer
1879 test_rvh()->OnMessageReceived(
1880 ViewHostMsg_RenderProcessGone(
1881 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1883 interstitial->TestDidNavigate(2, interstitial_url);
1886 // Test navigating to a page that shows an interstitial, then close the
1888 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1889 // Show interstitial.
1890 TestInterstitialPage::InterstitialState state =
1891 TestInterstitialPage::INVALID;
1892 bool deleted = false;
1893 GURL url("http://interstitial");
1894 TestInterstitialPage* interstitial =
1895 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1896 TestInterstitialPageStateGuard state_guard(interstitial);
1897 interstitial->Show();
1898 interstitial->TestDidNavigate(1, url);
1900 // Now close the contents.
1902 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1904 RunAllPendingInMessageLoop();
1905 EXPECT_TRUE(deleted);
1908 // Test navigating to a page that shows an interstitial, then close the
1910 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1911 // Show interstitial.
1912 TestInterstitialPage::InterstitialState state =
1913 TestInterstitialPage::INVALID;
1914 bool deleted = false;
1915 GURL url("http://interstitial");
1916 TestInterstitialPage* interstitial =
1917 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1918 TestInterstitialPageStateGuard state_guard(interstitial);
1919 interstitial->Show();
1920 interstitial->TestDidNavigate(1, url);
1921 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1922 interstitial->GetRenderViewHostForTesting());
1924 // Now close the contents.
1926 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1928 // Before the interstitial has a chance to process its shutdown task,
1929 // simulate quitting the browser. This goes through all processes and
1930 // tells them to destruct.
1931 rvh->OnMessageReceived(
1932 ViewHostMsg_RenderProcessGone(0, 0, 0));
1934 RunAllPendingInMessageLoop();
1935 EXPECT_TRUE(deleted);
1938 // Test that after Proceed is called and an interstitial is still shown, no more
1939 // commands get executed.
1940 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1941 // Navigate to a page so we have a navigation entry in the controller.
1942 GURL url1("http://www.google.com");
1943 contents()->GetMainFrame()->SendNavigate(1, url1);
1944 EXPECT_EQ(1, controller().GetEntryCount());
1946 // Show an interstitial.
1947 TestInterstitialPage::InterstitialState state =
1948 TestInterstitialPage::INVALID;
1949 bool deleted = false;
1950 GURL url2("http://interstitial");
1951 TestInterstitialPage* interstitial =
1952 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1953 TestInterstitialPageStateGuard state_guard(interstitial);
1954 interstitial->Show();
1955 interstitial->TestDidNavigate(1, url2);
1958 EXPECT_EQ(0, interstitial->command_received_count());
1959 interstitial->TestDomOperationResponse("toto");
1960 EXPECT_EQ(1, interstitial->command_received_count());
1963 interstitial->Proceed();
1964 RunAllPendingInMessageLoop();
1965 ASSERT_FALSE(deleted);
1967 // While the navigation to the new page is pending, send other commands, they
1968 // should be ignored.
1969 interstitial->TestDomOperationResponse("hello");
1970 interstitial->TestDomOperationResponse("hi");
1971 EXPECT_EQ(1, interstitial->command_received_count());
1974 // Test showing an interstitial while another interstitial is already showing.
1975 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1976 // Navigate to a page so we have a navigation entry in the controller.
1977 GURL start_url("http://www.google.com");
1978 contents()->GetMainFrame()->SendNavigate(1, start_url);
1979 EXPECT_EQ(1, controller().GetEntryCount());
1981 // Show an interstitial.
1982 TestInterstitialPage::InterstitialState state1 =
1983 TestInterstitialPage::INVALID;
1984 bool deleted1 = false;
1985 GURL url1("http://interstitial1");
1986 TestInterstitialPage* interstitial1 =
1987 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1988 TestInterstitialPageStateGuard state_guard1(interstitial1);
1989 interstitial1->Show();
1990 interstitial1->TestDidNavigate(1, url1);
1992 // Now show another interstitial.
1993 TestInterstitialPage::InterstitialState state2 =
1994 TestInterstitialPage::INVALID;
1995 bool deleted2 = false;
1996 GURL url2("http://interstitial2");
1997 TestInterstitialPage* interstitial2 =
1998 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1999 TestInterstitialPageStateGuard state_guard2(interstitial2);
2000 interstitial2->Show();
2001 interstitial2->TestDidNavigate(1, url2);
2003 // Showing interstitial2 should have caused interstitial1 to go away.
2004 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2005 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2007 RunAllPendingInMessageLoop();
2008 EXPECT_TRUE(deleted1);
2009 ASSERT_FALSE(deleted2);
2011 // Let's make sure interstitial2 is working as intended.
2012 interstitial2->Proceed();
2013 GURL landing_url("http://www.thepage.com");
2014 contents()->GetMainFrame()->SendNavigate(2, landing_url);
2016 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2017 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2018 NavigationEntry* entry = controller().GetVisibleEntry();
2019 ASSERT_TRUE(entry != NULL);
2020 EXPECT_TRUE(entry->GetURL() == landing_url);
2021 EXPECT_EQ(2, controller().GetEntryCount());
2022 RunAllPendingInMessageLoop();
2023 EXPECT_TRUE(deleted2);
2026 // Test showing an interstitial, proceeding and then navigating to another
2028 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
2029 // Navigate to a page so we have a navigation entry in the controller.
2030 GURL start_url("http://www.google.com");
2031 contents()->GetMainFrame()->SendNavigate(1, start_url);
2032 EXPECT_EQ(1, controller().GetEntryCount());
2034 // Show an interstitial.
2035 TestInterstitialPage::InterstitialState state1 =
2036 TestInterstitialPage::INVALID;
2037 bool deleted1 = false;
2038 GURL url1("http://interstitial1");
2039 TestInterstitialPage* interstitial1 =
2040 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2041 TestInterstitialPageStateGuard state_guard1(interstitial1);
2042 interstitial1->Show();
2043 interstitial1->TestDidNavigate(1, url1);
2045 // Take action. The interstitial won't be hidden until the navigation is
2047 interstitial1->Proceed();
2048 EXPECT_EQ(TestInterstitialPage::OKED, state1);
2050 // Now show another interstitial (simulating the navigation causing another
2052 TestInterstitialPage::InterstitialState state2 =
2053 TestInterstitialPage::INVALID;
2054 bool deleted2 = false;
2055 GURL url2("http://interstitial2");
2056 TestInterstitialPage* interstitial2 =
2057 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2058 TestInterstitialPageStateGuard state_guard2(interstitial2);
2059 interstitial2->Show();
2060 interstitial2->TestDidNavigate(1, url2);
2062 // Showing interstitial2 should have caused interstitial1 to go away.
2063 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2064 RunAllPendingInMessageLoop();
2065 EXPECT_TRUE(deleted1);
2066 ASSERT_FALSE(deleted2);
2068 // Let's make sure interstitial2 is working as intended.
2069 interstitial2->Proceed();
2070 GURL landing_url("http://www.thepage.com");
2071 contents()->GetMainFrame()->SendNavigate(2, landing_url);
2073 RunAllPendingInMessageLoop();
2074 EXPECT_TRUE(deleted2);
2075 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2076 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2077 NavigationEntry* entry = controller().GetVisibleEntry();
2078 ASSERT_TRUE(entry != NULL);
2079 EXPECT_TRUE(entry->GetURL() == landing_url);
2080 EXPECT_EQ(2, controller().GetEntryCount());
2083 // Test that navigating away from an interstitial while it's loading cause it
2085 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2086 // Show an interstitial.
2087 TestInterstitialPage::InterstitialState state =
2088 TestInterstitialPage::INVALID;
2089 bool deleted = false;
2090 GURL interstitial_url("http://interstitial");
2091 TestInterstitialPage* interstitial =
2092 new TestInterstitialPage(contents(), true, interstitial_url,
2094 TestInterstitialPageStateGuard state_guard(interstitial);
2095 interstitial->Show();
2097 // Let's simulate a navigation initiated from the browser before the
2098 // interstitial finishes loading.
2099 const GURL url("http://www.google.com");
2100 controller().LoadURL(
2101 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2102 EXPECT_FALSE(interstitial->is_showing());
2103 RunAllPendingInMessageLoop();
2104 ASSERT_FALSE(deleted);
2106 // Now let's make the interstitial navigation commit.
2107 interstitial->TestDidNavigate(1, interstitial_url);
2109 // After it loaded the interstitial should be gone.
2110 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2112 RunAllPendingInMessageLoop();
2113 EXPECT_TRUE(deleted);
2116 // Test that a new request to show an interstitial while an interstitial is
2117 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2118 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2119 GURL interstitial_url("http://interstitial");
2121 // Show a first interstitial.
2122 TestInterstitialPage::InterstitialState state1 =
2123 TestInterstitialPage::INVALID;
2124 bool deleted1 = false;
2125 TestInterstitialPage* interstitial1 =
2126 new TestInterstitialPage(contents(), true, interstitial_url,
2127 &state1, &deleted1);
2128 TestInterstitialPageStateGuard state_guard1(interstitial1);
2129 interstitial1->Show();
2131 // Show another interstitial on that same contents before the first one had
2133 TestInterstitialPage::InterstitialState state2 =
2134 TestInterstitialPage::INVALID;
2135 bool deleted2 = false;
2136 TestInterstitialPage* interstitial2 =
2137 new TestInterstitialPage(contents(), true, interstitial_url,
2138 &state2, &deleted2);
2139 TestInterstitialPageStateGuard state_guard2(interstitial2);
2140 interstitial2->Show();
2142 // The first interstitial should have been closed and deleted.
2143 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2144 // The 2nd one should still be OK.
2145 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2147 RunAllPendingInMessageLoop();
2148 EXPECT_TRUE(deleted1);
2149 ASSERT_FALSE(deleted2);
2151 // Make the interstitial navigation commit it should be showing.
2152 interstitial2->TestDidNavigate(1, interstitial_url);
2153 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2156 // Test showing an interstitial and have its renderer crash.
2157 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2158 // Show an interstitial.
2159 TestInterstitialPage::InterstitialState state =
2160 TestInterstitialPage::INVALID;
2161 bool deleted = false;
2162 GURL url("http://interstitial");
2163 TestInterstitialPage* interstitial =
2164 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2165 TestInterstitialPageStateGuard state_guard(interstitial);
2166 interstitial->Show();
2167 // Simulate a renderer crash before the interstitial is shown.
2168 interstitial->TestRenderViewTerminated(
2169 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2170 // The interstitial should have been dismissed.
2171 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2172 RunAllPendingInMessageLoop();
2173 EXPECT_TRUE(deleted);
2175 // Now try again but this time crash the intersitial after it was shown.
2177 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2178 interstitial->Show();
2179 interstitial->TestDidNavigate(1, url);
2180 // Simulate a renderer crash.
2181 interstitial->TestRenderViewTerminated(
2182 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2183 // The interstitial should have been dismissed.
2184 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2185 RunAllPendingInMessageLoop();
2186 EXPECT_TRUE(deleted);
2189 // Tests that showing an interstitial as a result of a browser initiated
2190 // navigation while an interstitial is showing does not remove the pending
2191 // entry (see http://crbug.com/9791).
2192 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2193 const char kUrl[] = "http://www.badguys.com/";
2194 const GURL kGURL(kUrl);
2196 // Start a navigation to a page
2197 contents()->GetController().LoadURL(
2198 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2200 // Simulate that navigation triggering an interstitial.
2201 TestInterstitialPage::InterstitialState state =
2202 TestInterstitialPage::INVALID;
2203 bool deleted = false;
2204 TestInterstitialPage* interstitial =
2205 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2206 TestInterstitialPageStateGuard state_guard(interstitial);
2207 interstitial->Show();
2208 interstitial->TestDidNavigate(1, kGURL);
2210 // Initiate a new navigation from the browser that also triggers an
2212 contents()->GetController().LoadURL(
2213 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2214 TestInterstitialPage::InterstitialState state2 =
2215 TestInterstitialPage::INVALID;
2216 bool deleted2 = false;
2217 TestInterstitialPage* interstitial2 =
2218 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2219 TestInterstitialPageStateGuard state_guard2(interstitial2);
2220 interstitial2->Show();
2221 interstitial2->TestDidNavigate(1, kGURL);
2223 // Make sure we still have an entry.
2224 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2226 EXPECT_EQ(kUrl, entry->GetURL().spec());
2228 // And that the first interstitial is gone, but not the second.
2229 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2230 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2231 RunAllPendingInMessageLoop();
2232 EXPECT_TRUE(deleted);
2233 EXPECT_FALSE(deleted2);
2236 // Tests that Javascript messages are not shown while an interstitial is
2238 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2239 const char kUrl[] = "http://www.badguys.com/";
2240 const GURL kGURL(kUrl);
2242 // Start a navigation to a page
2243 contents()->GetController().LoadURL(
2244 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2245 // DidNavigate from the page
2246 contents()->TestDidNavigate(
2247 contents()->GetMainFrame(), 1, kGURL, ui::PAGE_TRANSITION_TYPED);
2249 // Simulate showing an interstitial while the page is showing.
2250 TestInterstitialPage::InterstitialState state =
2251 TestInterstitialPage::INVALID;
2252 bool deleted = false;
2253 TestInterstitialPage* interstitial =
2254 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2255 TestInterstitialPageStateGuard state_guard(interstitial);
2256 interstitial->Show();
2257 interstitial->TestDidNavigate(1, kGURL);
2259 // While the interstitial is showing, let's simulate the hidden page
2260 // attempting to show a JS message.
2261 IPC::Message* dummy_message = new IPC::Message;
2262 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2263 base::ASCIIToUTF16("This is an informative message"),
2264 base::ASCIIToUTF16("OK"),
2265 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2266 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2269 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2270 // interstitial it isn't copied over to the destination.
2271 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2272 // Navigate to a page.
2273 GURL url1("http://www.google.com");
2274 contents()->GetMainFrame()->SendNavigate(1, url1);
2275 EXPECT_EQ(1, controller().GetEntryCount());
2277 // Initiate a browser navigation that will trigger the interstitial
2278 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2279 ui::PAGE_TRANSITION_TYPED, std::string());
2281 // Show an interstitial.
2282 TestInterstitialPage::InterstitialState state =
2283 TestInterstitialPage::INVALID;
2284 bool deleted = false;
2285 GURL url2("http://interstitial");
2286 TestInterstitialPage* interstitial =
2287 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2288 TestInterstitialPageStateGuard state_guard(interstitial);
2289 interstitial->Show();
2290 interstitial->TestDidNavigate(1, url2);
2291 EXPECT_TRUE(interstitial->is_showing());
2292 EXPECT_EQ(2, controller().GetEntryCount());
2294 // Create another NavigationController.
2295 GURL url3("http://foo2");
2296 scoped_ptr<TestWebContents> other_contents(
2297 static_cast<TestWebContents*>(CreateTestWebContents()));
2298 NavigationControllerImpl& other_controller = other_contents->GetController();
2299 other_contents->NavigateAndCommit(url3);
2300 other_contents->ExpectSetHistoryLengthAndPrune(
2301 NavigationEntryImpl::FromNavigationEntry(
2302 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2303 other_controller.GetEntryAtIndex(0)->GetPageID());
2304 other_controller.CopyStateFromAndPrune(&controller(), false);
2306 // The merged controller should only have two entries: url1 and url2.
2307 ASSERT_EQ(2, other_controller.GetEntryCount());
2308 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2309 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2310 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2312 // And the merged controller shouldn't be showing an interstitial.
2313 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2316 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2317 // showing an interstitial.
2318 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2319 // Navigate to a page.
2320 GURL url1("http://www.google.com");
2321 contents()->NavigateAndCommit(url1);
2323 // Create another NavigationController.
2324 scoped_ptr<TestWebContents> other_contents(
2325 static_cast<TestWebContents*>(CreateTestWebContents()));
2326 NavigationControllerImpl& other_controller = other_contents->GetController();
2328 // Navigate it to url2.
2329 GURL url2("http://foo2");
2330 other_contents->NavigateAndCommit(url2);
2332 // Show an interstitial.
2333 TestInterstitialPage::InterstitialState state =
2334 TestInterstitialPage::INVALID;
2335 bool deleted = false;
2336 GURL url3("http://interstitial");
2337 TestInterstitialPage* interstitial =
2338 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2340 TestInterstitialPageStateGuard state_guard(interstitial);
2341 interstitial->Show();
2342 interstitial->TestDidNavigate(1, url3);
2343 EXPECT_TRUE(interstitial->is_showing());
2344 EXPECT_EQ(2, other_controller.GetEntryCount());
2346 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2347 // interstitial is showing in the target.
2348 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2351 // Regression test for http://crbug.com/168611 - the URLs passed by the
2352 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2353 TEST_F(WebContentsImplTest, FilterURLs) {
2354 TestWebContentsObserver observer(contents());
2356 // A navigation to about:whatever should always look like a navigation to
2358 GURL url_normalized(url::kAboutBlankURL);
2359 GURL url_from_ipc("about:whatever");
2361 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2362 // will use the given URL to create the NavigationEntry as well, and that
2363 // entry should contain the filtered URL.
2364 contents()->NavigateAndCommit(url_normalized);
2366 // Check that an IPC with about:whatever is correctly normalized.
2367 contents()->TestDidFinishLoad(url_from_ipc);
2369 EXPECT_EQ(url_normalized, observer.last_url());
2371 // Create and navigate another WebContents.
2372 scoped_ptr<TestWebContents> other_contents(
2373 static_cast<TestWebContents*>(CreateTestWebContents()));
2374 TestWebContentsObserver other_observer(other_contents.get());
2375 other_contents->NavigateAndCommit(url_normalized);
2377 // Check that an IPC with about:whatever is correctly normalized.
2378 other_contents->TestDidFailLoadWithError(
2379 url_from_ipc, 1, base::string16());
2380 EXPECT_EQ(url_normalized, other_observer.last_url());
2383 // Test that if a pending contents is deleted before it is shown, we don't
2385 TEST_F(WebContentsImplTest, PendingContents) {
2386 scoped_ptr<TestWebContents> other_contents(
2387 static_cast<TestWebContents*>(CreateTestWebContents()));
2388 contents()->AddPendingContents(other_contents.get());
2389 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2390 other_contents.reset();
2391 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2394 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2395 const gfx::Size original_preferred_size(1024, 768);
2396 contents()->UpdatePreferredSize(original_preferred_size);
2398 // With no capturers, expect the preferred size to be the one propagated into
2399 // WebContentsImpl via the RenderViewHostDelegate interface.
2400 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2401 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2403 // Increment capturer count, but without specifying a capture size. Expect
2404 // a "not set" preferred size.
2405 contents()->IncrementCapturerCount(gfx::Size());
2406 EXPECT_EQ(1, contents()->GetCapturerCount());
2407 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2409 // Increment capturer count again, but with an overriding capture size.
2410 // Expect preferred size to now be overridden to the capture size.
2411 const gfx::Size capture_size(1280, 720);
2412 contents()->IncrementCapturerCount(capture_size);
2413 EXPECT_EQ(2, contents()->GetCapturerCount());
2414 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2416 // Increment capturer count a third time, but the expect that the preferred
2417 // size is still the first capture size.
2418 const gfx::Size another_capture_size(720, 480);
2419 contents()->IncrementCapturerCount(another_capture_size);
2420 EXPECT_EQ(3, contents()->GetCapturerCount());
2421 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2423 // Decrement capturer count twice, but expect the preferred size to still be
2425 contents()->DecrementCapturerCount();
2426 contents()->DecrementCapturerCount();
2427 EXPECT_EQ(1, contents()->GetCapturerCount());
2428 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2430 // Decrement capturer count, and since the count has dropped to zero, the
2431 // original preferred size should be restored.
2432 contents()->DecrementCapturerCount();
2433 EXPECT_EQ(0, contents()->GetCapturerCount());
2434 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2437 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2439 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2440 // The WebContents starts with a valid creation time.
2441 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2443 // Reset the last active time to a known-bad value.
2444 contents()->last_active_time_ = base::TimeTicks();
2445 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2447 // Simulate activating the WebContents. The active time should update.
2448 contents()->WasShown();
2449 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2452 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2454 ContentsZoomChangedDelegate() :
2455 contents_zoom_changed_call_count_(0),
2456 last_zoom_in_(false) {
2459 int GetAndResetContentsZoomChangedCallCount() {
2460 int count = contents_zoom_changed_call_count_;
2461 contents_zoom_changed_call_count_ = 0;
2465 bool last_zoom_in() const {
2466 return last_zoom_in_;
2469 // WebContentsDelegate:
2470 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
2471 contents_zoom_changed_call_count_++;
2472 last_zoom_in_ = zoom_in;
2476 int contents_zoom_changed_call_count_;
2479 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2482 // Tests that some mouseehweel events get turned into browser zoom requests.
2483 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2484 using blink::WebInputEvent;
2486 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2487 new ContentsZoomChangedDelegate());
2488 contents()->SetDelegate(delegate.get());
2491 // Verify that normal mouse wheel events do nothing to change the zoom level.
2492 blink::WebMouseWheelEvent event =
2493 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2494 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2495 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2497 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
2498 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2499 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2500 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2502 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2503 // Except on MacOS where we never want to adjust zoom with mousewheel.
2504 modifiers = WebInputEvent::ControlKey;
2505 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2506 bool handled = contents()->HandleWheelEvent(event);
2507 #if defined(OS_MACOSX)
2508 EXPECT_FALSE(handled);
2509 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2511 EXPECT_TRUE(handled);
2512 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2513 EXPECT_TRUE(delegate->last_zoom_in());
2516 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2517 WebInputEvent::AltKey;
2518 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2519 handled = contents()->HandleWheelEvent(event);
2520 #if defined(OS_MACOSX)
2521 EXPECT_FALSE(handled);
2522 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2524 EXPECT_TRUE(handled);
2525 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2526 EXPECT_FALSE(delegate->last_zoom_in());
2529 // Unless there is no vertical movement.
2530 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2531 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2532 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2534 // Events containing precise scrolling deltas also shouldn't result in the
2535 // zoom being adjusted, to avoid accidental adjustments caused by
2536 // two-finger-scrolling on a touchpad.
2537 modifiers = WebInputEvent::ControlKey;
2538 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2539 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2540 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2542 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2543 contents()->SetDelegate(NULL);
2546 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2547 TEST_F(WebContentsImplTest, HandleGestureEvent) {
2548 using blink::WebGestureEvent;
2549 using blink::WebInputEvent;
2551 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2552 new ContentsZoomChangedDelegate());
2553 contents()->SetDelegate(delegate.get());
2555 const float kZoomStepValue = 0.6f;
2556 blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
2557 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad);
2559 // A pinch less than the step value doesn't change the zoom level.
2560 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
2561 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2562 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2564 // But repeating the event so the combined scale is greater does.
2565 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2566 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2567 EXPECT_TRUE(delegate->last_zoom_in());
2569 // Pinching back out one step goes back to 100%.
2570 event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
2571 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2572 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2573 EXPECT_FALSE(delegate->last_zoom_in());
2575 // Pinching out again doesn't zoom (step is twice as large around 100%).
2576 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2577 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2579 // And again now it zooms once per step.
2580 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2581 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2582 EXPECT_FALSE(delegate->last_zoom_in());
2584 // No other type of gesture event is handled by WebContentsImpl (for example
2585 // a touchscreen pinch gesture).
2586 event = SyntheticWebGestureEventBuilder::Build(
2587 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen);
2588 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
2589 EXPECT_FALSE(contents()->HandleGestureEvent(event));
2590 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2592 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2593 contents()->SetDelegate(NULL);
2596 // Tests that GetRelatedActiveContentsCount is shared between related
2597 // SiteInstances and includes WebContents that have not navigated yet.
2598 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
2599 scoped_refptr<SiteInstance> instance1(
2600 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2601 scoped_refptr<SiteInstance> instance2(
2602 instance1->GetRelatedSiteInstance(GURL("http://b.com")));
2604 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2605 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2607 scoped_ptr<TestWebContents> contents1(
2608 TestWebContents::Create(browser_context(), instance1.get()));
2609 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2610 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2612 scoped_ptr<TestWebContents> contents2(
2613 TestWebContents::Create(browser_context(), instance1.get()));
2614 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
2615 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
2618 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2619 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2622 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2623 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2626 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2627 // same-site and cross-site navigations.
2628 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
2629 scoped_refptr<SiteInstance> instance(
2630 SiteInstance::Create(browser_context()));
2632 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2634 scoped_ptr<TestWebContents> contents(
2635 TestWebContents::Create(browser_context(), instance.get()));
2636 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2638 // Navigate to a URL.
2639 contents->GetController().LoadURL(GURL("http://a.com/1"),
2641 ui::PAGE_TRANSITION_TYPED,
2643 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2644 contents->CommitPendingNavigation();
2645 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2647 // Navigate to a URL in the same site.
2648 contents->GetController().LoadURL(GURL("http://a.com/2"),
2650 ui::PAGE_TRANSITION_TYPED,
2652 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2653 contents->CommitPendingNavigation();
2654 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2656 // Navigate to a URL in a different site.
2657 contents->GetController().LoadURL(GURL("http://b.com"),
2659 ui::PAGE_TRANSITION_TYPED,
2661 EXPECT_TRUE(contents->cross_navigation_pending());
2662 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2663 contents->CommitPendingNavigation();
2664 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2667 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2670 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2672 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2673 scoped_refptr<SiteInstance> instance(
2674 SiteInstance::Create(browser_context()));
2676 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2678 scoped_ptr<TestWebContents> contents(
2679 TestWebContents::Create(browser_context(), instance.get()));
2680 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2682 // Navigate to a URL.
2683 contents->NavigateAndCommit(GURL("http://a.com"));
2684 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2686 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2687 contents->GetController().LoadURL(GURL(kTestWebUIUrl),
2689 ui::PAGE_TRANSITION_TYPED,
2691 EXPECT_TRUE(contents->cross_navigation_pending());
2692 scoped_refptr<SiteInstance> instance_webui(
2693 contents->GetPendingMainFrame()->GetSiteInstance());
2694 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2696 // At this point, contents still counts for the old BrowsingInstance.
2697 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2698 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2700 // Commit and contents counts for the new one.
2701 contents->CommitPendingNavigation();
2702 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2703 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2706 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2707 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2710 // ChromeOS doesn't use WebContents based power save blocking.
2711 #if !defined(OS_CHROMEOS)
2712 TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
2713 // PlayerIDs are actually pointers cast to int64, so verify that both negative
2714 // and positive player ids don't blow up.
2715 const int kPlayerAudioVideoId = 15;
2716 const int kPlayerAudioOnlyId = -15;
2717 const int kPlayerVideoOnlyId = 30;
2719 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2720 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2722 TestRenderFrameHost* rfh = contents()->GetMainFrame();
2723 AudioStreamMonitor* monitor = contents()->audio_stream_monitor();
2725 // The audio power save blocker should not be based on having a media player
2726 // when audio stream monitoring is available.
2727 if (AudioStreamMonitor::monitoring_available()) {
2728 // Send a fake audio stream monitor notification. The audio power save
2729 // blocker should be created.
2730 monitor->set_was_recently_audible_for_testing(true);
2731 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
2732 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
2734 // Send another fake notification, this time when WasRecentlyAudible() will
2735 // be false. The power save blocker should be released.
2736 monitor->set_was_recently_audible_for_testing(false);
2737 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
2738 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2741 // Start a player with both audio and video. A video power save blocker
2742 // should be created. If audio stream monitoring is available, an audio power
2743 // save blocker should be created too.
2744 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2745 0, kPlayerAudioVideoId, true, true));
2746 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2747 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2748 !AudioStreamMonitor::monitoring_available());
2750 // Upon hiding the video power save blocker should be released.
2751 contents()->WasHidden();
2752 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2754 // Start another player that only has video. There should be no change in
2755 // the power save blockers. The notification should take into account the
2756 // visibility state of the WebContents.
2757 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2758 0, kPlayerVideoOnlyId, true, false));
2759 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2760 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2761 !AudioStreamMonitor::monitoring_available());
2763 // Showing the WebContents should result in the creation of the blocker.
2764 contents()->WasShown();
2765 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2767 // Start another player that only has audio. There should be no change in
2768 // the power save blockers.
2769 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2770 0, kPlayerAudioOnlyId, false, true));
2771 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2772 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2773 !AudioStreamMonitor::monitoring_available());
2775 // Destroy the original audio video player. Both power save blockers should
2777 rfh->OnMessageReceived(
2778 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
2779 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2780 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2781 !AudioStreamMonitor::monitoring_available());
2783 // Destroy the audio only player. The video power save blocker should remain.
2784 rfh->OnMessageReceived(
2785 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId));
2786 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2787 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2789 // Destroy the video only player. No power save blockers should remain.
2790 rfh->OnMessageReceived(
2791 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId));
2792 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2793 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2797 } // namespace content