web_contents_impl_unittest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/logging.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/browser/frame_host/interstitial_page_impl.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/browser/frame_host/navigation_entry_impl.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/browser/renderer_host/render_view_host_impl.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/browser/site_instance_impl.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/browser/webui/web_ui_controller_factory_registry.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/common/view_messages.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/global_request_id.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "content/public/browser/interstitial_page_delegate.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/navigation_details.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/notification_details.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/notification_source.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/render_widget_host_view.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/web_contents_observer.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/public/browser/web_ui_controller.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/common/bindings_policy.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/public/common/content_constants.h"
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "content/public/common/url_constants.h"
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "content/public/test/mock_render_process_host.h"
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "content/public/test/test_browser_thread.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/test/test_utils.h"
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/test/test_content_browser_client.h"
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/test/test_content_client.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/test/test_render_view_host.h"
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/test/test_web_contents.h"
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kTestWebUIUrl[] = "chrome://blah";
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class WebContentsImplTestWebUIControllerFactory
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : public WebUIControllerFactory {
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual WebUIController* CreateWebUIControllerForURL(
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      WebUI* web_ui, const GURL& url) const OVERRIDE {
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!UseWebUI(url))
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return NULL;
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return new WebUIController(web_ui);
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const GURL& url) const OVERRIDE {
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return WebUI::kNoWebUI;
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool UseWebUIForURL(BrowserContext* browser_context,
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              const GURL& url) const OVERRIDE {
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return UseWebUI(url);
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                      const GURL& url) const OVERRIDE {
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return UseWebUI(url);
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool UseWebUI(const GURL& url) const {
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return url == GURL(kTestWebUIUrl);
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class TestInterstitialPage;
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class TestInterstitialPageDelegate : public InterstitialPageDelegate {
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public:
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      : interstitial_page_(interstitial_page) {}
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void CommandReceived(const std::string& command) OVERRIDE;
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual void OnDontProceed() OVERRIDE;
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual void OnProceed() OVERRIDE;
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private:
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TestInterstitialPage* interstitial_page_;
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass TestInterstitialPage : public InterstitialPageImpl {
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public:
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  enum InterstitialState {
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    INVALID = 0,    // Hasn't yet been initialized.
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UNDECIDED,      // Initialized, but no decision taken yet.
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    OKED,           // Proceed was called.
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CANCELED        // DontProceed was called.
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  };
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  class Delegate {
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   public:
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    virtual void TestInterstitialPageDeleted(
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        TestInterstitialPage* interstitial) = 0;
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   protected:
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual ~Delegate() {}
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // IMPORTANT NOTE: if you pass stack allocated values for |state| and
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // |deleted| (like all interstitial related tests do at this point), make sure
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // to create an instance of the TestInterstitialPageStateGuard class on the
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // stack in your test.  This will ensure that the TestInterstitialPage states
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // are cleared when the test finishes.
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Not doing so will cause stack trashing if your test does not hide the
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // interstitial, as in such a case it will be destroyed in the test TearDown
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // method and will dereference the |deleted| local variable which by then is
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // out of scope.
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TestInterstitialPage(WebContentsImpl* contents,
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       bool new_navigation,
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       const GURL& url,
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       InterstitialState* state,
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       bool* deleted)
115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      : InterstitialPageImpl(
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            contents,
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            static_cast<RenderWidgetHostDelegate*>(contents),
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            new_navigation, url, new TestInterstitialPageDelegate(this)),
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        state_(state),
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        deleted_(deleted),
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        command_received_count_(0),
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        delegate_(NULL) {
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *state_ = UNDECIDED;
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *deleted_ = false;
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual ~TestInterstitialPage() {
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (deleted_)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      *deleted_ = true;
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (delegate_)
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->TestInterstitialPageDeleted(this);
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void OnDontProceed() {
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (state_)
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      *state_ = CANCELED;
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  void OnProceed() {
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (state_)
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      *state_ = OKED;
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int command_received_count() const {
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return command_received_count_;
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void TestDomOperationResponse(const std::string& json_string) {
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (enabled())
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      CommandReceived();
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void TestDidNavigate(int page_id, const GURL& url) {
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ViewHostMsg_FrameNavigate_Params params;
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DidNavigate(GetRenderViewHostForTesting(), params);
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void TestRenderViewTerminated(base::TerminationStatus status,
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                int error_code) {
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool is_showing() const {
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return static_cast<TestRenderWidgetHostView*>(
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        GetRenderViewHostForTesting()->GetView())->is_showing();
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void ClearStates() {
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    state_ = NULL;
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    deleted_ = NULL;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    delegate_ = NULL;
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void CommandReceived() {
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    command_received_count_++;
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void set_delegate(Delegate* delegate) {
17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    delegate_ = delegate;
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) protected:
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual RenderViewHost* CreateRenderViewHost() OVERRIDE {
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return new TestRenderViewHost(
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        SiteInstance::Create(web_contents()->GetBrowserContext()),
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        this, this, this, MSG_ROUTING_NONE, MSG_ROUTING_NONE, false);
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual WebContentsView* CreateWebContentsView() OVERRIDE {
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return NULL;
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private:
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  InterstitialState* state_;
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool* deleted_;
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int command_received_count_;
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Delegate* delegate_;
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  interstitial_page_->CommandReceived();
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void TestInterstitialPageDelegate::OnDontProceed() {
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  interstitial_page_->OnDontProceed();
20603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void TestInterstitialPageDelegate::OnProceed() {
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  interstitial_page_->OnProceed();
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit TestInterstitialPageStateGuard(
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      TestInterstitialPage* interstitial_page)
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      : interstitial_page_(interstitial_page) {
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK(interstitial_page_);
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    interstitial_page_->set_delegate(this);
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~TestInterstitialPageStateGuard() {
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (interstitial_page_)
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      interstitial_page_->ClearStates();
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void TestInterstitialPageDeleted(
22603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      TestInterstitialPage* interstitial) OVERRIDE {
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK(interstitial_page_ == interstitial);
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    interstitial_page_ = NULL;
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  TestInterstitialPage* interstitial_page_;
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  WebContentsImplTestBrowserClient()
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      : assign_site_for_url_(false) {}
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~WebContentsImplTestBrowserClient() {}
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
24303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return assign_site_for_url_;
24403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void set_assign_site_for_url(bool assign) {
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    assign_site_for_url_ = assign;
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
24903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
25003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private:
25103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool assign_site_for_url_;
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class WebContentsImplTest : public RenderViewHostImplTestHarness {
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void SetUp() {
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    RenderViewHostImplTestHarness::SetUp();
2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    WebUIControllerFactory::RegisterFactory(&factory_);
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void TearDown() {
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RenderViewHostImplTestHarness::TearDown();
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private:
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebContentsImplTestWebUIControllerFactory factory_;
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class TestWebContentsObserver : public WebContentsObserver {
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public:
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  explicit TestWebContentsObserver(WebContents* contents)
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      : WebContentsObserver(contents) {
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~TestWebContentsObserver() {}
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void DidFinishLoad(int64 frame_id,
27803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             const GURL& validated_url,
27903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             bool is_main_frame,
28003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             RenderViewHost* render_view_host) OVERRIDE {
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    last_url_ = validated_url;
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void DidFailLoad(int64 frame_id,
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const GURL& validated_url,
2857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           bool is_main_frame,
2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           int error_code,
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const base::string16& error_description,
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           RenderViewHost* render_view_host) OVERRIDE {
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    last_url_ = validated_url;
29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const GURL& last_url() const { return last_url_; }
29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GURL last_url_;
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
2987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Test to make sure that title updates get stripped of whitespace.
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST_F(WebContentsImplTest, UpdateTitle) {
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  NavigationControllerImpl& cont =
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      static_cast<NavigationControllerImpl&>(controller());
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ViewHostMsg_FrameNavigate_Params params;
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  InitNavigateParams(&params, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LoadCommittedDetails details;
3107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  cont.RendererDidNavigate(params, &details);
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  contents()->UpdateTitle(rvh(), 0, ASCIIToUTF16("    Lots O' Whitespace\n"),
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          base::i18n::LEFT_TO_RIGHT);
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
315}
316
317TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
318  const GURL kGURL("chrome://blah");
319  controller().LoadURL(
320      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
321  EXPECT_EQ(base::string16(), contents()->GetTitle());
322}
323
324TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
325  const GURL kGURL("chrome://blah");
326  const base::string16 title = ASCIIToUTF16("My Title");
327  controller().LoadURL(
328      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
329
330  NavigationEntry* entry = controller().GetVisibleEntry();
331  ASSERT_EQ(kGURL, entry->GetURL());
332  entry->SetTitle(title);
333
334  EXPECT_EQ(title, contents()->GetTitle());
335}
336
337// Test view source mode for a webui page.
338TEST_F(WebContentsImplTest, NTPViewSource) {
339  NavigationControllerImpl& cont =
340      static_cast<NavigationControllerImpl&>(controller());
341  const char kUrl[] = "view-source:chrome://blah";
342  const GURL kGURL(kUrl);
343
344  process()->sink().ClearMessages();
345
346  cont.LoadURL(
347      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
348  rvh()->GetDelegate()->RenderViewCreated(rvh());
349  // Did we get the expected message?
350  EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
351      ViewMsg_EnableViewSourceMode::ID));
352
353  ViewHostMsg_FrameNavigate_Params params;
354  InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
355  LoadCommittedDetails details;
356  cont.RendererDidNavigate(params, &details);
357  // Also check title and url.
358  EXPECT_EQ(ASCIIToUTF16(kUrl), contents()->GetTitle());
359}
360
361// Test to ensure UpdateMaxPageID is working properly.
362TEST_F(WebContentsImplTest, UpdateMaxPageID) {
363  SiteInstance* instance1 = contents()->GetSiteInstance();
364  scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
365
366  // Starts at -1.
367  EXPECT_EQ(-1, contents()->GetMaxPageID());
368  EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
369  EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
370
371  // Make sure max_page_id_ is monotonically increasing per SiteInstance.
372  contents()->UpdateMaxPageID(3);
373  contents()->UpdateMaxPageID(1);
374  EXPECT_EQ(3, contents()->GetMaxPageID());
375  EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
376  EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
377
378  contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
379  EXPECT_EQ(3, contents()->GetMaxPageID());
380  EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
381  EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
382}
383
384// Test simple same-SiteInstance navigation.
385TEST_F(WebContentsImplTest, SimpleNavigation) {
386  TestRenderViewHost* orig_rvh = test_rvh();
387  SiteInstance* instance1 = contents()->GetSiteInstance();
388  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
389
390  // Navigate to URL
391  const GURL url("http://www.google.com");
392  controller().LoadURL(
393      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
394  EXPECT_FALSE(contents()->cross_navigation_pending());
395  EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
396  // Controller's pending entry will have a NULL site instance until we assign
397  // it in DidNavigate.
398  EXPECT_TRUE(
399      NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
400          site_instance() == NULL);
401
402  // DidNavigate from the page
403  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
404  EXPECT_FALSE(contents()->cross_navigation_pending());
405  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
406  EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
407  // Controller's entry should now have the SiteInstance, or else we won't be
408  // able to find it later.
409  EXPECT_EQ(
410      instance1,
411      NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
412          site_instance());
413}
414
415// Test that we reject NavigateToEntry if the url is over kMaxURLChars.
416TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
417  // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
418  const GURL url(std::string("http://example.org/").append(
419      kMaxURLChars + 1, 'a'));
420
421  controller().LoadURL(
422      url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
423  EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
424}
425
426// Test that navigating across a site boundary creates a new RenderViewHost
427// with a new SiteInstance.  Going back should do the same.
428TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
429  contents()->transition_cross_site = true;
430  TestRenderViewHost* orig_rvh = test_rvh();
431  int orig_rvh_delete_count = 0;
432  orig_rvh->set_delete_counter(&orig_rvh_delete_count);
433  SiteInstance* instance1 = contents()->GetSiteInstance();
434
435  // Navigate to URL.  First URL should use first RenderViewHost.
436  const GURL url("http://www.google.com");
437  controller().LoadURL(
438      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
439  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
440
441  // Keep the number of active views in orig_rvh's SiteInstance
442  // non-zero so that orig_rvh doesn't get deleted when it gets
443  // swapped out.
444  static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
445      increment_active_view_count();
446
447  EXPECT_FALSE(contents()->cross_navigation_pending());
448  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
449  EXPECT_EQ(url, contents()->GetLastCommittedURL());
450  EXPECT_EQ(url, contents()->GetVisibleURL());
451
452  // Navigate to new site
453  const GURL url2("http://www.yahoo.com");
454  controller().LoadURL(
455      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
456  EXPECT_TRUE(contents()->cross_navigation_pending());
457  EXPECT_EQ(url, contents()->GetLastCommittedURL());
458  EXPECT_EQ(url2, contents()->GetVisibleURL());
459  TestRenderViewHost* pending_rvh =
460      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
461  int pending_rvh_delete_count = 0;
462  pending_rvh->set_delete_counter(&pending_rvh_delete_count);
463
464  // Navigations should be suspended in pending_rvh until ShouldCloseACK.
465  EXPECT_TRUE(pending_rvh->are_navigations_suspended());
466  orig_rvh->SendShouldCloseACK(true);
467  EXPECT_FALSE(pending_rvh->are_navigations_suspended());
468
469  // DidNavigate from the pending page
470  contents()->TestDidNavigate(
471      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
472  SiteInstance* instance2 = contents()->GetSiteInstance();
473
474  // Keep the number of active views in pending_rvh's SiteInstance
475  // non-zero so that orig_rvh doesn't get deleted when it gets
476  // swapped out.
477  static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
478      increment_active_view_count();
479
480  EXPECT_FALSE(contents()->cross_navigation_pending());
481  EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
482  EXPECT_EQ(url2, contents()->GetLastCommittedURL());
483  EXPECT_EQ(url2, contents()->GetVisibleURL());
484  EXPECT_NE(instance1, instance2);
485  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
486  // We keep the original RVH around, swapped out.
487  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
488      orig_rvh));
489  EXPECT_EQ(orig_rvh_delete_count, 0);
490
491  // Going back should switch SiteInstances again.  The first SiteInstance is
492  // stored in the NavigationEntry, so it should be the same as at the start.
493  // We should use the same RVH as before, swapping it back in.
494  controller().GoBack();
495  TestRenderViewHost* goback_rvh =
496      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
497  EXPECT_EQ(orig_rvh, goback_rvh);
498  EXPECT_TRUE(contents()->cross_navigation_pending());
499
500  // Navigations should be suspended in goback_rvh until ShouldCloseACK.
501  EXPECT_TRUE(goback_rvh->are_navigations_suspended());
502  pending_rvh->SendShouldCloseACK(true);
503  EXPECT_FALSE(goback_rvh->are_navigations_suspended());
504
505  // DidNavigate from the back action
506  contents()->TestDidNavigate(
507      goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
508  EXPECT_FALSE(contents()->cross_navigation_pending());
509  EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
510  EXPECT_EQ(instance1, contents()->GetSiteInstance());
511  // The pending RVH should now be swapped out, not deleted.
512  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
513      IsOnSwappedOutList(pending_rvh));
514  EXPECT_EQ(pending_rvh_delete_count, 0);
515
516  // Close contents and ensure RVHs are deleted.
517  DeleteContents();
518  EXPECT_EQ(orig_rvh_delete_count, 1);
519  EXPECT_EQ(pending_rvh_delete_count, 1);
520}
521
522// Test that navigating across a site boundary after a crash creates a new
523// RVH without requiring a cross-site transition (i.e., PENDING state).
524TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
525  contents()->transition_cross_site = true;
526  TestRenderViewHost* orig_rvh = test_rvh();
527  int orig_rvh_delete_count = 0;
528  orig_rvh->set_delete_counter(&orig_rvh_delete_count);
529  SiteInstance* instance1 = contents()->GetSiteInstance();
530
531  // Navigate to URL.  First URL should use first RenderViewHost.
532  const GURL url("http://www.google.com");
533  controller().LoadURL(
534      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
535  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
536
537  EXPECT_FALSE(contents()->cross_navigation_pending());
538  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
539
540  // Crash the renderer.
541  orig_rvh->set_render_view_created(false);
542
543  // Navigate to new site.  We should not go into PENDING.
544  const GURL url2("http://www.yahoo.com");
545  controller().LoadURL(
546      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
547  RenderViewHost* new_rvh = rvh();
548  EXPECT_FALSE(contents()->cross_navigation_pending());
549  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
550  EXPECT_NE(orig_rvh, new_rvh);
551  EXPECT_EQ(orig_rvh_delete_count, 1);
552
553  // DidNavigate from the new page
554  contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
555  SiteInstance* instance2 = contents()->GetSiteInstance();
556
557  EXPECT_FALSE(contents()->cross_navigation_pending());
558  EXPECT_EQ(new_rvh, rvh());
559  EXPECT_NE(instance1, instance2);
560  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
561
562  // Close contents and ensure RVHs are deleted.
563  DeleteContents();
564  EXPECT_EQ(orig_rvh_delete_count, 1);
565}
566
567// Test that opening a new contents in the same SiteInstance and then navigating
568// both contentses to a new site will place both contentses in a single
569// SiteInstance.
570TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
571  contents()->transition_cross_site = true;
572  TestRenderViewHost* orig_rvh = test_rvh();
573  SiteInstance* instance1 = contents()->GetSiteInstance();
574
575  // Navigate to URL.  First URL should use first RenderViewHost.
576  const GURL url("http://www.google.com");
577  controller().LoadURL(
578      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
579  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
580
581  // Open a new contents with the same SiteInstance, navigated to the same site.
582  scoped_ptr<TestWebContents> contents2(
583      TestWebContents::Create(browser_context(), instance1));
584  contents2->transition_cross_site = true;
585  contents2->GetController().LoadURL(url, Referrer(),
586                                    PAGE_TRANSITION_TYPED,
587                                    std::string());
588  // Need this page id to be 2 since the site instance is the same (which is the
589  // scope of page IDs) and we want to consider this a new page.
590  contents2->TestDidNavigate(
591      contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
592
593  // Navigate first contents to a new site.
594  const GURL url2a("http://www.yahoo.com");
595  controller().LoadURL(
596      url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
597  orig_rvh->SendShouldCloseACK(true);
598  TestRenderViewHost* pending_rvh_a =
599      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
600  contents()->TestDidNavigate(
601      pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
602  SiteInstance* instance2a = contents()->GetSiteInstance();
603  EXPECT_NE(instance1, instance2a);
604
605  // Navigate second contents to the same site as the first tab.
606  const GURL url2b("http://mail.yahoo.com");
607  contents2->GetController().LoadURL(url2b, Referrer(),
608                                    PAGE_TRANSITION_TYPED,
609                                    std::string());
610  TestRenderViewHost* rvh2 =
611      static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
612  rvh2->SendShouldCloseACK(true);
613  TestRenderViewHost* pending_rvh_b =
614      static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
615  EXPECT_TRUE(pending_rvh_b != NULL);
616  EXPECT_TRUE(contents2->cross_navigation_pending());
617
618  // NOTE(creis): We used to be in danger of showing a crash page here if the
619  // second contents hadn't navigated somewhere first (bug 1145430).  That case
620  // is now covered by the CrossSiteBoundariesAfterCrash test.
621  contents2->TestDidNavigate(
622      pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
623  SiteInstance* instance2b = contents2->GetSiteInstance();
624  EXPECT_NE(instance1, instance2b);
625
626  // Both contentses should now be in the same SiteInstance.
627  EXPECT_EQ(instance2a, instance2b);
628}
629
630TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
631  WebContentsImplTestBrowserClient browser_client;
632  SetBrowserClientForTesting(&browser_client);
633
634  contents()->transition_cross_site = true;
635  TestRenderViewHost* orig_rvh = test_rvh();
636  int orig_rvh_delete_count = 0;
637  orig_rvh->set_delete_counter(&orig_rvh_delete_count);
638  SiteInstanceImpl* orig_instance =
639      static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
640
641  browser_client.set_assign_site_for_url(false);
642  // Navigate to an URL that will not assign a new SiteInstance.
643  const GURL native_url("non-site-url://stuffandthings");
644  controller().LoadURL(
645      native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
646  contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
647
648  EXPECT_FALSE(contents()->cross_navigation_pending());
649  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
650  EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
651  EXPECT_EQ(native_url, contents()->GetVisibleURL());
652  EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
653  EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
654  EXPECT_FALSE(orig_instance->HasSite());
655
656  browser_client.set_assign_site_for_url(true);
657  // Navigate to new site (should keep same site instance).
658  const GURL url("http://www.google.com");
659  controller().LoadURL(
660      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
661  EXPECT_FALSE(contents()->cross_navigation_pending());
662  EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
663  EXPECT_EQ(url, contents()->GetVisibleURL());
664  EXPECT_FALSE(contents()->GetPendingRenderViewHost());
665  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
666
667  // Keep the number of active views in orig_rvh's SiteInstance
668  // non-zero so that orig_rvh doesn't get deleted when it gets
669  // swapped out.
670  static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
671      increment_active_view_count();
672
673  EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
674  EXPECT_TRUE(
675      contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
676  EXPECT_EQ(url, contents()->GetLastCommittedURL());
677
678  // Navigate to another new site (should create a new site instance).
679  const GURL url2("http://www.yahoo.com");
680  controller().LoadURL(
681      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
682  EXPECT_TRUE(contents()->cross_navigation_pending());
683  EXPECT_EQ(url, contents()->GetLastCommittedURL());
684  EXPECT_EQ(url2, contents()->GetVisibleURL());
685  TestRenderViewHost* pending_rvh =
686      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
687  int pending_rvh_delete_count = 0;
688  pending_rvh->set_delete_counter(&pending_rvh_delete_count);
689
690  // Navigations should be suspended in pending_rvh until ShouldCloseACK.
691  EXPECT_TRUE(pending_rvh->are_navigations_suspended());
692  orig_rvh->SendShouldCloseACK(true);
693  EXPECT_FALSE(pending_rvh->are_navigations_suspended());
694
695  // DidNavigate from the pending page.
696  contents()->TestDidNavigate(
697      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
698  SiteInstance* new_instance = contents()->GetSiteInstance();
699
700  EXPECT_FALSE(contents()->cross_navigation_pending());
701  EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
702  EXPECT_EQ(url2, contents()->GetLastCommittedURL());
703  EXPECT_EQ(url2, contents()->GetVisibleURL());
704  EXPECT_NE(new_instance, orig_instance);
705  EXPECT_FALSE(contents()->GetPendingRenderViewHost());
706  // We keep the original RVH around, swapped out.
707  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
708      orig_rvh));
709  EXPECT_EQ(orig_rvh_delete_count, 0);
710
711  // Close contents and ensure RVHs are deleted.
712  DeleteContents();
713  EXPECT_EQ(orig_rvh_delete_count, 1);
714  EXPECT_EQ(pending_rvh_delete_count, 1);
715}
716
717// Test that we can find an opener RVH even if it's pending.
718// http://crbug.com/176252.
719TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
720  contents()->transition_cross_site = true;
721  TestRenderViewHost* orig_rvh = test_rvh();
722
723  // Navigate to a URL.
724  const GURL url("http://www.google.com");
725  controller().LoadURL(
726      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
727  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
728
729  // Start to navigate first tab to a new site, so that it has a pending RVH.
730  const GURL url2("http://www.yahoo.com");
731  controller().LoadURL(
732      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
733  orig_rvh->SendShouldCloseACK(true);
734  TestRenderViewHost* pending_rvh =
735      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
736
737  // While it is still pending, simulate opening a new tab with the first tab
738  // as its opener.  This will call WebContentsImpl::CreateOpenerRenderViews
739  // on the opener to ensure that an RVH exists.
740  int opener_routing_id = contents()->CreateOpenerRenderViews(
741      pending_rvh->GetSiteInstance());
742
743  // We should find the pending RVH and not create a new one.
744  EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
745}
746
747// Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
748// to determine whether a navigation is cross-site.
749TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
750  contents()->transition_cross_site = true;
751  RenderViewHost* orig_rvh = rvh();
752  SiteInstance* instance1 = contents()->GetSiteInstance();
753
754  // Navigate to URL.
755  const GURL url("http://www.google.com");
756  controller().LoadURL(
757      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
758  contents()->TestDidNavigate(
759      orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
760
761  // Open a related contents to a second site.
762  scoped_ptr<TestWebContents> contents2(
763      TestWebContents::Create(browser_context(), instance1));
764  contents2->transition_cross_site = true;
765  const GURL url2("http://www.yahoo.com");
766  contents2->GetController().LoadURL(url2, Referrer(),
767                                    PAGE_TRANSITION_TYPED,
768                                    std::string());
769  // The first RVH in contents2 isn't live yet, so we shortcut the cross site
770  // pending.
771  TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
772      contents2->GetRenderViewHost());
773  EXPECT_FALSE(contents2->cross_navigation_pending());
774  contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
775  SiteInstance* instance2 = contents2->GetSiteInstance();
776  EXPECT_NE(instance1, instance2);
777  EXPECT_FALSE(contents2->cross_navigation_pending());
778
779  // Simulate a link click in first contents to second site.  Doesn't switch
780  // SiteInstances, because we don't intercept WebKit navigations.
781  contents()->TestDidNavigate(
782      orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
783  SiteInstance* instance3 = contents()->GetSiteInstance();
784  EXPECT_EQ(instance1, instance3);
785  EXPECT_FALSE(contents()->cross_navigation_pending());
786
787  // Navigate to the new site.  Doesn't switch SiteInstancees, because we
788  // compare against the current URL, not the SiteInstance's site.
789  const GURL url3("http://mail.yahoo.com");
790  controller().LoadURL(
791      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
792  EXPECT_FALSE(contents()->cross_navigation_pending());
793  contents()->TestDidNavigate(
794      orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
795  SiteInstance* instance4 = contents()->GetSiteInstance();
796  EXPECT_EQ(instance1, instance4);
797}
798
799// Test that the onbeforeunload and onunload handlers run when navigating
800// across site boundaries.
801TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
802  contents()->transition_cross_site = true;
803  TestRenderViewHost* orig_rvh = test_rvh();
804  SiteInstance* instance1 = contents()->GetSiteInstance();
805
806  // Navigate to URL.  First URL should use first RenderViewHost.
807  const GURL url("http://www.google.com");
808  controller().LoadURL(
809      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
810  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
811  EXPECT_FALSE(contents()->cross_navigation_pending());
812  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
813
814  // Navigate to new site, but simulate an onbeforeunload denial.
815  const GURL url2("http://www.yahoo.com");
816  controller().LoadURL(
817      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
818  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
819  base::TimeTicks now = base::TimeTicks::Now();
820  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false, now, now));
821  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
822  EXPECT_FALSE(contents()->cross_navigation_pending());
823  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
824
825  // Navigate again, but simulate an onbeforeunload approval.
826  controller().LoadURL(
827      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
828  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
829  now = base::TimeTicks::Now();
830  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
831  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
832  EXPECT_TRUE(contents()->cross_navigation_pending());
833  TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
834      contents()->GetPendingRenderViewHost());
835
836  // We won't hear DidNavigate until the onunload handler has finished running.
837
838  // DidNavigate from the pending page.
839  contents()->TestDidNavigate(
840      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
841  SiteInstance* instance2 = contents()->GetSiteInstance();
842  EXPECT_FALSE(contents()->cross_navigation_pending());
843  EXPECT_EQ(pending_rvh, rvh());
844  EXPECT_NE(instance1, instance2);
845  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
846}
847
848// Test that during a slow cross-site navigation, the original renderer can
849// navigate to a different URL and have it displayed, canceling the slow
850// navigation.
851TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
852  contents()->transition_cross_site = true;
853  TestRenderViewHost* orig_rvh = test_rvh();
854  SiteInstance* instance1 = contents()->GetSiteInstance();
855
856  // Navigate to URL.  First URL should use first RenderViewHost.
857  const GURL url("http://www.google.com");
858  controller().LoadURL(
859      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
860  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
861  EXPECT_FALSE(contents()->cross_navigation_pending());
862  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
863
864  // Navigate to new site, simulating an onbeforeunload approval.
865  const GURL url2("http://www.yahoo.com");
866  controller().LoadURL(
867      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
868  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
869  base::TimeTicks now = base::TimeTicks::Now();
870  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
871  EXPECT_TRUE(contents()->cross_navigation_pending());
872
873  // Suppose the original renderer navigates before the new one is ready.
874  orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
875
876  // Verify that the pending navigation is cancelled.
877  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
878  SiteInstance* instance2 = contents()->GetSiteInstance();
879  EXPECT_FALSE(contents()->cross_navigation_pending());
880  EXPECT_EQ(orig_rvh, rvh());
881  EXPECT_EQ(instance1, instance2);
882  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
883}
884
885TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
886  contents()->transition_cross_site = true;
887
888  // Start with a web ui page, which gets a new RVH with WebUI bindings.
889  const GURL url1("chrome://blah");
890  controller().LoadURL(
891      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
892  TestRenderViewHost* ntp_rvh = test_rvh();
893  contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
894  NavigationEntry* entry1 = controller().GetLastCommittedEntry();
895  SiteInstance* instance1 = contents()->GetSiteInstance();
896
897  EXPECT_FALSE(contents()->cross_navigation_pending());
898  EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
899  EXPECT_EQ(url1, entry1->GetURL());
900  EXPECT_EQ(instance1,
901            NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
902  EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
903
904  // Navigate to new site.
905  const GURL url2("http://www.google.com");
906  controller().LoadURL(
907      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
908  EXPECT_TRUE(contents()->cross_navigation_pending());
909  TestRenderViewHost* google_rvh =
910      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
911
912  // Simulate beforeunload approval.
913  EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
914  base::TimeTicks now = base::TimeTicks::Now();
915  ntp_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
916
917  // DidNavigate from the pending page.
918  contents()->TestDidNavigate(
919      google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
920  NavigationEntry* entry2 = controller().GetLastCommittedEntry();
921  SiteInstance* instance2 = contents()->GetSiteInstance();
922
923  EXPECT_FALSE(contents()->cross_navigation_pending());
924  EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
925  EXPECT_NE(instance1, instance2);
926  EXPECT_FALSE(contents()->GetPendingRenderViewHost());
927  EXPECT_EQ(url2, entry2->GetURL());
928  EXPECT_EQ(instance2,
929            NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
930  EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
931
932  // Navigate to third page on same site.
933  const GURL url3("http://news.google.com");
934  controller().LoadURL(
935      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
936  EXPECT_FALSE(contents()->cross_navigation_pending());
937  contents()->TestDidNavigate(
938      google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
939  NavigationEntry* entry3 = controller().GetLastCommittedEntry();
940  SiteInstance* instance3 = contents()->GetSiteInstance();
941
942  EXPECT_FALSE(contents()->cross_navigation_pending());
943  EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
944  EXPECT_EQ(instance2, instance3);
945  EXPECT_FALSE(contents()->GetPendingRenderViewHost());
946  EXPECT_EQ(url3, entry3->GetURL());
947  EXPECT_EQ(instance3,
948            NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
949
950  // Go back within the site.
951  controller().GoBack();
952  EXPECT_FALSE(contents()->cross_navigation_pending());
953  EXPECT_EQ(entry2, controller().GetPendingEntry());
954
955  // Before that commits, go back again.
956  controller().GoBack();
957  EXPECT_TRUE(contents()->cross_navigation_pending());
958  EXPECT_TRUE(contents()->GetPendingRenderViewHost());
959  EXPECT_EQ(entry1, controller().GetPendingEntry());
960
961  // Simulate beforeunload approval.
962  EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
963  now = base::TimeTicks::Now();
964  google_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
965
966  // DidNavigate from the first back. This aborts the second back's pending RVH.
967  contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
968
969  // We should commit this page and forget about the second back.
970  EXPECT_FALSE(contents()->cross_navigation_pending());
971  EXPECT_FALSE(controller().GetPendingEntry());
972  EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
973  EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
974
975  // We should not have corrupted the NTP entry.
976  EXPECT_EQ(instance3,
977            NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
978  EXPECT_EQ(instance2,
979            NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
980  EXPECT_EQ(instance1,
981            NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
982  EXPECT_EQ(url1, entry1->GetURL());
983}
984
985// Test that during a slow cross-site navigation, a sub-frame navigation in the
986// original renderer will not cancel the slow navigation (bug 42029).
987TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
988  contents()->transition_cross_site = true;
989  TestRenderViewHost* orig_rvh = test_rvh();
990
991  // Navigate to URL.  First URL should use first RenderViewHost.
992  const GURL url("http://www.google.com");
993  controller().LoadURL(
994      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
995  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
996  EXPECT_FALSE(contents()->cross_navigation_pending());
997  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
998
999  // Start navigating to new site.
1000  const GURL url2("http://www.yahoo.com");
1001  controller().LoadURL(
1002      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1003
1004  // Simulate a sub-frame navigation arriving and ensure the RVH is still
1005  // waiting for a before unload response.
1006  orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1007                                       PAGE_TRANSITION_AUTO_SUBFRAME);
1008  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1009
1010  // Now simulate the onbeforeunload approval and verify the navigation is
1011  // not canceled.
1012  base::TimeTicks now = base::TimeTicks::Now();
1013  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1014  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1015  EXPECT_TRUE(contents()->cross_navigation_pending());
1016}
1017
1018// Test that a cross-site navigation is not preempted if the previous
1019// renderer sends a FrameNavigate message just before being told to stop.
1020// We should only preempt the cross-site navigation if the previous renderer
1021// has started a new navigation.  See http://crbug.com/79176.
1022TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1023  contents()->transition_cross_site = true;
1024
1025  // Navigate to NTP URL.
1026  const GURL url("chrome://blah");
1027  controller().LoadURL(
1028      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1029  TestRenderViewHost* orig_rvh = test_rvh();
1030  EXPECT_FALSE(contents()->cross_navigation_pending());
1031
1032  // Navigate to new site, with the beforeunload request in flight.
1033  const GURL url2("http://www.yahoo.com");
1034  controller().LoadURL(
1035      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1036  TestRenderViewHost* pending_rvh =
1037      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1038  EXPECT_TRUE(contents()->cross_navigation_pending());
1039  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1040
1041  // Suppose the first navigation tries to commit now, with a
1042  // ViewMsg_Stop in flight.  This should not cancel the pending navigation,
1043  // but it should act as if the beforeunload ack arrived.
1044  orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1045  EXPECT_TRUE(contents()->cross_navigation_pending());
1046  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1047  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1048
1049  // The pending navigation should be able to commit successfully.
1050  contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1051  EXPECT_FALSE(contents()->cross_navigation_pending());
1052  EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1053}
1054
1055// Test that the original renderer cannot preempt a cross-site navigation once
1056// the unload request has been made.  At this point, the cross-site navigation
1057// is almost ready to be displayed, and the original renderer is only given a
1058// short chance to run an unload handler.  Prevents regression of bug 23942.
1059TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1060  contents()->transition_cross_site = true;
1061  TestRenderViewHost* orig_rvh = test_rvh();
1062  SiteInstance* instance1 = contents()->GetSiteInstance();
1063
1064  // Navigate to URL.  First URL should use first RenderViewHost.
1065  const GURL url("http://www.google.com");
1066  controller().LoadURL(
1067      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1068  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1069  EXPECT_FALSE(contents()->cross_navigation_pending());
1070  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1071
1072  // Navigate to new site, simulating an onbeforeunload approval.
1073  const GURL url2("http://www.yahoo.com");
1074  controller().LoadURL(
1075      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1076  base::TimeTicks now = base::TimeTicks::Now();
1077  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1078  EXPECT_TRUE(contents()->cross_navigation_pending());
1079  TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1080      contents()->GetPendingRenderViewHost());
1081
1082  // Simulate the pending renderer's response, which leads to an unload request
1083  // being sent to orig_rvh.
1084  std::vector<GURL> url_chain;
1085  url_chain.push_back(GURL());
1086  contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1087      pending_rvh, GlobalRequestID(0, 0), false, url_chain, Referrer(),
1088      PAGE_TRANSITION_TYPED, 1, false);
1089
1090  // Suppose the original renderer navigates now, while the unload request is in
1091  // flight.  We should ignore it, wait for the unload ack, and let the pending
1092  // request continue.  Otherwise, the contents may close spontaneously or stop
1093  // responding to navigation requests.  (See bug 23942.)
1094  ViewHostMsg_FrameNavigate_Params params1a;
1095  InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
1096                     PAGE_TRANSITION_TYPED);
1097  orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1098
1099  // Verify that the pending navigation is still in progress.
1100  EXPECT_TRUE(contents()->cross_navigation_pending());
1101  EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1102
1103  // DidNavigate from the pending page should commit it.
1104  contents()->TestDidNavigate(
1105      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1106  SiteInstance* instance2 = contents()->GetSiteInstance();
1107  EXPECT_FALSE(contents()->cross_navigation_pending());
1108  EXPECT_EQ(pending_rvh, rvh());
1109  EXPECT_NE(instance1, instance2);
1110  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1111}
1112
1113// Test that a cross-site navigation that doesn't commit after the unload
1114// handler doesn't leave the contents in a stuck state.  http://crbug.com/88562
1115TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1116  contents()->transition_cross_site = true;
1117  TestRenderViewHost* orig_rvh = test_rvh();
1118  SiteInstance* instance1 = contents()->GetSiteInstance();
1119
1120  // Navigate to URL.  First URL should use first RenderViewHost.
1121  const GURL url("http://www.google.com");
1122  controller().LoadURL(
1123      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1124  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1125  EXPECT_FALSE(contents()->cross_navigation_pending());
1126  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1127
1128  // Navigate to new site, simulating an onbeforeunload approval.
1129  const GURL url2("http://www.yahoo.com");
1130  controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1131  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1132  base::TimeTicks now = base::TimeTicks::Now();
1133  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1134  EXPECT_TRUE(contents()->cross_navigation_pending());
1135
1136  // Simulate swap out message when the response arrives.
1137  orig_rvh->set_is_swapped_out(true);
1138
1139  // Suppose the navigation doesn't get a chance to commit, and the user
1140  // navigates in the current RVH's SiteInstance.
1141  controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1142
1143  // Verify that the pending navigation is cancelled and the renderer is no
1144  // longer swapped out.
1145  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1146  SiteInstance* instance2 = contents()->GetSiteInstance();
1147  EXPECT_FALSE(contents()->cross_navigation_pending());
1148  EXPECT_EQ(orig_rvh, rvh());
1149  EXPECT_FALSE(orig_rvh->is_swapped_out());
1150  EXPECT_EQ(instance1, instance2);
1151  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1152}
1153
1154// Test that NavigationEntries have the correct page state after going
1155// forward and back.  Prevents regression for bug 1116137.
1156TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1157  TestRenderViewHost* orig_rvh = test_rvh();
1158
1159  // Navigate to URL.  There should be no committed entry yet.
1160  const GURL url("http://www.google.com");
1161  controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1162  NavigationEntry* entry = controller().GetLastCommittedEntry();
1163  EXPECT_TRUE(entry == NULL);
1164
1165  // Committed entry should have page state after DidNavigate.
1166  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1167  entry = controller().GetLastCommittedEntry();
1168  EXPECT_TRUE(entry->GetPageState().IsValid());
1169
1170  // Navigate to same site.
1171  const GURL url2("http://images.google.com");
1172  controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1173  entry = controller().GetLastCommittedEntry();
1174  EXPECT_TRUE(entry->GetPageState().IsValid());
1175
1176  // Committed entry should have page state after DidNavigate.
1177  contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1178  entry = controller().GetLastCommittedEntry();
1179  EXPECT_TRUE(entry->GetPageState().IsValid());
1180
1181  // Now go back.  Committed entry should still have page state.
1182  controller().GoBack();
1183  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1184  entry = controller().GetLastCommittedEntry();
1185  EXPECT_TRUE(entry->GetPageState().IsValid());
1186}
1187
1188// Test that NavigationEntries have the correct page state and SiteInstance
1189// state after opening a new window to about:blank.  Prevents regression for
1190// bugs b/1116137 and http://crbug.com/111975.
1191TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1192  TestRenderViewHost* orig_rvh = test_rvh();
1193
1194  // When opening a new window, it is navigated to about:blank internally.
1195  // Currently, this results in two DidNavigate events.
1196  const GURL url(kAboutBlankURL);
1197  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1198  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1199
1200  // Should have a page state here.
1201  NavigationEntry* entry = controller().GetLastCommittedEntry();
1202  EXPECT_TRUE(entry->GetPageState().IsValid());
1203
1204  // The SiteInstance should be available for other navigations to use.
1205  NavigationEntryImpl* entry_impl =
1206      NavigationEntryImpl::FromNavigationEntry(entry);
1207  EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1208  int32 site_instance_id = entry_impl->site_instance()->GetId();
1209
1210  // Navigating to a normal page should not cause a process swap.
1211  const GURL new_url("http://www.google.com");
1212  controller().LoadURL(new_url, Referrer(),
1213                       PAGE_TRANSITION_TYPED, std::string());
1214  EXPECT_FALSE(contents()->cross_navigation_pending());
1215  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1216  contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1217  NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1218      controller().GetLastCommittedEntry());
1219  EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1220  EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1221}
1222
1223////////////////////////////////////////////////////////////////////////////////
1224// Interstitial Tests
1225////////////////////////////////////////////////////////////////////////////////
1226
1227// Test navigating to a page (with the navigation initiated from the browser,
1228// as when a URL is typed in the location bar) that shows an interstitial and
1229// creates a new navigation entry, then hiding it without proceeding.
1230TEST_F(WebContentsImplTest,
1231       ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1232  // Navigate to a page.
1233  GURL url1("http://www.google.com");
1234  test_rvh()->SendNavigate(1, url1);
1235  EXPECT_EQ(1, controller().GetEntryCount());
1236
1237  // Initiate a browser navigation that will trigger the interstitial
1238  controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1239                        PAGE_TRANSITION_TYPED, std::string());
1240
1241  // Show an interstitial.
1242  TestInterstitialPage::InterstitialState state =
1243      TestInterstitialPage::INVALID;
1244  bool deleted = false;
1245  GURL url2("http://interstitial");
1246  TestInterstitialPage* interstitial =
1247      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1248  TestInterstitialPageStateGuard state_guard(interstitial);
1249  interstitial->Show();
1250  // The interstitial should not show until its navigation has committed.
1251  EXPECT_FALSE(interstitial->is_showing());
1252  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1253  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1254  // Let's commit the interstitial navigation.
1255  interstitial->TestDidNavigate(1, url2);
1256  EXPECT_TRUE(interstitial->is_showing());
1257  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1258  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1259  NavigationEntry* entry = controller().GetVisibleEntry();
1260  ASSERT_TRUE(entry != NULL);
1261  EXPECT_TRUE(entry->GetURL() == url2);
1262
1263  // Now don't proceed.
1264  interstitial->DontProceed();
1265  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1266  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1267  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1268  entry = controller().GetVisibleEntry();
1269  ASSERT_TRUE(entry != NULL);
1270  EXPECT_TRUE(entry->GetURL() == url1);
1271  EXPECT_EQ(1, controller().GetEntryCount());
1272
1273  RunAllPendingInMessageLoop();
1274  EXPECT_TRUE(deleted);
1275}
1276
1277// Test navigating to a page (with the navigation initiated from the renderer,
1278// as when clicking on a link in the page) that shows an interstitial and
1279// creates a new navigation entry, then hiding it without proceeding.
1280TEST_F(WebContentsImplTest,
1281       ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1282  // Navigate to a page.
1283  GURL url1("http://www.google.com");
1284  test_rvh()->SendNavigate(1, url1);
1285  EXPECT_EQ(1, controller().GetEntryCount());
1286
1287  // Show an interstitial (no pending entry, the interstitial would have been
1288  // triggered by clicking on a link).
1289  TestInterstitialPage::InterstitialState state =
1290      TestInterstitialPage::INVALID;
1291  bool deleted = false;
1292  GURL url2("http://interstitial");
1293  TestInterstitialPage* interstitial =
1294      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1295  TestInterstitialPageStateGuard state_guard(interstitial);
1296  interstitial->Show();
1297  // The interstitial should not show until its navigation has committed.
1298  EXPECT_FALSE(interstitial->is_showing());
1299  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1300  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1301  // Let's commit the interstitial navigation.
1302  interstitial->TestDidNavigate(1, url2);
1303  EXPECT_TRUE(interstitial->is_showing());
1304  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1305  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1306  NavigationEntry* entry = controller().GetVisibleEntry();
1307  ASSERT_TRUE(entry != NULL);
1308  EXPECT_TRUE(entry->GetURL() == url2);
1309
1310  // Now don't proceed.
1311  interstitial->DontProceed();
1312  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1313  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1314  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1315  entry = controller().GetVisibleEntry();
1316  ASSERT_TRUE(entry != NULL);
1317  EXPECT_TRUE(entry->GetURL() == url1);
1318  EXPECT_EQ(1, controller().GetEntryCount());
1319
1320  RunAllPendingInMessageLoop();
1321  EXPECT_TRUE(deleted);
1322}
1323
1324// Test navigating to a page that shows an interstitial without creating a new
1325// navigation entry (this happens when the interstitial is triggered by a
1326// sub-resource in the page), then hiding it without proceeding.
1327TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1328  // Navigate to a page.
1329  GURL url1("http://www.google.com");
1330  test_rvh()->SendNavigate(1, url1);
1331  EXPECT_EQ(1, controller().GetEntryCount());
1332
1333  // Show an interstitial.
1334  TestInterstitialPage::InterstitialState state =
1335      TestInterstitialPage::INVALID;
1336  bool deleted = false;
1337  GURL url2("http://interstitial");
1338  TestInterstitialPage* interstitial =
1339      new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1340  TestInterstitialPageStateGuard state_guard(interstitial);
1341  interstitial->Show();
1342  // The interstitial should not show until its navigation has committed.
1343  EXPECT_FALSE(interstitial->is_showing());
1344  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1345  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1346  // Let's commit the interstitial navigation.
1347  interstitial->TestDidNavigate(1, url2);
1348  EXPECT_TRUE(interstitial->is_showing());
1349  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1350  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1351  NavigationEntry* entry = controller().GetVisibleEntry();
1352  ASSERT_TRUE(entry != NULL);
1353  // The URL specified to the interstitial should have been ignored.
1354  EXPECT_TRUE(entry->GetURL() == url1);
1355
1356  // Now don't proceed.
1357  interstitial->DontProceed();
1358  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1359  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1360  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1361  entry = controller().GetVisibleEntry();
1362  ASSERT_TRUE(entry != NULL);
1363  EXPECT_TRUE(entry->GetURL() == url1);
1364  EXPECT_EQ(1, controller().GetEntryCount());
1365
1366  RunAllPendingInMessageLoop();
1367  EXPECT_TRUE(deleted);
1368}
1369
1370// Test navigating to a page (with the navigation initiated from the browser,
1371// as when a URL is typed in the location bar) that shows an interstitial and
1372// creates a new navigation entry, then proceeding.
1373TEST_F(WebContentsImplTest,
1374       ShowInterstitialFromBrowserNewNavigationProceed) {
1375  // Navigate to a page.
1376  GURL url1("http://www.google.com");
1377  test_rvh()->SendNavigate(1, url1);
1378  EXPECT_EQ(1, controller().GetEntryCount());
1379
1380  // Initiate a browser navigation that will trigger the interstitial
1381  controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1382                        PAGE_TRANSITION_TYPED, std::string());
1383
1384  // Show an interstitial.
1385  TestInterstitialPage::InterstitialState state =
1386      TestInterstitialPage::INVALID;
1387  bool deleted = false;
1388  GURL url2("http://interstitial");
1389  TestInterstitialPage* interstitial =
1390      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1391  TestInterstitialPageStateGuard state_guard(interstitial);
1392  interstitial->Show();
1393  // The interstitial should not show until its navigation has committed.
1394  EXPECT_FALSE(interstitial->is_showing());
1395  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1396  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1397  // Let's commit the interstitial navigation.
1398  interstitial->TestDidNavigate(1, url2);
1399  EXPECT_TRUE(interstitial->is_showing());
1400  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1401  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1402  NavigationEntry* entry = controller().GetVisibleEntry();
1403  ASSERT_TRUE(entry != NULL);
1404  EXPECT_TRUE(entry->GetURL() == url2);
1405
1406  // Then proceed.
1407  interstitial->Proceed();
1408  // The interstitial should show until the new navigation commits.
1409  RunAllPendingInMessageLoop();
1410  ASSERT_FALSE(deleted);
1411  EXPECT_EQ(TestInterstitialPage::OKED, state);
1412  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1413  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1414
1415  // Simulate the navigation to the page, that's when the interstitial gets
1416  // hidden.
1417  GURL url3("http://www.thepage.com");
1418  test_rvh()->SendNavigate(2, url3);
1419
1420  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1421  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1422  entry = controller().GetVisibleEntry();
1423  ASSERT_TRUE(entry != NULL);
1424  EXPECT_TRUE(entry->GetURL() == url3);
1425
1426  EXPECT_EQ(2, controller().GetEntryCount());
1427
1428  RunAllPendingInMessageLoop();
1429  EXPECT_TRUE(deleted);
1430}
1431
1432// Test navigating to a page (with the navigation initiated from the renderer,
1433// as when clicking on a link in the page) that shows an interstitial and
1434// creates a new navigation entry, then proceeding.
1435TEST_F(WebContentsImplTest,
1436       ShowInterstitialFromRendererNewNavigationProceed) {
1437  // Navigate to a page.
1438  GURL url1("http://www.google.com");
1439  test_rvh()->SendNavigate(1, url1);
1440  EXPECT_EQ(1, controller().GetEntryCount());
1441
1442  // Show an interstitial.
1443  TestInterstitialPage::InterstitialState state =
1444      TestInterstitialPage::INVALID;
1445  bool deleted = false;
1446  GURL url2("http://interstitial");
1447  TestInterstitialPage* interstitial =
1448      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1449  TestInterstitialPageStateGuard state_guard(interstitial);
1450  interstitial->Show();
1451  // The interstitial should not show until its navigation has committed.
1452  EXPECT_FALSE(interstitial->is_showing());
1453  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1454  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1455  // Let's commit the interstitial navigation.
1456  interstitial->TestDidNavigate(1, url2);
1457  EXPECT_TRUE(interstitial->is_showing());
1458  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1459  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1460  NavigationEntry* entry = controller().GetVisibleEntry();
1461  ASSERT_TRUE(entry != NULL);
1462  EXPECT_TRUE(entry->GetURL() == url2);
1463
1464  // Then proceed.
1465  interstitial->Proceed();
1466  // The interstitial should show until the new navigation commits.
1467  RunAllPendingInMessageLoop();
1468  ASSERT_FALSE(deleted);
1469  EXPECT_EQ(TestInterstitialPage::OKED, state);
1470  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1471  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1472
1473  // Simulate the navigation to the page, that's when the interstitial gets
1474  // hidden.
1475  GURL url3("http://www.thepage.com");
1476  test_rvh()->SendNavigate(2, url3);
1477
1478  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1479  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1480  entry = controller().GetVisibleEntry();
1481  ASSERT_TRUE(entry != NULL);
1482  EXPECT_TRUE(entry->GetURL() == url3);
1483
1484  EXPECT_EQ(2, controller().GetEntryCount());
1485
1486  RunAllPendingInMessageLoop();
1487  EXPECT_TRUE(deleted);
1488}
1489
1490// Test navigating to a page that shows an interstitial without creating a new
1491// navigation entry (this happens when the interstitial is triggered by a
1492// sub-resource in the page), then proceeding.
1493TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1494  // Navigate to a page so we have a navigation entry in the controller.
1495  GURL url1("http://www.google.com");
1496  test_rvh()->SendNavigate(1, url1);
1497  EXPECT_EQ(1, controller().GetEntryCount());
1498
1499  // Show an interstitial.
1500  TestInterstitialPage::InterstitialState state =
1501      TestInterstitialPage::INVALID;
1502  bool deleted = false;
1503  GURL url2("http://interstitial");
1504  TestInterstitialPage* interstitial =
1505      new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1506  TestInterstitialPageStateGuard state_guard(interstitial);
1507  interstitial->Show();
1508  // The interstitial should not show until its navigation has committed.
1509  EXPECT_FALSE(interstitial->is_showing());
1510  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1511  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1512  // Let's commit the interstitial navigation.
1513  interstitial->TestDidNavigate(1, url2);
1514  EXPECT_TRUE(interstitial->is_showing());
1515  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1516  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1517  NavigationEntry* entry = controller().GetVisibleEntry();
1518  ASSERT_TRUE(entry != NULL);
1519  // The URL specified to the interstitial should have been ignored.
1520  EXPECT_TRUE(entry->GetURL() == url1);
1521
1522  // Then proceed.
1523  interstitial->Proceed();
1524  // Since this is not a new navigation, the previous page is dismissed right
1525  // away and shows the original page.
1526  EXPECT_EQ(TestInterstitialPage::OKED, state);
1527  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1528  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1529  entry = controller().GetVisibleEntry();
1530  ASSERT_TRUE(entry != NULL);
1531  EXPECT_TRUE(entry->GetURL() == url1);
1532
1533  EXPECT_EQ(1, controller().GetEntryCount());
1534
1535  RunAllPendingInMessageLoop();
1536  EXPECT_TRUE(deleted);
1537}
1538
1539// Test navigating to a page that shows an interstitial, then navigating away.
1540TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1541  // Show interstitial.
1542  TestInterstitialPage::InterstitialState state =
1543      TestInterstitialPage::INVALID;
1544  bool deleted = false;
1545  GURL url("http://interstitial");
1546  TestInterstitialPage* interstitial =
1547      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1548  TestInterstitialPageStateGuard state_guard(interstitial);
1549  interstitial->Show();
1550  interstitial->TestDidNavigate(1, url);
1551
1552  // While interstitial showing, navigate to a new URL.
1553  const GURL url2("http://www.yahoo.com");
1554  test_rvh()->SendNavigate(1, url2);
1555
1556  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1557
1558  RunAllPendingInMessageLoop();
1559  EXPECT_TRUE(deleted);
1560}
1561
1562// Test navigating to a page that shows an interstitial, then going back.
1563TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1564  // Navigate to a page so we have a navigation entry in the controller.
1565  GURL url1("http://www.google.com");
1566  test_rvh()->SendNavigate(1, url1);
1567  EXPECT_EQ(1, controller().GetEntryCount());
1568
1569  // Show interstitial.
1570  TestInterstitialPage::InterstitialState state =
1571      TestInterstitialPage::INVALID;
1572  bool deleted = false;
1573  GURL interstitial_url("http://interstitial");
1574  TestInterstitialPage* interstitial =
1575      new TestInterstitialPage(contents(), true, interstitial_url,
1576                               &state, &deleted);
1577  TestInterstitialPageStateGuard state_guard(interstitial);
1578  interstitial->Show();
1579  interstitial->TestDidNavigate(2, interstitial_url);
1580
1581  // While the interstitial is showing, go back.
1582  controller().GoBack();
1583  test_rvh()->SendNavigate(1, url1);
1584
1585  // Make sure we are back to the original page and that the interstitial is
1586  // gone.
1587  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1588  NavigationEntry* entry = controller().GetVisibleEntry();
1589  ASSERT_TRUE(entry);
1590  EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1591
1592  RunAllPendingInMessageLoop();
1593  EXPECT_TRUE(deleted);
1594}
1595
1596// Test navigating to a page that shows an interstitial, has a renderer crash,
1597// and then goes back.
1598TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1599  // Navigate to a page so we have a navigation entry in the controller.
1600  GURL url1("http://www.google.com");
1601  test_rvh()->SendNavigate(1, url1);
1602  EXPECT_EQ(1, controller().GetEntryCount());
1603
1604  // Show interstitial.
1605  TestInterstitialPage::InterstitialState state =
1606      TestInterstitialPage::INVALID;
1607  bool deleted = false;
1608  GURL interstitial_url("http://interstitial");
1609  TestInterstitialPage* interstitial =
1610      new TestInterstitialPage(contents(), true, interstitial_url,
1611                               &state, &deleted);
1612  TestInterstitialPageStateGuard state_guard(interstitial);
1613  interstitial->Show();
1614  interstitial->TestDidNavigate(2, interstitial_url);
1615
1616  // Crash the renderer
1617  test_rvh()->OnMessageReceived(
1618      ViewHostMsg_RenderProcessGone(
1619          0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1620
1621  // While the interstitial is showing, go back.
1622  controller().GoBack();
1623  test_rvh()->SendNavigate(1, url1);
1624
1625  // Make sure we are back to the original page and that the interstitial is
1626  // gone.
1627  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1628  NavigationEntry* entry = controller().GetVisibleEntry();
1629  ASSERT_TRUE(entry);
1630  EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1631
1632  RunAllPendingInMessageLoop();
1633  EXPECT_TRUE(deleted);
1634}
1635
1636// Test navigating to a page that shows an interstitial, has the renderer crash,
1637// and then navigates to the interstitial.
1638TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1639  // Navigate to a page so we have a navigation entry in the controller.
1640  GURL url1("http://www.google.com");
1641  test_rvh()->SendNavigate(1, url1);
1642  EXPECT_EQ(1, controller().GetEntryCount());
1643
1644  // Show interstitial.
1645  TestInterstitialPage::InterstitialState state =
1646      TestInterstitialPage::INVALID;
1647  bool deleted = false;
1648  GURL interstitial_url("http://interstitial");
1649  TestInterstitialPage* interstitial =
1650      new TestInterstitialPage(contents(), true, interstitial_url,
1651                               &state, &deleted);
1652  TestInterstitialPageStateGuard state_guard(interstitial);
1653  interstitial->Show();
1654
1655  // Crash the renderer
1656  test_rvh()->OnMessageReceived(
1657      ViewHostMsg_RenderProcessGone(
1658          0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1659
1660  interstitial->TestDidNavigate(2, interstitial_url);
1661}
1662
1663// Test navigating to a page that shows an interstitial, then close the
1664// contents.
1665TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1666  // Show interstitial.
1667  TestInterstitialPage::InterstitialState state =
1668      TestInterstitialPage::INVALID;
1669  bool deleted = false;
1670  GURL url("http://interstitial");
1671  TestInterstitialPage* interstitial =
1672      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1673  TestInterstitialPageStateGuard state_guard(interstitial);
1674  interstitial->Show();
1675  interstitial->TestDidNavigate(1, url);
1676
1677  // Now close the contents.
1678  DeleteContents();
1679  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1680
1681  RunAllPendingInMessageLoop();
1682  EXPECT_TRUE(deleted);
1683}
1684
1685// Test navigating to a page that shows an interstitial, then close the
1686// contents.
1687TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1688  // Show interstitial.
1689  TestInterstitialPage::InterstitialState state =
1690      TestInterstitialPage::INVALID;
1691  bool deleted = false;
1692  GURL url("http://interstitial");
1693  TestInterstitialPage* interstitial =
1694      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1695  TestInterstitialPageStateGuard state_guard(interstitial);
1696  interstitial->Show();
1697  interstitial->TestDidNavigate(1, url);
1698  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1699      interstitial->GetRenderViewHostForTesting());
1700
1701  // Now close the contents.
1702  DeleteContents();
1703  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1704
1705  // Before the interstitial has a chance to process its shutdown task,
1706  // simulate quitting the browser.  This goes through all processes and
1707  // tells them to destruct.
1708  rvh->OnMessageReceived(
1709        ViewHostMsg_RenderProcessGone(0, 0, 0));
1710
1711  RunAllPendingInMessageLoop();
1712  EXPECT_TRUE(deleted);
1713}
1714
1715// Test that after Proceed is called and an interstitial is still shown, no more
1716// commands get executed.
1717TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1718  // Navigate to a page so we have a navigation entry in the controller.
1719  GURL url1("http://www.google.com");
1720  test_rvh()->SendNavigate(1, url1);
1721  EXPECT_EQ(1, controller().GetEntryCount());
1722
1723  // Show an interstitial.
1724  TestInterstitialPage::InterstitialState state =
1725      TestInterstitialPage::INVALID;
1726  bool deleted = false;
1727  GURL url2("http://interstitial");
1728  TestInterstitialPage* interstitial =
1729      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1730  TestInterstitialPageStateGuard state_guard(interstitial);
1731  interstitial->Show();
1732  interstitial->TestDidNavigate(1, url2);
1733
1734  // Run a command.
1735  EXPECT_EQ(0, interstitial->command_received_count());
1736  interstitial->TestDomOperationResponse("toto");
1737  EXPECT_EQ(1, interstitial->command_received_count());
1738
1739  // Then proceed.
1740  interstitial->Proceed();
1741  RunAllPendingInMessageLoop();
1742  ASSERT_FALSE(deleted);
1743
1744  // While the navigation to the new page is pending, send other commands, they
1745  // should be ignored.
1746  interstitial->TestDomOperationResponse("hello");
1747  interstitial->TestDomOperationResponse("hi");
1748  EXPECT_EQ(1, interstitial->command_received_count());
1749}
1750
1751// Test showing an interstitial while another interstitial is already showing.
1752TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1753  // Navigate to a page so we have a navigation entry in the controller.
1754  GURL start_url("http://www.google.com");
1755  test_rvh()->SendNavigate(1, start_url);
1756  EXPECT_EQ(1, controller().GetEntryCount());
1757
1758  // Show an interstitial.
1759  TestInterstitialPage::InterstitialState state1 =
1760      TestInterstitialPage::INVALID;
1761  bool deleted1 = false;
1762  GURL url1("http://interstitial1");
1763  TestInterstitialPage* interstitial1 =
1764      new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1765  TestInterstitialPageStateGuard state_guard1(interstitial1);
1766  interstitial1->Show();
1767  interstitial1->TestDidNavigate(1, url1);
1768
1769  // Now show another interstitial.
1770  TestInterstitialPage::InterstitialState state2 =
1771      TestInterstitialPage::INVALID;
1772  bool deleted2 = false;
1773  GURL url2("http://interstitial2");
1774  TestInterstitialPage* interstitial2 =
1775      new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1776  TestInterstitialPageStateGuard state_guard2(interstitial2);
1777  interstitial2->Show();
1778  interstitial2->TestDidNavigate(1, url2);
1779
1780  // Showing interstitial2 should have caused interstitial1 to go away.
1781  EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1782  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1783
1784  RunAllPendingInMessageLoop();
1785  EXPECT_TRUE(deleted1);
1786  ASSERT_FALSE(deleted2);
1787
1788  // Let's make sure interstitial2 is working as intended.
1789  interstitial2->Proceed();
1790  GURL landing_url("http://www.thepage.com");
1791  test_rvh()->SendNavigate(2, landing_url);
1792
1793  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1794  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1795  NavigationEntry* entry = controller().GetVisibleEntry();
1796  ASSERT_TRUE(entry != NULL);
1797  EXPECT_TRUE(entry->GetURL() == landing_url);
1798  EXPECT_EQ(2, controller().GetEntryCount());
1799  RunAllPendingInMessageLoop();
1800  EXPECT_TRUE(deleted2);
1801}
1802
1803// Test showing an interstitial, proceeding and then navigating to another
1804// interstitial.
1805TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1806  // Navigate to a page so we have a navigation entry in the controller.
1807  GURL start_url("http://www.google.com");
1808  test_rvh()->SendNavigate(1, start_url);
1809  EXPECT_EQ(1, controller().GetEntryCount());
1810
1811  // Show an interstitial.
1812  TestInterstitialPage::InterstitialState state1 =
1813      TestInterstitialPage::INVALID;
1814  bool deleted1 = false;
1815  GURL url1("http://interstitial1");
1816  TestInterstitialPage* interstitial1 =
1817      new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1818  TestInterstitialPageStateGuard state_guard1(interstitial1);
1819  interstitial1->Show();
1820  interstitial1->TestDidNavigate(1, url1);
1821
1822  // Take action.  The interstitial won't be hidden until the navigation is
1823  // committed.
1824  interstitial1->Proceed();
1825  EXPECT_EQ(TestInterstitialPage::OKED, state1);
1826
1827  // Now show another interstitial (simulating the navigation causing another
1828  // interstitial).
1829  TestInterstitialPage::InterstitialState state2 =
1830      TestInterstitialPage::INVALID;
1831  bool deleted2 = false;
1832  GURL url2("http://interstitial2");
1833  TestInterstitialPage* interstitial2 =
1834      new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1835  TestInterstitialPageStateGuard state_guard2(interstitial2);
1836  interstitial2->Show();
1837  interstitial2->TestDidNavigate(1, url2);
1838
1839  // Showing interstitial2 should have caused interstitial1 to go away.
1840  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1841  RunAllPendingInMessageLoop();
1842  EXPECT_TRUE(deleted1);
1843  ASSERT_FALSE(deleted2);
1844
1845  // Let's make sure interstitial2 is working as intended.
1846  interstitial2->Proceed();
1847  GURL landing_url("http://www.thepage.com");
1848  test_rvh()->SendNavigate(2, landing_url);
1849
1850  RunAllPendingInMessageLoop();
1851  EXPECT_TRUE(deleted2);
1852  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1853  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1854  NavigationEntry* entry = controller().GetVisibleEntry();
1855  ASSERT_TRUE(entry != NULL);
1856  EXPECT_TRUE(entry->GetURL() == landing_url);
1857  EXPECT_EQ(2, controller().GetEntryCount());
1858}
1859
1860// Test that navigating away from an interstitial while it's loading cause it
1861// not to show.
1862TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
1863  // Show an interstitial.
1864  TestInterstitialPage::InterstitialState state =
1865      TestInterstitialPage::INVALID;
1866  bool deleted = false;
1867  GURL interstitial_url("http://interstitial");
1868  TestInterstitialPage* interstitial =
1869      new TestInterstitialPage(contents(), true, interstitial_url,
1870                               &state, &deleted);
1871  TestInterstitialPageStateGuard state_guard(interstitial);
1872  interstitial->Show();
1873
1874  // Let's simulate a navigation initiated from the browser before the
1875  // interstitial finishes loading.
1876  const GURL url("http://www.google.com");
1877  controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1878  EXPECT_FALSE(interstitial->is_showing());
1879  RunAllPendingInMessageLoop();
1880  ASSERT_FALSE(deleted);
1881
1882  // Now let's make the interstitial navigation commit.
1883  interstitial->TestDidNavigate(1, interstitial_url);
1884
1885  // After it loaded the interstitial should be gone.
1886  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1887
1888  RunAllPendingInMessageLoop();
1889  EXPECT_TRUE(deleted);
1890}
1891
1892// Test that a new request to show an interstitial while an interstitial is
1893// pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
1894TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
1895  GURL interstitial_url("http://interstitial");
1896
1897  // Show a first interstitial.
1898  TestInterstitialPage::InterstitialState state1 =
1899      TestInterstitialPage::INVALID;
1900  bool deleted1 = false;
1901  TestInterstitialPage* interstitial1 =
1902      new TestInterstitialPage(contents(), true, interstitial_url,
1903                               &state1, &deleted1);
1904  TestInterstitialPageStateGuard state_guard1(interstitial1);
1905  interstitial1->Show();
1906
1907  // Show another interstitial on that same contents before the first one had
1908  // time to load.
1909  TestInterstitialPage::InterstitialState state2 =
1910      TestInterstitialPage::INVALID;
1911  bool deleted2 = false;
1912  TestInterstitialPage* interstitial2 =
1913      new TestInterstitialPage(contents(), true, interstitial_url,
1914                               &state2, &deleted2);
1915  TestInterstitialPageStateGuard state_guard2(interstitial2);
1916  interstitial2->Show();
1917
1918  // The first interstitial should have been closed and deleted.
1919  EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1920  // The 2nd one should still be OK.
1921  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1922
1923  RunAllPendingInMessageLoop();
1924  EXPECT_TRUE(deleted1);
1925  ASSERT_FALSE(deleted2);
1926
1927  // Make the interstitial navigation commit it should be showing.
1928  interstitial2->TestDidNavigate(1, interstitial_url);
1929  EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
1930}
1931
1932// Test showing an interstitial and have its renderer crash.
1933TEST_F(WebContentsImplTest, InterstitialCrasher) {
1934  // Show an interstitial.
1935  TestInterstitialPage::InterstitialState state =
1936      TestInterstitialPage::INVALID;
1937  bool deleted = false;
1938  GURL url("http://interstitial");
1939  TestInterstitialPage* interstitial =
1940      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1941  TestInterstitialPageStateGuard state_guard(interstitial);
1942  interstitial->Show();
1943  // Simulate a renderer crash before the interstitial is shown.
1944  interstitial->TestRenderViewTerminated(
1945      base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1946  // The interstitial should have been dismissed.
1947  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1948  RunAllPendingInMessageLoop();
1949  EXPECT_TRUE(deleted);
1950
1951  // Now try again but this time crash the intersitial after it was shown.
1952  interstitial =
1953      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1954  interstitial->Show();
1955  interstitial->TestDidNavigate(1, url);
1956  // Simulate a renderer crash.
1957  interstitial->TestRenderViewTerminated(
1958      base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1959  // The interstitial should have been dismissed.
1960  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1961  RunAllPendingInMessageLoop();
1962  EXPECT_TRUE(deleted);
1963}
1964
1965// Tests that showing an interstitial as a result of a browser initiated
1966// navigation while an interstitial is showing does not remove the pending
1967// entry (see http://crbug.com/9791).
1968TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
1969  const char kUrl[] = "http://www.badguys.com/";
1970  const GURL kGURL(kUrl);
1971
1972  // Start a navigation to a page
1973  contents()->GetController().LoadURL(
1974      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1975
1976  // Simulate that navigation triggering an interstitial.
1977  TestInterstitialPage::InterstitialState state =
1978      TestInterstitialPage::INVALID;
1979  bool deleted = false;
1980  TestInterstitialPage* interstitial =
1981      new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
1982  TestInterstitialPageStateGuard state_guard(interstitial);
1983  interstitial->Show();
1984  interstitial->TestDidNavigate(1, kGURL);
1985
1986  // Initiate a new navigation from the browser that also triggers an
1987  // interstitial.
1988  contents()->GetController().LoadURL(
1989      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1990  TestInterstitialPage::InterstitialState state2 =
1991      TestInterstitialPage::INVALID;
1992  bool deleted2 = false;
1993  TestInterstitialPage* interstitial2 =
1994      new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
1995  TestInterstitialPageStateGuard state_guard2(interstitial2);
1996  interstitial2->Show();
1997  interstitial2->TestDidNavigate(1, kGURL);
1998
1999  // Make sure we still have an entry.
2000  NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2001  ASSERT_TRUE(entry);
2002  EXPECT_EQ(kUrl, entry->GetURL().spec());
2003
2004  // And that the first interstitial is gone, but not the second.
2005  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2006  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2007  RunAllPendingInMessageLoop();
2008  EXPECT_TRUE(deleted);
2009  EXPECT_FALSE(deleted2);
2010}
2011
2012// Tests that Javascript messages are not shown while an interstitial is
2013// showing.
2014TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2015  const char kUrl[] = "http://www.badguys.com/";
2016  const GURL kGURL(kUrl);
2017
2018  // Start a navigation to a page
2019  contents()->GetController().LoadURL(
2020      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2021  // DidNavigate from the page
2022  contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2023
2024  // Simulate showing an interstitial while the page is showing.
2025  TestInterstitialPage::InterstitialState state =
2026      TestInterstitialPage::INVALID;
2027  bool deleted = false;
2028  TestInterstitialPage* interstitial =
2029      new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2030  TestInterstitialPageStateGuard state_guard(interstitial);
2031  interstitial->Show();
2032  interstitial->TestDidNavigate(1, kGURL);
2033
2034  // While the interstitial is showing, let's simulate the hidden page
2035  // attempting to show a JS message.
2036  IPC::Message* dummy_message = new IPC::Message;
2037  bool did_suppress_message = false;
2038  contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
2039      ASCIIToUTF16("This is an informative message"), ASCIIToUTF16("OK"),
2040      kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
2041      &did_suppress_message);
2042  EXPECT_TRUE(did_suppress_message);
2043}
2044
2045// Makes sure that if the source passed to CopyStateFromAndPrune has an
2046// interstitial it isn't copied over to the destination.
2047TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2048  // Navigate to a page.
2049  GURL url1("http://www.google.com");
2050  test_rvh()->SendNavigate(1, url1);
2051  EXPECT_EQ(1, controller().GetEntryCount());
2052
2053  // Initiate a browser navigation that will trigger the interstitial
2054  controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2055                        PAGE_TRANSITION_TYPED, std::string());
2056
2057  // Show an interstitial.
2058  TestInterstitialPage::InterstitialState state =
2059      TestInterstitialPage::INVALID;
2060  bool deleted = false;
2061  GURL url2("http://interstitial");
2062  TestInterstitialPage* interstitial =
2063      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2064  TestInterstitialPageStateGuard state_guard(interstitial);
2065  interstitial->Show();
2066  interstitial->TestDidNavigate(1, url2);
2067  EXPECT_TRUE(interstitial->is_showing());
2068  EXPECT_EQ(2, controller().GetEntryCount());
2069
2070  // Create another NavigationController.
2071  GURL url3("http://foo2");
2072  scoped_ptr<TestWebContents> other_contents(
2073      static_cast<TestWebContents*>(CreateTestWebContents()));
2074  NavigationControllerImpl& other_controller = other_contents->GetController();
2075  other_contents->NavigateAndCommit(url3);
2076  other_contents->ExpectSetHistoryLengthAndPrune(
2077      NavigationEntryImpl::FromNavigationEntry(
2078          other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2079      other_controller.GetEntryAtIndex(0)->GetPageID());
2080  other_controller.CopyStateFromAndPrune(&controller());
2081
2082  // The merged controller should only have two entries: url1 and url2.
2083  ASSERT_EQ(2, other_controller.GetEntryCount());
2084  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2085  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2086  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2087
2088  // And the merged controller shouldn't be showing an interstitial.
2089  EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2090}
2091
2092// Makes sure that CopyStateFromAndPrune cannot be called if the target is
2093// showing an interstitial.
2094TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2095  // Navigate to a page.
2096  GURL url1("http://www.google.com");
2097  contents()->NavigateAndCommit(url1);
2098
2099  // Create another NavigationController.
2100  scoped_ptr<TestWebContents> other_contents(
2101      static_cast<TestWebContents*>(CreateTestWebContents()));
2102  NavigationControllerImpl& other_controller = other_contents->GetController();
2103
2104  // Navigate it to url2.
2105  GURL url2("http://foo2");
2106  other_contents->NavigateAndCommit(url2);
2107
2108  // Show an interstitial.
2109  TestInterstitialPage::InterstitialState state =
2110      TestInterstitialPage::INVALID;
2111  bool deleted = false;
2112  GURL url3("http://interstitial");
2113  TestInterstitialPage* interstitial =
2114      new TestInterstitialPage(other_contents.get(), true, url3, &state,
2115                               &deleted);
2116  TestInterstitialPageStateGuard state_guard(interstitial);
2117  interstitial->Show();
2118  interstitial->TestDidNavigate(1, url3);
2119  EXPECT_TRUE(interstitial->is_showing());
2120  EXPECT_EQ(2, other_controller.GetEntryCount());
2121
2122  // Ensure that we do not allow calling CopyStateFromAndPrune when an
2123  // interstitial is showing in the target.
2124  EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2125}
2126
2127// Regression test for http://crbug.com/168611 - the URLs passed by the
2128// DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2129TEST_F(WebContentsImplTest, FilterURLs) {
2130  TestWebContentsObserver observer(contents());
2131
2132  // A navigation to about:whatever should always look like a navigation to
2133  // about:blank
2134  GURL url_normalized(kAboutBlankURL);
2135  GURL url_from_ipc("about:whatever");
2136
2137  // We navigate the test WebContents to about:blank, since NavigateAndCommit
2138  // will use the given URL to create the NavigationEntry as well, and that
2139  // entry should contain the filtered URL.
2140  contents()->NavigateAndCommit(url_normalized);
2141
2142  // Check that an IPC with about:whatever is correctly normalized.
2143  contents()->TestDidFinishLoad(1, url_from_ipc, true);
2144
2145  EXPECT_EQ(url_normalized, observer.last_url());
2146
2147  // Create and navigate another WebContents.
2148  scoped_ptr<TestWebContents> other_contents(
2149      static_cast<TestWebContents*>(CreateTestWebContents()));
2150  TestWebContentsObserver other_observer(other_contents.get());
2151  other_contents->NavigateAndCommit(url_normalized);
2152
2153  // Check that an IPC with about:whatever is correctly normalized.
2154  other_contents->TestDidFailLoadWithError(
2155      1, url_from_ipc, true, 1, base::string16());
2156  EXPECT_EQ(url_normalized, other_observer.last_url());
2157}
2158
2159// Test that if a pending contents is deleted before it is shown, we don't
2160// crash.
2161TEST_F(WebContentsImplTest, PendingContents) {
2162  scoped_ptr<TestWebContents> other_contents(
2163      static_cast<TestWebContents*>(CreateTestWebContents()));
2164  contents()->AddPendingContents(other_contents.get());
2165  int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2166  other_contents.reset();
2167  EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2168}
2169
2170}  // namespace content
2171