web_contents_impl_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/logging.h"
6#include "base/utf_string_conversions.h"
7#include "content/browser/renderer_host/render_view_host_impl.h"
8#include "content/browser/renderer_host/test_render_view_host.h"
9#include "content/browser/site_instance_impl.h"
10#include "content/browser/web_contents/interstitial_page_impl.h"
11#include "content/browser/web_contents/navigation_entry_impl.h"
12#include "content/browser/webui/web_ui_controller_factory_registry.h"
13#include "content/common/view_messages.h"
14#include "content/public/browser/interstitial_page_delegate.h"
15#include "content/public/browser/navigation_details.h"
16#include "content/public/browser/notification_details.h"
17#include "content/public/browser/notification_source.h"
18#include "content/public/browser/notification_source.h"
19#include "content/public/browser/render_widget_host_view.h"
20#include "content/public/browser/web_contents_observer.h"
21#include "content/public/browser/web_ui_controller.h"
22#include "content/public/common/bindings_policy.h"
23#include "content/public/common/content_constants.h"
24#include "content/public/common/url_constants.h"
25#include "content/public/test/mock_render_process_host.h"
26#include "content/public/test/test_browser_thread.h"
27#include "content/public/test/test_utils.h"
28#include "content/test/test_content_browser_client.h"
29#include "content/test/test_content_client.h"
30#include "content/test/test_web_contents.h"
31#include "testing/gtest/include/gtest/gtest.h"
32#include "webkit/glue/webkit_glue.h"
33
34namespace content {
35namespace {
36
37const char kTestWebUIUrl[] = "chrome://blah";
38
39class WebContentsImplTestWebUIControllerFactory
40    : public WebUIControllerFactory {
41 public:
42  virtual WebUIController* CreateWebUIControllerForURL(
43      WebUI* web_ui, const GURL& url) const OVERRIDE {
44   if (!UseWebUI(url))
45     return NULL;
46
47   return new WebUIController(web_ui);
48  }
49
50  virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
51      const GURL& url) const OVERRIDE {
52    return WebUI::kNoWebUI;
53  }
54
55  virtual bool UseWebUIForURL(BrowserContext* browser_context,
56                              const GURL& url) const OVERRIDE {
57    return UseWebUI(url);
58  }
59
60  virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
61                                      const GURL& url) const OVERRIDE {
62    return UseWebUI(url);
63  }
64
65 private:
66  bool UseWebUI(const GURL& url) const {
67    return url == GURL(kTestWebUIUrl);
68  }
69};
70
71class TestInterstitialPage;
72
73class TestInterstitialPageDelegate : public InterstitialPageDelegate {
74 public:
75  TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
76      : interstitial_page_(interstitial_page) {}
77  virtual void CommandReceived(const std::string& command) OVERRIDE;
78  virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
79  virtual void OnDontProceed() OVERRIDE;
80  virtual void OnProceed() OVERRIDE;
81 private:
82  TestInterstitialPage* interstitial_page_;
83};
84
85class TestInterstitialPage : public InterstitialPageImpl {
86 public:
87  enum InterstitialState {
88    INVALID = 0,    // Hasn't yet been initialized.
89    UNDECIDED,      // Initialized, but no decision taken yet.
90    OKED,           // Proceed was called.
91    CANCELED        // DontProceed was called.
92  };
93
94  class Delegate {
95   public:
96    virtual void TestInterstitialPageDeleted(
97        TestInterstitialPage* interstitial) = 0;
98
99   protected:
100    virtual ~Delegate() {}
101  };
102
103  // IMPORTANT NOTE: if you pass stack allocated values for |state| and
104  // |deleted| (like all interstitial related tests do at this point), make sure
105  // to create an instance of the TestInterstitialPageStateGuard class on the
106  // stack in your test.  This will ensure that the TestInterstitialPage states
107  // are cleared when the test finishes.
108  // Not doing so will cause stack trashing if your test does not hide the
109  // interstitial, as in such a case it will be destroyed in the test TearDown
110  // method and will dereference the |deleted| local variable which by then is
111  // out of scope.
112  TestInterstitialPage(WebContentsImpl* contents,
113                       bool new_navigation,
114                       const GURL& url,
115                       InterstitialState* state,
116                       bool* deleted)
117      : InterstitialPageImpl(
118            contents, new_navigation, url,
119            new TestInterstitialPageDelegate(this)),
120        state_(state),
121        deleted_(deleted),
122        command_received_count_(0),
123        delegate_(NULL) {
124    *state_ = UNDECIDED;
125    *deleted_ = false;
126  }
127
128  virtual ~TestInterstitialPage() {
129    if (deleted_)
130      *deleted_ = true;
131    if (delegate_)
132      delegate_->TestInterstitialPageDeleted(this);
133  }
134
135  void OnDontProceed() {
136    if (state_)
137      *state_ = CANCELED;
138  }
139  void OnProceed() {
140    if (state_)
141      *state_ = OKED;
142  }
143
144  int command_received_count() const {
145    return command_received_count_;
146  }
147
148  void TestDomOperationResponse(const std::string& json_string) {
149    if (enabled())
150      CommandReceived();
151  }
152
153  void TestDidNavigate(int page_id, const GURL& url) {
154    ViewHostMsg_FrameNavigate_Params params;
155    InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
156    DidNavigate(GetRenderViewHostForTesting(), params);
157  }
158
159  void TestRenderViewTerminated(base::TerminationStatus status,
160                                int error_code) {
161    RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
162  }
163
164  bool is_showing() const {
165    return static_cast<TestRenderWidgetHostView*>(
166        GetRenderViewHostForTesting()->GetView())->is_showing();
167  }
168
169  void ClearStates() {
170    state_ = NULL;
171    deleted_ = NULL;
172    delegate_ = NULL;
173  }
174
175  void CommandReceived() {
176    command_received_count_++;
177  }
178
179  void set_delegate(Delegate* delegate) {
180    delegate_ = delegate;
181  }
182
183 protected:
184  virtual RenderViewHost* CreateRenderViewHost() OVERRIDE {
185    return new TestRenderViewHost(
186        SiteInstance::Create(web_contents()->GetBrowserContext()),
187        this, this, MSG_ROUTING_NONE, false);
188  }
189
190  virtual WebContentsView* CreateWebContentsView() OVERRIDE {
191    return NULL;
192  }
193
194 private:
195  InterstitialState* state_;
196  bool* deleted_;
197  int command_received_count_;
198  Delegate* delegate_;
199};
200
201void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
202  interstitial_page_->CommandReceived();
203}
204
205void TestInterstitialPageDelegate::OnDontProceed() {
206  interstitial_page_->OnDontProceed();
207}
208
209void TestInterstitialPageDelegate::OnProceed() {
210  interstitial_page_->OnProceed();
211}
212
213class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
214 public:
215  explicit TestInterstitialPageStateGuard(
216      TestInterstitialPage* interstitial_page)
217      : interstitial_page_(interstitial_page) {
218    DCHECK(interstitial_page_);
219    interstitial_page_->set_delegate(this);
220  }
221  virtual ~TestInterstitialPageStateGuard() {
222    if (interstitial_page_)
223      interstitial_page_->ClearStates();
224  }
225
226  virtual void TestInterstitialPageDeleted(
227      TestInterstitialPage* interstitial) OVERRIDE {
228    DCHECK(interstitial_page_ == interstitial);
229    interstitial_page_ = NULL;
230  }
231
232 private:
233  TestInterstitialPage* interstitial_page_;
234};
235
236class WebContentsImplTest : public RenderViewHostImplTestHarness {
237 public:
238  WebContentsImplTest()
239      : ui_thread_(BrowserThread::UI, &message_loop_),
240        file_user_blocking_thread_(
241            BrowserThread::FILE_USER_BLOCKING, &message_loop_),
242        io_thread_(BrowserThread::IO, &message_loop_) {
243  }
244
245  virtual void SetUp() {
246    RenderViewHostImplTestHarness::SetUp();
247    WebUIControllerFactory::RegisterFactory(&factory_);
248  }
249
250  virtual void TearDown() {
251    RenderViewHostImplTestHarness::TearDown();
252    WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
253  }
254
255 private:
256  WebContentsImplTestWebUIControllerFactory factory_;
257  TestBrowserThread ui_thread_;
258  TestBrowserThread file_user_blocking_thread_;
259  TestBrowserThread io_thread_;
260};
261
262class TestWebContentsObserver : public WebContentsObserver {
263 public:
264  TestWebContentsObserver(WebContents* contents)
265      : WebContentsObserver(contents) {
266  }
267  virtual ~TestWebContentsObserver() {}
268
269  virtual void DidFinishLoad(int64 frame_id,
270                             const GURL& validated_url,
271                             bool is_main_frame,
272                             RenderViewHost* render_view_host) OVERRIDE {
273    last_url_ = validated_url;
274  }
275  virtual void DidFailLoad(int64 frame_id,
276                           const GURL& validated_url,
277                           bool is_main_frame,
278                           int error_code,
279                           const string16& error_description,
280                           RenderViewHost* render_view_host) OVERRIDE {
281    last_url_ = validated_url;
282  }
283
284  const GURL& last_url() const { return last_url_; }
285
286 private:
287  GURL last_url_;
288
289  DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
290};
291
292}  // namespace
293
294// Test to make sure that title updates get stripped of whitespace.
295TEST_F(WebContentsImplTest, UpdateTitle) {
296  NavigationControllerImpl& cont =
297      static_cast<NavigationControllerImpl&>(controller());
298  ViewHostMsg_FrameNavigate_Params params;
299  InitNavigateParams(&params, 0, GURL(chrome::kAboutBlankURL),
300                     PAGE_TRANSITION_TYPED);
301
302  LoadCommittedDetails details;
303  cont.RendererDidNavigate(params, &details);
304
305  contents()->UpdateTitle(rvh(), 0, ASCIIToUTF16("    Lots O' Whitespace\n"),
306                          base::i18n::LEFT_TO_RIGHT);
307  EXPECT_EQ(ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
308}
309
310// Test view source mode for a webui page.
311TEST_F(WebContentsImplTest, NTPViewSource) {
312  NavigationControllerImpl& cont =
313      static_cast<NavigationControllerImpl&>(controller());
314  const char kUrl[] = "view-source:chrome://blah";
315  const GURL kGURL(kUrl);
316
317  process()->sink().ClearMessages();
318
319  cont.LoadURL(
320      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
321  rvh()->GetDelegate()->RenderViewCreated(rvh());
322  // Did we get the expected message?
323  EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
324      ViewMsg_EnableViewSourceMode::ID));
325
326  ViewHostMsg_FrameNavigate_Params params;
327  InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
328  LoadCommittedDetails details;
329  cont.RendererDidNavigate(params, &details);
330  // Also check title and url.
331  EXPECT_EQ(ASCIIToUTF16(kUrl), contents()->GetTitle());
332}
333
334// Test to ensure UpdateMaxPageID is working properly.
335TEST_F(WebContentsImplTest, UpdateMaxPageID) {
336  SiteInstance* instance1 = contents()->GetSiteInstance();
337  scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
338
339  // Starts at -1.
340  EXPECT_EQ(-1, contents()->GetMaxPageID());
341  EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
342  EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2));
343
344  // Make sure max_page_id_ is monotonically increasing per SiteInstance.
345  contents()->UpdateMaxPageID(3);
346  contents()->UpdateMaxPageID(1);
347  EXPECT_EQ(3, contents()->GetMaxPageID());
348  EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
349  EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2));
350
351  contents()->UpdateMaxPageIDForSiteInstance(instance2, 7);
352  EXPECT_EQ(3, contents()->GetMaxPageID());
353  EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
354  EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2));
355}
356
357// Test simple same-SiteInstance navigation.
358TEST_F(WebContentsImplTest, SimpleNavigation) {
359  TestRenderViewHost* orig_rvh = test_rvh();
360  SiteInstance* instance1 = contents()->GetSiteInstance();
361  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
362
363  // Navigate to URL
364  const GURL url("http://www.google.com");
365  controller().LoadURL(
366      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
367  EXPECT_FALSE(contents()->cross_navigation_pending());
368  EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
369  // Controller's pending entry will have a NULL site instance until we assign
370  // it in DidNavigate.
371  EXPECT_TRUE(
372      NavigationEntryImpl::FromNavigationEntry(controller().GetActiveEntry())->
373          site_instance() == NULL);
374
375  // DidNavigate from the page
376  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
377  EXPECT_FALSE(contents()->cross_navigation_pending());
378  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
379  EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
380  // Controller's entry should now have the SiteInstance, or else we won't be
381  // able to find it later.
382  EXPECT_EQ(
383      instance1,
384      NavigationEntryImpl::FromNavigationEntry(controller().GetActiveEntry())->
385          site_instance());
386}
387
388// Test that we reject NavigateToEntry if the url is over kMaxURLChars.
389TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
390  // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
391  const GURL url(std::string("http://example.org/").append(
392      kMaxURLChars + 1, 'a'));
393
394  controller().LoadURL(
395      url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
396  EXPECT_TRUE(controller().GetActiveEntry() == NULL);
397}
398
399// Test that navigating across a site boundary creates a new RenderViewHost
400// with a new SiteInstance.  Going back should do the same.
401TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
402  contents()->transition_cross_site = true;
403  TestRenderViewHost* orig_rvh = test_rvh();
404  int orig_rvh_delete_count = 0;
405  orig_rvh->set_delete_counter(&orig_rvh_delete_count);
406  SiteInstance* instance1 = contents()->GetSiteInstance();
407
408  // Navigate to URL.  First URL should use first RenderViewHost.
409  const GURL url("http://www.google.com");
410  controller().LoadURL(
411      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
412  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
413
414  EXPECT_FALSE(contents()->cross_navigation_pending());
415  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
416
417  // Navigate to new site
418  const GURL url2("http://www.yahoo.com");
419  controller().LoadURL(
420      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
421  EXPECT_TRUE(contents()->cross_navigation_pending());
422  TestRenderViewHost* pending_rvh =
423      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
424  int pending_rvh_delete_count = 0;
425  pending_rvh->set_delete_counter(&pending_rvh_delete_count);
426
427  // Navigations should be suspended in pending_rvh until ShouldCloseACK.
428  EXPECT_TRUE(pending_rvh->are_navigations_suspended());
429  orig_rvh->SendShouldCloseACK(true);
430  EXPECT_FALSE(pending_rvh->are_navigations_suspended());
431
432  // DidNavigate from the pending page
433  contents()->TestDidNavigate(
434      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
435  SiteInstance* instance2 = contents()->GetSiteInstance();
436
437  EXPECT_FALSE(contents()->cross_navigation_pending());
438  EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
439  EXPECT_NE(instance1, instance2);
440  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
441  // We keep the original RVH around, swapped out.
442  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
443      orig_rvh));
444  EXPECT_EQ(orig_rvh_delete_count, 0);
445
446  // Going back should switch SiteInstances again.  The first SiteInstance is
447  // stored in the NavigationEntry, so it should be the same as at the start.
448  // We should use the same RVH as before, swapping it back in.
449  controller().GoBack();
450  TestRenderViewHost* goback_rvh =
451      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
452  EXPECT_EQ(orig_rvh, goback_rvh);
453  EXPECT_TRUE(contents()->cross_navigation_pending());
454
455  // Navigations should be suspended in goback_rvh until ShouldCloseACK.
456  EXPECT_TRUE(goback_rvh->are_navigations_suspended());
457  pending_rvh->SendShouldCloseACK(true);
458  EXPECT_FALSE(goback_rvh->are_navigations_suspended());
459
460  // DidNavigate from the back action
461  contents()->TestDidNavigate(
462      goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
463  EXPECT_FALSE(contents()->cross_navigation_pending());
464  EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
465  EXPECT_EQ(instance1, contents()->GetSiteInstance());
466  // The pending RVH should now be swapped out, not deleted.
467  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
468      IsOnSwappedOutList(pending_rvh));
469  EXPECT_EQ(pending_rvh_delete_count, 0);
470
471  // Close contents and ensure RVHs are deleted.
472  DeleteContents();
473  EXPECT_EQ(orig_rvh_delete_count, 1);
474  EXPECT_EQ(pending_rvh_delete_count, 1);
475}
476
477// Test that navigating across a site boundary after a crash creates a new
478// RVH without requiring a cross-site transition (i.e., PENDING state).
479TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
480  contents()->transition_cross_site = true;
481  TestRenderViewHost* orig_rvh = test_rvh();
482  int orig_rvh_delete_count = 0;
483  orig_rvh->set_delete_counter(&orig_rvh_delete_count);
484  SiteInstance* instance1 = contents()->GetSiteInstance();
485
486  // Navigate to URL.  First URL should use first RenderViewHost.
487  const GURL url("http://www.google.com");
488  controller().LoadURL(
489      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
490  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
491
492  EXPECT_FALSE(contents()->cross_navigation_pending());
493  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
494
495  // Crash the renderer.
496  orig_rvh->set_render_view_created(false);
497
498  // Navigate to new site.  We should not go into PENDING.
499  const GURL url2("http://www.yahoo.com");
500  controller().LoadURL(
501      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
502  RenderViewHost* new_rvh = rvh();
503  EXPECT_FALSE(contents()->cross_navigation_pending());
504  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
505  EXPECT_NE(orig_rvh, new_rvh);
506  EXPECT_EQ(orig_rvh_delete_count, 1);
507
508  // DidNavigate from the new page
509  contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
510  SiteInstance* instance2 = contents()->GetSiteInstance();
511
512  EXPECT_FALSE(contents()->cross_navigation_pending());
513  EXPECT_EQ(new_rvh, rvh());
514  EXPECT_NE(instance1, instance2);
515  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
516
517  // Close contents and ensure RVHs are deleted.
518  DeleteContents();
519  EXPECT_EQ(orig_rvh_delete_count, 1);
520}
521
522// Test that opening a new contents in the same SiteInstance and then navigating
523// both contentses to a new site will place both contentses in a single
524// SiteInstance.
525TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
526  contents()->transition_cross_site = true;
527  TestRenderViewHost* orig_rvh = test_rvh();
528  SiteInstance* instance1 = contents()->GetSiteInstance();
529
530  // Navigate to URL.  First URL should use first RenderViewHost.
531  const GURL url("http://www.google.com");
532  controller().LoadURL(
533      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
534  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
535
536  // Open a new contents with the same SiteInstance, navigated to the same site.
537  scoped_ptr<TestWebContents> contents2(
538      TestWebContents::Create(browser_context_.get(), instance1));
539  contents2->transition_cross_site = true;
540  contents2->GetController().LoadURL(url, Referrer(),
541                                    PAGE_TRANSITION_TYPED,
542                                    std::string());
543  // Need this page id to be 2 since the site instance is the same (which is the
544  // scope of page IDs) and we want to consider this a new page.
545  contents2->TestDidNavigate(
546      contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
547
548  // Navigate first contents to a new site.
549  const GURL url2a("http://www.yahoo.com");
550  controller().LoadURL(
551      url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
552  orig_rvh->SendShouldCloseACK(true);
553  TestRenderViewHost* pending_rvh_a =
554      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
555  contents()->TestDidNavigate(
556      pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
557  SiteInstance* instance2a = contents()->GetSiteInstance();
558  EXPECT_NE(instance1, instance2a);
559
560  // Navigate second contents to the same site as the first tab.
561  const GURL url2b("http://mail.yahoo.com");
562  contents2->GetController().LoadURL(url2b, Referrer(),
563                                    PAGE_TRANSITION_TYPED,
564                                    std::string());
565  TestRenderViewHost* rvh2 =
566      static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
567  rvh2->SendShouldCloseACK(true);
568  TestRenderViewHost* pending_rvh_b =
569      static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
570  EXPECT_TRUE(pending_rvh_b != NULL);
571  EXPECT_TRUE(contents2->cross_navigation_pending());
572
573  // NOTE(creis): We used to be in danger of showing a crash page here if the
574  // second contents hadn't navigated somewhere first (bug 1145430).  That case
575  // is now covered by the CrossSiteBoundariesAfterCrash test.
576  contents2->TestDidNavigate(
577      pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
578  SiteInstance* instance2b = contents2->GetSiteInstance();
579  EXPECT_NE(instance1, instance2b);
580
581  // Both contentses should now be in the same SiteInstance.
582  EXPECT_EQ(instance2a, instance2b);
583}
584
585// Test that we can find an opener RVH even if it's pending.
586// http://crbug.com/176252.
587TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
588  contents()->transition_cross_site = true;
589  TestRenderViewHost* orig_rvh = test_rvh();
590
591  // Navigate to a URL.
592  const GURL url("http://www.google.com");
593  controller().LoadURL(
594      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
595  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
596
597  // Start to navigate first tab to a new site, so that it has a pending RVH.
598  const GURL url2("http://www.yahoo.com");
599  controller().LoadURL(
600      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
601  orig_rvh->SendShouldCloseACK(true);
602  TestRenderViewHost* pending_rvh =
603      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
604
605  // While it is still pending, simulate opening a new tab with the first tab
606  // as its opener.  This will call WebContentsImpl::CreateOpenerRenderViews
607  // on the opener to ensure that an RVH exists.
608  int opener_routing_id = contents()->CreateOpenerRenderViews(
609      pending_rvh->GetSiteInstance());
610
611  // We should find the pending RVH and not create a new one.
612  EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
613}
614
615// Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
616// to determine whether a navigation is cross-site.
617TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
618  contents()->transition_cross_site = true;
619  RenderViewHost* orig_rvh = rvh();
620  SiteInstance* instance1 = contents()->GetSiteInstance();
621
622  // Navigate to URL.
623  const GURL url("http://www.google.com");
624  controller().LoadURL(
625      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
626  contents()->TestDidNavigate(
627      orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
628
629  // Open a related contents to a second site.
630  scoped_ptr<TestWebContents> contents2(
631      TestWebContents::Create(browser_context_.get(), instance1));
632  contents2->transition_cross_site = true;
633  const GURL url2("http://www.yahoo.com");
634  contents2->GetController().LoadURL(url2, Referrer(),
635                                    PAGE_TRANSITION_TYPED,
636                                    std::string());
637  // The first RVH in contents2 isn't live yet, so we shortcut the cross site
638  // pending.
639  TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
640      contents2->GetRenderViewHost());
641  EXPECT_FALSE(contents2->cross_navigation_pending());
642  contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
643  SiteInstance* instance2 = contents2->GetSiteInstance();
644  EXPECT_NE(instance1, instance2);
645  EXPECT_FALSE(contents2->cross_navigation_pending());
646
647  // Simulate a link click in first contents to second site.  Doesn't switch
648  // SiteInstances, because we don't intercept WebKit navigations.
649  contents()->TestDidNavigate(
650      orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
651  SiteInstance* instance3 = contents()->GetSiteInstance();
652  EXPECT_EQ(instance1, instance3);
653  EXPECT_FALSE(contents()->cross_navigation_pending());
654
655  // Navigate to the new site.  Doesn't switch SiteInstancees, because we
656  // compare against the current URL, not the SiteInstance's site.
657  const GURL url3("http://mail.yahoo.com");
658  controller().LoadURL(
659      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
660  EXPECT_FALSE(contents()->cross_navigation_pending());
661  contents()->TestDidNavigate(
662      orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
663  SiteInstance* instance4 = contents()->GetSiteInstance();
664  EXPECT_EQ(instance1, instance4);
665}
666
667// Test that the onbeforeunload and onunload handlers run when navigating
668// across site boundaries.
669TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
670  contents()->transition_cross_site = true;
671  TestRenderViewHost* orig_rvh = test_rvh();
672  SiteInstance* instance1 = contents()->GetSiteInstance();
673
674  // Navigate to URL.  First URL should use first RenderViewHost.
675  const GURL url("http://www.google.com");
676  controller().LoadURL(
677      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
678  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
679  EXPECT_FALSE(contents()->cross_navigation_pending());
680  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
681
682  // Navigate to new site, but simulate an onbeforeunload denial.
683  const GURL url2("http://www.yahoo.com");
684  controller().LoadURL(
685      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
686  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
687  base::TimeTicks now = base::TimeTicks::Now();
688  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false, now, now));
689  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
690  EXPECT_FALSE(contents()->cross_navigation_pending());
691  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
692
693  // Navigate again, but simulate an onbeforeunload approval.
694  controller().LoadURL(
695      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
696  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
697  now = base::TimeTicks::Now();
698  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
699  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
700  EXPECT_TRUE(contents()->cross_navigation_pending());
701  TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
702      contents()->GetPendingRenderViewHost());
703
704  // We won't hear DidNavigate until the onunload handler has finished running.
705  // (No way to simulate that here, but it involves a call from RDH to
706  // WebContentsImpl::OnCrossSiteResponse.)
707
708  // DidNavigate from the pending page
709  contents()->TestDidNavigate(
710      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
711  SiteInstance* instance2 = contents()->GetSiteInstance();
712  EXPECT_FALSE(contents()->cross_navigation_pending());
713  EXPECT_EQ(pending_rvh, rvh());
714  EXPECT_NE(instance1, instance2);
715  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
716}
717
718// Test that during a slow cross-site navigation, the original renderer can
719// navigate to a different URL and have it displayed, canceling the slow
720// navigation.
721TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
722  contents()->transition_cross_site = true;
723  TestRenderViewHost* orig_rvh = test_rvh();
724  SiteInstance* instance1 = contents()->GetSiteInstance();
725
726  // Navigate to URL.  First URL should use first RenderViewHost.
727  const GURL url("http://www.google.com");
728  controller().LoadURL(
729      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
730  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
731  EXPECT_FALSE(contents()->cross_navigation_pending());
732  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
733
734  // Navigate to new site, simulating an onbeforeunload approval.
735  const GURL url2("http://www.yahoo.com");
736  controller().LoadURL(
737      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
738  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
739  base::TimeTicks now = base::TimeTicks::Now();
740  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
741  EXPECT_TRUE(contents()->cross_navigation_pending());
742
743  // Suppose the original renderer navigates before the new one is ready.
744  orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
745
746  // Verify that the pending navigation is cancelled.
747  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
748  SiteInstance* instance2 = contents()->GetSiteInstance();
749  EXPECT_FALSE(contents()->cross_navigation_pending());
750  EXPECT_EQ(orig_rvh, rvh());
751  EXPECT_EQ(instance1, instance2);
752  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
753}
754
755TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
756  contents()->transition_cross_site = true;
757
758  // Start with a web ui page, which gets a new RVH with WebUI bindings.
759  const GURL url1("chrome://blah");
760  controller().LoadURL(
761      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
762  TestRenderViewHost* ntp_rvh = test_rvh();
763  contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
764  NavigationEntry* entry1 = controller().GetLastCommittedEntry();
765  SiteInstance* instance1 = contents()->GetSiteInstance();
766
767  EXPECT_FALSE(contents()->cross_navigation_pending());
768  EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
769  EXPECT_EQ(url1, entry1->GetURL());
770  EXPECT_EQ(instance1,
771            NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
772  EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
773
774  // Navigate to new site.
775  const GURL url2("http://www.google.com");
776  controller().LoadURL(
777      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
778  EXPECT_TRUE(contents()->cross_navigation_pending());
779  TestRenderViewHost* google_rvh =
780      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
781
782  // Simulate beforeunload approval.
783  EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
784  base::TimeTicks now = base::TimeTicks::Now();
785  ntp_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
786
787  // DidNavigate from the pending page.
788  contents()->TestDidNavigate(
789      google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
790  NavigationEntry* entry2 = controller().GetLastCommittedEntry();
791  SiteInstance* instance2 = contents()->GetSiteInstance();
792
793  EXPECT_FALSE(contents()->cross_navigation_pending());
794  EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
795  EXPECT_NE(instance1, instance2);
796  EXPECT_FALSE(contents()->GetPendingRenderViewHost());
797  EXPECT_EQ(url2, entry2->GetURL());
798  EXPECT_EQ(instance2,
799            NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
800  EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
801
802  // Navigate to third page on same site.
803  const GURL url3("http://news.google.com");
804  controller().LoadURL(
805      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
806  EXPECT_FALSE(contents()->cross_navigation_pending());
807  contents()->TestDidNavigate(
808      google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
809  NavigationEntry* entry3 = controller().GetLastCommittedEntry();
810  SiteInstance* instance3 = contents()->GetSiteInstance();
811
812  EXPECT_FALSE(contents()->cross_navigation_pending());
813  EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
814  EXPECT_EQ(instance2, instance3);
815  EXPECT_FALSE(contents()->GetPendingRenderViewHost());
816  EXPECT_EQ(url3, entry3->GetURL());
817  EXPECT_EQ(instance3,
818            NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
819
820  // Go back within the site.
821  controller().GoBack();
822  EXPECT_FALSE(contents()->cross_navigation_pending());
823  EXPECT_EQ(entry2, controller().GetPendingEntry());
824
825  // Before that commits, go back again.
826  controller().GoBack();
827  EXPECT_TRUE(contents()->cross_navigation_pending());
828  EXPECT_TRUE(contents()->GetPendingRenderViewHost());
829  EXPECT_EQ(entry1, controller().GetPendingEntry());
830
831  // Simulate beforeunload approval.
832  EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
833  now = base::TimeTicks::Now();
834  google_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
835
836  // DidNavigate from the first back. This aborts the second back's pending RVH.
837  contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
838
839  // We should commit this page and forget about the second back.
840  EXPECT_FALSE(contents()->cross_navigation_pending());
841  EXPECT_FALSE(controller().GetPendingEntry());
842  EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
843  EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
844
845  // We should not have corrupted the NTP entry.
846  EXPECT_EQ(instance3,
847            NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
848  EXPECT_EQ(instance2,
849            NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
850  EXPECT_EQ(instance1,
851            NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
852  EXPECT_EQ(url1, entry1->GetURL());
853}
854
855// Test that during a slow cross-site navigation, a sub-frame navigation in the
856// original renderer will not cancel the slow navigation (bug 42029).
857TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
858  contents()->transition_cross_site = true;
859  TestRenderViewHost* orig_rvh = test_rvh();
860
861  // Navigate to URL.  First URL should use first RenderViewHost.
862  const GURL url("http://www.google.com");
863  controller().LoadURL(
864      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
865  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
866  EXPECT_FALSE(contents()->cross_navigation_pending());
867  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
868
869  // Start navigating to new site.
870  const GURL url2("http://www.yahoo.com");
871  controller().LoadURL(
872      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
873
874  // Simulate a sub-frame navigation arriving and ensure the RVH is still
875  // waiting for a before unload response.
876  orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
877                                       PAGE_TRANSITION_AUTO_SUBFRAME);
878  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
879
880  // Now simulate the onbeforeunload approval and verify the navigation is
881  // not canceled.
882  base::TimeTicks now = base::TimeTicks::Now();
883  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
884  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
885  EXPECT_TRUE(contents()->cross_navigation_pending());
886}
887
888// Test that a cross-site navigation is not preempted if the previous
889// renderer sends a FrameNavigate message just before being told to stop.
890// We should only preempt the cross-site navigation if the previous renderer
891// has started a new navigation.  See http://crbug.com/79176.
892TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
893  contents()->transition_cross_site = true;
894
895  // Navigate to NTP URL.
896  const GURL url("chrome://blah");
897  controller().LoadURL(
898      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
899  TestRenderViewHost* orig_rvh = test_rvh();
900  EXPECT_FALSE(contents()->cross_navigation_pending());
901
902  // Navigate to new site, with the beforeunload request in flight.
903  const GURL url2("http://www.yahoo.com");
904  controller().LoadURL(
905      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
906  TestRenderViewHost* pending_rvh =
907      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
908  EXPECT_TRUE(contents()->cross_navigation_pending());
909  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
910
911  // Suppose the first navigation tries to commit now, with a
912  // ViewMsg_Stop in flight.  This should not cancel the pending navigation,
913  // but it should act as if the beforeunload ack arrived.
914  orig_rvh->SendNavigate(1, GURL("chrome://blah"));
915  EXPECT_TRUE(contents()->cross_navigation_pending());
916  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
917  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
918
919  // The pending navigation should be able to commit successfully.
920  contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
921  EXPECT_FALSE(contents()->cross_navigation_pending());
922  EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
923}
924
925// Test that the original renderer cannot preempt a cross-site navigation once
926// the unload request has been made.  At this point, the cross-site navigation
927// is almost ready to be displayed, and the original renderer is only given a
928// short chance to run an unload handler.  Prevents regression of bug 23942.
929TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
930  contents()->transition_cross_site = true;
931  TestRenderViewHost* orig_rvh = test_rvh();
932  SiteInstance* instance1 = contents()->GetSiteInstance();
933
934  // Navigate to URL.  First URL should use first RenderViewHost.
935  const GURL url("http://www.google.com");
936  controller().LoadURL(
937      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
938  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
939  EXPECT_FALSE(contents()->cross_navigation_pending());
940  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
941
942  // Navigate to new site, simulating an onbeforeunload approval.
943  const GURL url2("http://www.yahoo.com");
944  controller().LoadURL(
945      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
946  base::TimeTicks now = base::TimeTicks::Now();
947  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
948  EXPECT_TRUE(contents()->cross_navigation_pending());
949  TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
950      contents()->GetPendingRenderViewHost());
951
952  // Simulate the pending renderer's response, which leads to an unload request
953  // being sent to orig_rvh.
954  contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(0, 0);
955
956  // Suppose the original renderer navigates now, while the unload request is in
957  // flight.  We should ignore it, wait for the unload ack, and let the pending
958  // request continue.  Otherwise, the contents may close spontaneously or stop
959  // responding to navigation requests.  (See bug 23942.)
960  ViewHostMsg_FrameNavigate_Params params1a;
961  InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
962                     PAGE_TRANSITION_TYPED);
963  orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
964
965  // Verify that the pending navigation is still in progress.
966  EXPECT_TRUE(contents()->cross_navigation_pending());
967  EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
968
969  // DidNavigate from the pending page should commit it.
970  contents()->TestDidNavigate(
971      pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
972  SiteInstance* instance2 = contents()->GetSiteInstance();
973  EXPECT_FALSE(contents()->cross_navigation_pending());
974  EXPECT_EQ(pending_rvh, rvh());
975  EXPECT_NE(instance1, instance2);
976  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
977}
978
979// Test that a cross-site navigation that doesn't commit after the unload
980// handler doesn't leave the contents in a stuck state.  http://crbug.com/88562
981TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
982  contents()->transition_cross_site = true;
983  TestRenderViewHost* orig_rvh = test_rvh();
984  SiteInstance* instance1 = contents()->GetSiteInstance();
985
986  // Navigate to URL.  First URL should use first RenderViewHost.
987  const GURL url("http://www.google.com");
988  controller().LoadURL(
989      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
990  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
991  EXPECT_FALSE(contents()->cross_navigation_pending());
992  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
993
994  // Navigate to new site, simulating an onbeforeunload approval.
995  const GURL url2("http://www.yahoo.com");
996  controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
997  EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
998  base::TimeTicks now = base::TimeTicks::Now();
999  orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1000  EXPECT_TRUE(contents()->cross_navigation_pending());
1001
1002  // Simulate swap out message when the response arrives.
1003  orig_rvh->set_is_swapped_out(true);
1004
1005  // Suppose the navigation doesn't get a chance to commit, and the user
1006  // navigates in the current RVH's SiteInstance.
1007  controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1008
1009  // Verify that the pending navigation is cancelled and the renderer is no
1010  // longer swapped out.
1011  EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1012  SiteInstance* instance2 = contents()->GetSiteInstance();
1013  EXPECT_FALSE(contents()->cross_navigation_pending());
1014  EXPECT_EQ(orig_rvh, rvh());
1015  EXPECT_FALSE(orig_rvh->is_swapped_out());
1016  EXPECT_EQ(instance1, instance2);
1017  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1018}
1019
1020// Test that NavigationEntries have the correct content state after going
1021// forward and back.  Prevents regression for bug 1116137.
1022TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1023  TestRenderViewHost* orig_rvh = test_rvh();
1024
1025  // Navigate to URL.  There should be no committed entry yet.
1026  const GURL url("http://www.google.com");
1027  controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1028  NavigationEntry* entry = controller().GetLastCommittedEntry();
1029  EXPECT_TRUE(entry == NULL);
1030
1031  // Committed entry should have content state after DidNavigate.
1032  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1033  entry = controller().GetLastCommittedEntry();
1034  EXPECT_FALSE(entry->GetContentState().empty());
1035
1036  // Navigate to same site.
1037  const GURL url2("http://images.google.com");
1038  controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1039  entry = controller().GetLastCommittedEntry();
1040  EXPECT_FALSE(entry->GetContentState().empty());
1041
1042  // Committed entry should have content state after DidNavigate.
1043  contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1044  entry = controller().GetLastCommittedEntry();
1045  EXPECT_FALSE(entry->GetContentState().empty());
1046
1047  // Now go back.  Committed entry should still have content state.
1048  controller().GoBack();
1049  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1050  entry = controller().GetLastCommittedEntry();
1051  EXPECT_FALSE(entry->GetContentState().empty());
1052}
1053
1054// Test that NavigationEntries have the correct content state and SiteInstance
1055// state after opening a new window to about:blank.  Prevents regression for
1056// bugs b/1116137 and http://crbug.com/111975.
1057TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1058  TestRenderViewHost* orig_rvh = test_rvh();
1059
1060  // When opening a new window, it is navigated to about:blank internally.
1061  // Currently, this results in two DidNavigate events.
1062  const GURL url(chrome::kAboutBlankURL);
1063  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1064  contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1065
1066  // Should have a content state here.
1067  NavigationEntry* entry = controller().GetLastCommittedEntry();
1068  EXPECT_FALSE(entry->GetContentState().empty());
1069
1070  // The SiteInstance should be available for other navigations to use.
1071  NavigationEntryImpl* entry_impl =
1072      NavigationEntryImpl::FromNavigationEntry(entry);
1073  EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1074  int32 site_instance_id = entry_impl->site_instance()->GetId();
1075
1076  // Navigating to a normal page should not cause a process swap.
1077  const GURL new_url("http://www.google.com");
1078  controller().LoadURL(new_url, Referrer(),
1079                       PAGE_TRANSITION_TYPED, std::string());
1080  EXPECT_FALSE(contents()->cross_navigation_pending());
1081  EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1082  contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1083  NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1084      controller().GetLastCommittedEntry());
1085  EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1086  EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1087}
1088
1089////////////////////////////////////////////////////////////////////////////////
1090// Interstitial Tests
1091////////////////////////////////////////////////////////////////////////////////
1092
1093// Test navigating to a page (with the navigation initiated from the browser,
1094// as when a URL is typed in the location bar) that shows an interstitial and
1095// creates a new navigation entry, then hiding it without proceeding.
1096TEST_F(WebContentsImplTest,
1097       ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1098  // Navigate to a page.
1099  GURL url1("http://www.google.com");
1100  test_rvh()->SendNavigate(1, url1);
1101  EXPECT_EQ(1, controller().GetEntryCount());
1102
1103  // Initiate a browser navigation that will trigger the interstitial
1104  controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1105                        PAGE_TRANSITION_TYPED, std::string());
1106
1107  // Show an interstitial.
1108  TestInterstitialPage::InterstitialState state =
1109      TestInterstitialPage::INVALID;
1110  bool deleted = false;
1111  GURL url2("http://interstitial");
1112  TestInterstitialPage* interstitial =
1113      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1114  TestInterstitialPageStateGuard state_guard(interstitial);
1115  interstitial->Show();
1116  // The interstitial should not show until its navigation has committed.
1117  EXPECT_FALSE(interstitial->is_showing());
1118  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1119  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1120  // Let's commit the interstitial navigation.
1121  interstitial->TestDidNavigate(1, url2);
1122  EXPECT_TRUE(interstitial->is_showing());
1123  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1124  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1125  NavigationEntry* entry = controller().GetActiveEntry();
1126  ASSERT_TRUE(entry != NULL);
1127  EXPECT_TRUE(entry->GetURL() == url2);
1128
1129  // Now don't proceed.
1130  interstitial->DontProceed();
1131  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1132  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1133  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1134  entry = controller().GetActiveEntry();
1135  ASSERT_TRUE(entry != NULL);
1136  EXPECT_TRUE(entry->GetURL() == url1);
1137  EXPECT_EQ(1, controller().GetEntryCount());
1138
1139  RunAllPendingInMessageLoop();
1140  EXPECT_TRUE(deleted);
1141}
1142
1143// Test navigating to a page (with the navigation initiated from the renderer,
1144// as when clicking on a link in the page) that shows an interstitial and
1145// creates a new navigation entry, then hiding it without proceeding.
1146TEST_F(WebContentsImplTest,
1147       ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1148  // Navigate to a page.
1149  GURL url1("http://www.google.com");
1150  test_rvh()->SendNavigate(1, url1);
1151  EXPECT_EQ(1, controller().GetEntryCount());
1152
1153  // Show an interstitial (no pending entry, the interstitial would have been
1154  // triggered by clicking on a link).
1155  TestInterstitialPage::InterstitialState state =
1156      TestInterstitialPage::INVALID;
1157  bool deleted = false;
1158  GURL url2("http://interstitial");
1159  TestInterstitialPage* interstitial =
1160      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1161  TestInterstitialPageStateGuard state_guard(interstitial);
1162  interstitial->Show();
1163  // The interstitial should not show until its navigation has committed.
1164  EXPECT_FALSE(interstitial->is_showing());
1165  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1166  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1167  // Let's commit the interstitial navigation.
1168  interstitial->TestDidNavigate(1, url2);
1169  EXPECT_TRUE(interstitial->is_showing());
1170  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1171  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1172  NavigationEntry* entry = controller().GetActiveEntry();
1173  ASSERT_TRUE(entry != NULL);
1174  EXPECT_TRUE(entry->GetURL() == url2);
1175
1176  // Now don't proceed.
1177  interstitial->DontProceed();
1178  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1179  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1180  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1181  entry = controller().GetActiveEntry();
1182  ASSERT_TRUE(entry != NULL);
1183  EXPECT_TRUE(entry->GetURL() == url1);
1184  EXPECT_EQ(1, controller().GetEntryCount());
1185
1186  RunAllPendingInMessageLoop();
1187  EXPECT_TRUE(deleted);
1188}
1189
1190// Test navigating to a page that shows an interstitial without creating a new
1191// navigation entry (this happens when the interstitial is triggered by a
1192// sub-resource in the page), then hiding it without proceeding.
1193TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1194  // Navigate to a page.
1195  GURL url1("http://www.google.com");
1196  test_rvh()->SendNavigate(1, url1);
1197  EXPECT_EQ(1, controller().GetEntryCount());
1198
1199  // Show an interstitial.
1200  TestInterstitialPage::InterstitialState state =
1201      TestInterstitialPage::INVALID;
1202  bool deleted = false;
1203  GURL url2("http://interstitial");
1204  TestInterstitialPage* interstitial =
1205      new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1206  TestInterstitialPageStateGuard state_guard(interstitial);
1207  interstitial->Show();
1208  // The interstitial should not show until its navigation has committed.
1209  EXPECT_FALSE(interstitial->is_showing());
1210  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1211  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1212  // Let's commit the interstitial navigation.
1213  interstitial->TestDidNavigate(1, url2);
1214  EXPECT_TRUE(interstitial->is_showing());
1215  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1216  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1217  NavigationEntry* entry = controller().GetActiveEntry();
1218  ASSERT_TRUE(entry != NULL);
1219  // The URL specified to the interstitial should have been ignored.
1220  EXPECT_TRUE(entry->GetURL() == url1);
1221
1222  // Now don't proceed.
1223  interstitial->DontProceed();
1224  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1225  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1226  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1227  entry = controller().GetActiveEntry();
1228  ASSERT_TRUE(entry != NULL);
1229  EXPECT_TRUE(entry->GetURL() == url1);
1230  EXPECT_EQ(1, controller().GetEntryCount());
1231
1232  RunAllPendingInMessageLoop();
1233  EXPECT_TRUE(deleted);
1234}
1235
1236// Test navigating to a page (with the navigation initiated from the browser,
1237// as when a URL is typed in the location bar) that shows an interstitial and
1238// creates a new navigation entry, then proceeding.
1239TEST_F(WebContentsImplTest,
1240       ShowInterstitialFromBrowserNewNavigationProceed) {
1241  // Navigate to a page.
1242  GURL url1("http://www.google.com");
1243  test_rvh()->SendNavigate(1, url1);
1244  EXPECT_EQ(1, controller().GetEntryCount());
1245
1246  // Initiate a browser navigation that will trigger the interstitial
1247  controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1248                        PAGE_TRANSITION_TYPED, std::string());
1249
1250  // Show an interstitial.
1251  TestInterstitialPage::InterstitialState state =
1252      TestInterstitialPage::INVALID;
1253  bool deleted = false;
1254  GURL url2("http://interstitial");
1255  TestInterstitialPage* interstitial =
1256      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1257  TestInterstitialPageStateGuard state_guard(interstitial);
1258  interstitial->Show();
1259  // The interstitial should not show until its navigation has committed.
1260  EXPECT_FALSE(interstitial->is_showing());
1261  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1262  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1263  // Let's commit the interstitial navigation.
1264  interstitial->TestDidNavigate(1, url2);
1265  EXPECT_TRUE(interstitial->is_showing());
1266  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1267  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1268  NavigationEntry* entry = controller().GetActiveEntry();
1269  ASSERT_TRUE(entry != NULL);
1270  EXPECT_TRUE(entry->GetURL() == url2);
1271
1272  // Then proceed.
1273  interstitial->Proceed();
1274  // The interstitial should show until the new navigation commits.
1275  RunAllPendingInMessageLoop();
1276  ASSERT_FALSE(deleted);
1277  EXPECT_EQ(TestInterstitialPage::OKED, state);
1278  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1279  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1280
1281  // Simulate the navigation to the page, that's when the interstitial gets
1282  // hidden.
1283  GURL url3("http://www.thepage.com");
1284  test_rvh()->SendNavigate(2, url3);
1285
1286  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1287  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1288  entry = controller().GetActiveEntry();
1289  ASSERT_TRUE(entry != NULL);
1290  EXPECT_TRUE(entry->GetURL() == url3);
1291
1292  EXPECT_EQ(2, controller().GetEntryCount());
1293
1294  RunAllPendingInMessageLoop();
1295  EXPECT_TRUE(deleted);
1296}
1297
1298// Test navigating to a page (with the navigation initiated from the renderer,
1299// as when clicking on a link in the page) that shows an interstitial and
1300// creates a new navigation entry, then proceeding.
1301TEST_F(WebContentsImplTest,
1302       ShowInterstitialFromRendererNewNavigationProceed) {
1303  // Navigate to a page.
1304  GURL url1("http://www.google.com");
1305  test_rvh()->SendNavigate(1, url1);
1306  EXPECT_EQ(1, controller().GetEntryCount());
1307
1308  // Show an interstitial.
1309  TestInterstitialPage::InterstitialState state =
1310      TestInterstitialPage::INVALID;
1311  bool deleted = false;
1312  GURL url2("http://interstitial");
1313  TestInterstitialPage* interstitial =
1314      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1315  TestInterstitialPageStateGuard state_guard(interstitial);
1316  interstitial->Show();
1317  // The interstitial should not show until its navigation has committed.
1318  EXPECT_FALSE(interstitial->is_showing());
1319  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1320  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1321  // Let's commit the interstitial navigation.
1322  interstitial->TestDidNavigate(1, url2);
1323  EXPECT_TRUE(interstitial->is_showing());
1324  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1325  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1326  NavigationEntry* entry = controller().GetActiveEntry();
1327  ASSERT_TRUE(entry != NULL);
1328  EXPECT_TRUE(entry->GetURL() == url2);
1329
1330  // Then proceed.
1331  interstitial->Proceed();
1332  // The interstitial should show until the new navigation commits.
1333  RunAllPendingInMessageLoop();
1334  ASSERT_FALSE(deleted);
1335  EXPECT_EQ(TestInterstitialPage::OKED, state);
1336  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1337  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1338
1339  // Simulate the navigation to the page, that's when the interstitial gets
1340  // hidden.
1341  GURL url3("http://www.thepage.com");
1342  test_rvh()->SendNavigate(2, url3);
1343
1344  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1345  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1346  entry = controller().GetActiveEntry();
1347  ASSERT_TRUE(entry != NULL);
1348  EXPECT_TRUE(entry->GetURL() == url3);
1349
1350  EXPECT_EQ(2, controller().GetEntryCount());
1351
1352  RunAllPendingInMessageLoop();
1353  EXPECT_TRUE(deleted);
1354}
1355
1356// Test navigating to a page that shows an interstitial without creating a new
1357// navigation entry (this happens when the interstitial is triggered by a
1358// sub-resource in the page), then proceeding.
1359TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1360  // Navigate to a page so we have a navigation entry in the controller.
1361  GURL url1("http://www.google.com");
1362  test_rvh()->SendNavigate(1, url1);
1363  EXPECT_EQ(1, controller().GetEntryCount());
1364
1365  // Show an interstitial.
1366  TestInterstitialPage::InterstitialState state =
1367      TestInterstitialPage::INVALID;
1368  bool deleted = false;
1369  GURL url2("http://interstitial");
1370  TestInterstitialPage* interstitial =
1371      new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1372  TestInterstitialPageStateGuard state_guard(interstitial);
1373  interstitial->Show();
1374  // The interstitial should not show until its navigation has committed.
1375  EXPECT_FALSE(interstitial->is_showing());
1376  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1377  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1378  // Let's commit the interstitial navigation.
1379  interstitial->TestDidNavigate(1, url2);
1380  EXPECT_TRUE(interstitial->is_showing());
1381  EXPECT_TRUE(contents()->ShowingInterstitialPage());
1382  EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1383  NavigationEntry* entry = controller().GetActiveEntry();
1384  ASSERT_TRUE(entry != NULL);
1385  // The URL specified to the interstitial should have been ignored.
1386  EXPECT_TRUE(entry->GetURL() == url1);
1387
1388  // Then proceed.
1389  interstitial->Proceed();
1390  // Since this is not a new navigation, the previous page is dismissed right
1391  // away and shows the original page.
1392  EXPECT_EQ(TestInterstitialPage::OKED, state);
1393  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1394  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1395  entry = controller().GetActiveEntry();
1396  ASSERT_TRUE(entry != NULL);
1397  EXPECT_TRUE(entry->GetURL() == url1);
1398
1399  EXPECT_EQ(1, controller().GetEntryCount());
1400
1401  RunAllPendingInMessageLoop();
1402  EXPECT_TRUE(deleted);
1403}
1404
1405// Test navigating to a page that shows an interstitial, then navigating away.
1406TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1407  // Show interstitial.
1408  TestInterstitialPage::InterstitialState state =
1409      TestInterstitialPage::INVALID;
1410  bool deleted = false;
1411  GURL url("http://interstitial");
1412  TestInterstitialPage* interstitial =
1413      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1414  TestInterstitialPageStateGuard state_guard(interstitial);
1415  interstitial->Show();
1416  interstitial->TestDidNavigate(1, url);
1417
1418  // While interstitial showing, navigate to a new URL.
1419  const GURL url2("http://www.yahoo.com");
1420  test_rvh()->SendNavigate(1, url2);
1421
1422  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1423
1424  RunAllPendingInMessageLoop();
1425  EXPECT_TRUE(deleted);
1426}
1427
1428// Test navigating to a page that shows an interstitial, then going back.
1429TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1430  // Navigate to a page so we have a navigation entry in the controller.
1431  GURL url1("http://www.google.com");
1432  test_rvh()->SendNavigate(1, url1);
1433  EXPECT_EQ(1, controller().GetEntryCount());
1434
1435  // Show interstitial.
1436  TestInterstitialPage::InterstitialState state =
1437      TestInterstitialPage::INVALID;
1438  bool deleted = false;
1439  GURL interstitial_url("http://interstitial");
1440  TestInterstitialPage* interstitial =
1441      new TestInterstitialPage(contents(), true, interstitial_url,
1442                               &state, &deleted);
1443  TestInterstitialPageStateGuard state_guard(interstitial);
1444  interstitial->Show();
1445  interstitial->TestDidNavigate(2, interstitial_url);
1446
1447  // While the interstitial is showing, go back.
1448  controller().GoBack();
1449  test_rvh()->SendNavigate(1, url1);
1450
1451  // Make sure we are back to the original page and that the interstitial is
1452  // gone.
1453  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1454  NavigationEntry* entry = controller().GetActiveEntry();
1455  ASSERT_TRUE(entry);
1456  EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1457
1458  RunAllPendingInMessageLoop();
1459  EXPECT_TRUE(deleted);
1460}
1461
1462// Test navigating to a page that shows an interstitial, has a renderer crash,
1463// and then goes back.
1464TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1465  // Navigate to a page so we have a navigation entry in the controller.
1466  GURL url1("http://www.google.com");
1467  test_rvh()->SendNavigate(1, url1);
1468  EXPECT_EQ(1, controller().GetEntryCount());
1469
1470  // Show interstitial.
1471  TestInterstitialPage::InterstitialState state =
1472      TestInterstitialPage::INVALID;
1473  bool deleted = false;
1474  GURL interstitial_url("http://interstitial");
1475  TestInterstitialPage* interstitial =
1476      new TestInterstitialPage(contents(), true, interstitial_url,
1477                               &state, &deleted);
1478  TestInterstitialPageStateGuard state_guard(interstitial);
1479  interstitial->Show();
1480  interstitial->TestDidNavigate(2, interstitial_url);
1481
1482  // Crash the renderer
1483  test_rvh()->OnMessageReceived(
1484      ViewHostMsg_RenderViewGone(
1485          0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1486
1487  // While the interstitial is showing, go back.
1488  controller().GoBack();
1489  test_rvh()->SendNavigate(1, url1);
1490
1491  // Make sure we are back to the original page and that the interstitial is
1492  // gone.
1493  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1494  NavigationEntry* entry = controller().GetActiveEntry();
1495  ASSERT_TRUE(entry);
1496  EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1497
1498  RunAllPendingInMessageLoop();
1499  EXPECT_TRUE(deleted);
1500}
1501
1502// Test navigating to a page that shows an interstitial, has the renderer crash,
1503// and then navigates to the interstitial.
1504TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1505  // Navigate to a page so we have a navigation entry in the controller.
1506  GURL url1("http://www.google.com");
1507  test_rvh()->SendNavigate(1, url1);
1508  EXPECT_EQ(1, controller().GetEntryCount());
1509
1510  // Show interstitial.
1511  TestInterstitialPage::InterstitialState state =
1512      TestInterstitialPage::INVALID;
1513  bool deleted = false;
1514  GURL interstitial_url("http://interstitial");
1515  TestInterstitialPage* interstitial =
1516      new TestInterstitialPage(contents(), true, interstitial_url,
1517                               &state, &deleted);
1518  TestInterstitialPageStateGuard state_guard(interstitial);
1519  interstitial->Show();
1520
1521  // Crash the renderer
1522  test_rvh()->OnMessageReceived(
1523      ViewHostMsg_RenderViewGone(
1524          0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1525
1526  interstitial->TestDidNavigate(2, interstitial_url);
1527}
1528
1529// Test navigating to a page that shows an interstitial, then close the
1530// contents.
1531TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1532  // Show interstitial.
1533  TestInterstitialPage::InterstitialState state =
1534      TestInterstitialPage::INVALID;
1535  bool deleted = false;
1536  GURL url("http://interstitial");
1537  TestInterstitialPage* interstitial =
1538      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1539  TestInterstitialPageStateGuard state_guard(interstitial);
1540  interstitial->Show();
1541  interstitial->TestDidNavigate(1, url);
1542
1543  // Now close the contents.
1544  DeleteContents();
1545  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1546
1547  RunAllPendingInMessageLoop();
1548  EXPECT_TRUE(deleted);
1549}
1550
1551// Test navigating to a page that shows an interstitial, then close the
1552// contents.
1553TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1554  // Show interstitial.
1555  TestInterstitialPage::InterstitialState state =
1556      TestInterstitialPage::INVALID;
1557  bool deleted = false;
1558  GURL url("http://interstitial");
1559  TestInterstitialPage* interstitial =
1560      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1561  TestInterstitialPageStateGuard state_guard(interstitial);
1562  interstitial->Show();
1563  interstitial->TestDidNavigate(1, url);
1564  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1565      interstitial->GetRenderViewHostForTesting());
1566
1567  // Now close the contents.
1568  DeleteContents();
1569  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1570
1571  // Before the interstitial has a chance to process its shutdown task,
1572  // simulate quitting the browser.  This goes through all processes and
1573  // tells them to destruct.
1574  rvh->OnMessageReceived(
1575        ViewHostMsg_RenderViewGone(0, 0, 0));
1576
1577  RunAllPendingInMessageLoop();
1578  EXPECT_TRUE(deleted);
1579}
1580
1581// Test that after Proceed is called and an interstitial is still shown, no more
1582// commands get executed.
1583TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1584  // Navigate to a page so we have a navigation entry in the controller.
1585  GURL url1("http://www.google.com");
1586  test_rvh()->SendNavigate(1, url1);
1587  EXPECT_EQ(1, controller().GetEntryCount());
1588
1589  // Show an interstitial.
1590  TestInterstitialPage::InterstitialState state =
1591      TestInterstitialPage::INVALID;
1592  bool deleted = false;
1593  GURL url2("http://interstitial");
1594  TestInterstitialPage* interstitial =
1595      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1596  TestInterstitialPageStateGuard state_guard(interstitial);
1597  interstitial->Show();
1598  interstitial->TestDidNavigate(1, url2);
1599
1600  // Run a command.
1601  EXPECT_EQ(0, interstitial->command_received_count());
1602  interstitial->TestDomOperationResponse("toto");
1603  EXPECT_EQ(1, interstitial->command_received_count());
1604
1605  // Then proceed.
1606  interstitial->Proceed();
1607  RunAllPendingInMessageLoop();
1608  ASSERT_FALSE(deleted);
1609
1610  // While the navigation to the new page is pending, send other commands, they
1611  // should be ignored.
1612  interstitial->TestDomOperationResponse("hello");
1613  interstitial->TestDomOperationResponse("hi");
1614  EXPECT_EQ(1, interstitial->command_received_count());
1615}
1616
1617// Test showing an interstitial while another interstitial is already showing.
1618TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1619  // Navigate to a page so we have a navigation entry in the controller.
1620  GURL start_url("http://www.google.com");
1621  test_rvh()->SendNavigate(1, start_url);
1622  EXPECT_EQ(1, controller().GetEntryCount());
1623
1624  // Show an interstitial.
1625  TestInterstitialPage::InterstitialState state1 =
1626      TestInterstitialPage::INVALID;
1627  bool deleted1 = false;
1628  GURL url1("http://interstitial1");
1629  TestInterstitialPage* interstitial1 =
1630      new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1631  TestInterstitialPageStateGuard state_guard1(interstitial1);
1632  interstitial1->Show();
1633  interstitial1->TestDidNavigate(1, url1);
1634
1635  // Now show another interstitial.
1636  TestInterstitialPage::InterstitialState state2 =
1637      TestInterstitialPage::INVALID;
1638  bool deleted2 = false;
1639  GURL url2("http://interstitial2");
1640  TestInterstitialPage* interstitial2 =
1641      new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1642  TestInterstitialPageStateGuard state_guard2(interstitial2);
1643  interstitial2->Show();
1644  interstitial2->TestDidNavigate(1, url2);
1645
1646  // Showing interstitial2 should have caused interstitial1 to go away.
1647  EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1648  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1649
1650  RunAllPendingInMessageLoop();
1651  EXPECT_TRUE(deleted1);
1652  ASSERT_FALSE(deleted2);
1653
1654  // Let's make sure interstitial2 is working as intended.
1655  interstitial2->Proceed();
1656  GURL landing_url("http://www.thepage.com");
1657  test_rvh()->SendNavigate(2, landing_url);
1658
1659  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1660  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1661  NavigationEntry* entry = controller().GetActiveEntry();
1662  ASSERT_TRUE(entry != NULL);
1663  EXPECT_TRUE(entry->GetURL() == landing_url);
1664  EXPECT_EQ(2, controller().GetEntryCount());
1665  RunAllPendingInMessageLoop();
1666  EXPECT_TRUE(deleted2);
1667}
1668
1669// Test showing an interstitial, proceeding and then navigating to another
1670// interstitial.
1671TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1672  // Navigate to a page so we have a navigation entry in the controller.
1673  GURL start_url("http://www.google.com");
1674  test_rvh()->SendNavigate(1, start_url);
1675  EXPECT_EQ(1, controller().GetEntryCount());
1676
1677  // Show an interstitial.
1678  TestInterstitialPage::InterstitialState state1 =
1679      TestInterstitialPage::INVALID;
1680  bool deleted1 = false;
1681  GURL url1("http://interstitial1");
1682  TestInterstitialPage* interstitial1 =
1683      new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1684  TestInterstitialPageStateGuard state_guard1(interstitial1);
1685  interstitial1->Show();
1686  interstitial1->TestDidNavigate(1, url1);
1687
1688  // Take action.  The interstitial won't be hidden until the navigation is
1689  // committed.
1690  interstitial1->Proceed();
1691  EXPECT_EQ(TestInterstitialPage::OKED, state1);
1692
1693  // Now show another interstitial (simulating the navigation causing another
1694  // interstitial).
1695  TestInterstitialPage::InterstitialState state2 =
1696      TestInterstitialPage::INVALID;
1697  bool deleted2 = false;
1698  GURL url2("http://interstitial2");
1699  TestInterstitialPage* interstitial2 =
1700      new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1701  TestInterstitialPageStateGuard state_guard2(interstitial2);
1702  interstitial2->Show();
1703  interstitial2->TestDidNavigate(1, url2);
1704
1705  // Showing interstitial2 should have caused interstitial1 to go away.
1706  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1707  RunAllPendingInMessageLoop();
1708  EXPECT_TRUE(deleted1);
1709  ASSERT_FALSE(deleted2);
1710
1711  // Let's make sure interstitial2 is working as intended.
1712  interstitial2->Proceed();
1713  GURL landing_url("http://www.thepage.com");
1714  test_rvh()->SendNavigate(2, landing_url);
1715
1716  RunAllPendingInMessageLoop();
1717  EXPECT_TRUE(deleted2);
1718  EXPECT_FALSE(contents()->ShowingInterstitialPage());
1719  EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1720  NavigationEntry* entry = controller().GetActiveEntry();
1721  ASSERT_TRUE(entry != NULL);
1722  EXPECT_TRUE(entry->GetURL() == landing_url);
1723  EXPECT_EQ(2, controller().GetEntryCount());
1724}
1725
1726// Test that navigating away from an interstitial while it's loading cause it
1727// not to show.
1728TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
1729  // Show an interstitial.
1730  TestInterstitialPage::InterstitialState state =
1731      TestInterstitialPage::INVALID;
1732  bool deleted = false;
1733  GURL interstitial_url("http://interstitial");
1734  TestInterstitialPage* interstitial =
1735      new TestInterstitialPage(contents(), true, interstitial_url,
1736                               &state, &deleted);
1737  TestInterstitialPageStateGuard state_guard(interstitial);
1738  interstitial->Show();
1739
1740  // Let's simulate a navigation initiated from the browser before the
1741  // interstitial finishes loading.
1742  const GURL url("http://www.google.com");
1743  controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1744  EXPECT_FALSE(interstitial->is_showing());
1745  RunAllPendingInMessageLoop();
1746  ASSERT_FALSE(deleted);
1747
1748  // Now let's make the interstitial navigation commit.
1749  interstitial->TestDidNavigate(1, interstitial_url);
1750
1751  // After it loaded the interstitial should be gone.
1752  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1753
1754  RunAllPendingInMessageLoop();
1755  EXPECT_TRUE(deleted);
1756}
1757
1758// Test that a new request to show an interstitial while an interstitial is
1759// pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
1760TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
1761  GURL interstitial_url("http://interstitial");
1762
1763  // Show a first interstitial.
1764  TestInterstitialPage::InterstitialState state1 =
1765      TestInterstitialPage::INVALID;
1766  bool deleted1 = false;
1767  TestInterstitialPage* interstitial1 =
1768      new TestInterstitialPage(contents(), true, interstitial_url,
1769                               &state1, &deleted1);
1770  TestInterstitialPageStateGuard state_guard1(interstitial1);
1771  interstitial1->Show();
1772
1773  // Show another interstitial on that same contents before the first one had
1774  // time to load.
1775  TestInterstitialPage::InterstitialState state2 =
1776      TestInterstitialPage::INVALID;
1777  bool deleted2 = false;
1778  TestInterstitialPage* interstitial2 =
1779      new TestInterstitialPage(contents(), true, interstitial_url,
1780                               &state2, &deleted2);
1781  TestInterstitialPageStateGuard state_guard2(interstitial2);
1782  interstitial2->Show();
1783
1784  // The first interstitial should have been closed and deleted.
1785  EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1786  // The 2nd one should still be OK.
1787  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1788
1789  RunAllPendingInMessageLoop();
1790  EXPECT_TRUE(deleted1);
1791  ASSERT_FALSE(deleted2);
1792
1793  // Make the interstitial navigation commit it should be showing.
1794  interstitial2->TestDidNavigate(1, interstitial_url);
1795  EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
1796}
1797
1798// Test showing an interstitial and have its renderer crash.
1799TEST_F(WebContentsImplTest, InterstitialCrasher) {
1800  // Show an interstitial.
1801  TestInterstitialPage::InterstitialState state =
1802      TestInterstitialPage::INVALID;
1803  bool deleted = false;
1804  GURL url("http://interstitial");
1805  TestInterstitialPage* interstitial =
1806      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1807  TestInterstitialPageStateGuard state_guard(interstitial);
1808  interstitial->Show();
1809  // Simulate a renderer crash before the interstitial is shown.
1810  interstitial->TestRenderViewTerminated(
1811      base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1812  // The interstitial should have been dismissed.
1813  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1814  RunAllPendingInMessageLoop();
1815  EXPECT_TRUE(deleted);
1816
1817  // Now try again but this time crash the intersitial after it was shown.
1818  interstitial =
1819      new TestInterstitialPage(contents(), true, url, &state, &deleted);
1820  interstitial->Show();
1821  interstitial->TestDidNavigate(1, url);
1822  // Simulate a renderer crash.
1823  interstitial->TestRenderViewTerminated(
1824      base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1825  // The interstitial should have been dismissed.
1826  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1827  RunAllPendingInMessageLoop();
1828  EXPECT_TRUE(deleted);
1829}
1830
1831// Tests that showing an interstitial as a result of a browser initiated
1832// navigation while an interstitial is showing does not remove the pending
1833// entry (see http://crbug.com/9791).
1834TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
1835  const char kUrl[] = "http://www.badguys.com/";
1836  const GURL kGURL(kUrl);
1837
1838  // Start a navigation to a page
1839  contents()->GetController().LoadURL(
1840      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1841
1842  // Simulate that navigation triggering an interstitial.
1843  TestInterstitialPage::InterstitialState state =
1844      TestInterstitialPage::INVALID;
1845  bool deleted = false;
1846  TestInterstitialPage* interstitial =
1847      new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
1848  TestInterstitialPageStateGuard state_guard(interstitial);
1849  interstitial->Show();
1850  interstitial->TestDidNavigate(1, kGURL);
1851
1852  // Initiate a new navigation from the browser that also triggers an
1853  // interstitial.
1854  contents()->GetController().LoadURL(
1855      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1856  TestInterstitialPage::InterstitialState state2 =
1857      TestInterstitialPage::INVALID;
1858  bool deleted2 = false;
1859  TestInterstitialPage* interstitial2 =
1860      new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
1861  TestInterstitialPageStateGuard state_guard2(interstitial2);
1862  interstitial2->Show();
1863  interstitial2->TestDidNavigate(1, kGURL);
1864
1865  // Make sure we still have an entry.
1866  NavigationEntry* entry = contents()->GetController().GetPendingEntry();
1867  ASSERT_TRUE(entry);
1868  EXPECT_EQ(kUrl, entry->GetURL().spec());
1869
1870  // And that the first interstitial is gone, but not the second.
1871  EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1872  EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1873  RunAllPendingInMessageLoop();
1874  EXPECT_TRUE(deleted);
1875  EXPECT_FALSE(deleted2);
1876}
1877
1878// Tests that Javascript messages are not shown while an interstitial is
1879// showing.
1880TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
1881  const char kUrl[] = "http://www.badguys.com/";
1882  const GURL kGURL(kUrl);
1883
1884  // Start a navigation to a page
1885  contents()->GetController().LoadURL(
1886      kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1887  // DidNavigate from the page
1888  contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
1889
1890  // Simulate showing an interstitial while the page is showing.
1891  TestInterstitialPage::InterstitialState state =
1892      TestInterstitialPage::INVALID;
1893  bool deleted = false;
1894  TestInterstitialPage* interstitial =
1895      new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
1896  TestInterstitialPageStateGuard state_guard(interstitial);
1897  interstitial->Show();
1898  interstitial->TestDidNavigate(1, kGURL);
1899
1900  // While the interstitial is showing, let's simulate the hidden page
1901  // attempting to show a JS message.
1902  IPC::Message* dummy_message = new IPC::Message;
1903  bool did_suppress_message = false;
1904  contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
1905      ASCIIToUTF16("This is an informative message"), ASCIIToUTF16("OK"),
1906      kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
1907      &did_suppress_message);
1908  EXPECT_TRUE(did_suppress_message);
1909}
1910
1911// Makes sure that if the source passed to CopyStateFromAndPrune has an
1912// interstitial it isn't copied over to the destination.
1913TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
1914  // Navigate to a page.
1915  GURL url1("http://www.google.com");
1916  test_rvh()->SendNavigate(1, url1);
1917  EXPECT_EQ(1, controller().GetEntryCount());
1918
1919  // Initiate a browser navigation that will trigger the interstitial
1920  controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1921                        PAGE_TRANSITION_TYPED, std::string());
1922
1923  // Show an interstitial.
1924  TestInterstitialPage::InterstitialState state =
1925      TestInterstitialPage::INVALID;
1926  bool deleted = false;
1927  GURL url2("http://interstitial");
1928  TestInterstitialPage* interstitial =
1929      new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1930  TestInterstitialPageStateGuard state_guard(interstitial);
1931  interstitial->Show();
1932  interstitial->TestDidNavigate(1, url2);
1933  EXPECT_TRUE(interstitial->is_showing());
1934  EXPECT_EQ(2, controller().GetEntryCount());
1935
1936  // Create another NavigationController.
1937  GURL url3("http://foo2");
1938  scoped_ptr<TestWebContents> other_contents(
1939      static_cast<TestWebContents*>(CreateTestWebContents()));
1940  NavigationControllerImpl& other_controller = other_contents->GetController();
1941  other_contents->NavigateAndCommit(url3);
1942  other_contents->ExpectSetHistoryLengthAndPrune(
1943      NavigationEntryImpl::FromNavigationEntry(
1944          other_controller.GetEntryAtIndex(0))->site_instance(), 1,
1945      other_controller.GetEntryAtIndex(0)->GetPageID());
1946  other_controller.CopyStateFromAndPrune(&controller());
1947
1948  // The merged controller should only have two entries: url1 and url2.
1949  ASSERT_EQ(2, other_controller.GetEntryCount());
1950  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
1951  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
1952  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
1953
1954  // And the merged controller shouldn't be showing an interstitial.
1955  EXPECT_FALSE(other_contents->ShowingInterstitialPage());
1956}
1957
1958// Makes sure that CopyStateFromAndPrune does the right thing if the object
1959// CopyStateFromAndPrune is invoked on is showing an interstitial.
1960TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
1961  // Navigate to a page.
1962  GURL url1("http://www.google.com");
1963  contents()->NavigateAndCommit(url1);
1964
1965  // Create another NavigationController.
1966  scoped_ptr<TestWebContents> other_contents(
1967      static_cast<TestWebContents*>(CreateTestWebContents()));
1968  NavigationControllerImpl& other_controller = other_contents->GetController();
1969
1970  // Navigate it to url2.
1971  GURL url2("http://foo2");
1972  other_contents->NavigateAndCommit(url2);
1973
1974  // Show an interstitial.
1975  TestInterstitialPage::InterstitialState state =
1976      TestInterstitialPage::INVALID;
1977  bool deleted = false;
1978  GURL url3("http://interstitial");
1979  TestInterstitialPage* interstitial =
1980      new TestInterstitialPage(other_contents.get(), true, url3, &state,
1981                               &deleted);
1982  TestInterstitialPageStateGuard state_guard(interstitial);
1983  interstitial->Show();
1984  interstitial->TestDidNavigate(1, url3);
1985  EXPECT_TRUE(interstitial->is_showing());
1986  EXPECT_EQ(2, other_controller.GetEntryCount());
1987  other_contents->ExpectSetHistoryLengthAndPrune(
1988      NavigationEntryImpl::FromNavigationEntry(
1989          other_controller.GetEntryAtIndex(0))->site_instance(), 1,
1990      other_controller.GetEntryAtIndex(0)->GetPageID());
1991  other_controller.CopyStateFromAndPrune(&controller());
1992
1993  // The merged controller should only have two entries: url1 and url2.
1994  ASSERT_EQ(2, other_controller.GetEntryCount());
1995  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
1996  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
1997  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
1998
1999  // It should have a transient entry.
2000  EXPECT_TRUE(other_controller.GetTransientEntry());
2001
2002  // And the interstitial should be showing.
2003  EXPECT_TRUE(other_contents->ShowingInterstitialPage());
2004
2005  // And the interstitial should do a reload on don't proceed.
2006  EXPECT_TRUE(static_cast<InterstitialPageImpl*>(
2007      other_contents->GetInterstitialPage())->reload_on_dont_proceed());
2008}
2009
2010// Regression test for http://crbug.com/168611 - the URLs passed by the
2011// DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2012TEST_F(WebContentsImplTest, FilterURLs) {
2013  TestWebContentsObserver observer(contents());
2014
2015  // A navigation to about:whatever should always look like a navigation to
2016  // about:blank
2017  GURL url_normalized("about:blank");
2018  GURL url_from_ipc("about:whatever");
2019
2020  // We navigate the test WebContents to about:blank, since NavigateAndCommit
2021  // will use the given URL to create the NavigationEntry as well, and that
2022  // entry should contain the filtered URL.
2023  contents()->NavigateAndCommit(url_normalized);
2024
2025  // Check that an IPC with about:whatever is correctly normalized.
2026  contents()->TestDidFinishLoad(1, url_from_ipc, true);
2027
2028  EXPECT_EQ(url_normalized, observer.last_url());
2029
2030  // Create and navigate another WebContents.
2031  scoped_ptr<TestWebContents> other_contents(
2032      static_cast<TestWebContents*>(CreateTestWebContents()));
2033  TestWebContentsObserver other_observer(other_contents.get());
2034  other_contents->NavigateAndCommit(url_normalized);
2035
2036  // Check that an IPC with about:whatever is correctly normalized.
2037  other_contents->TestDidFailLoadWithError(
2038      1, url_from_ipc, true, 1, string16());
2039  EXPECT_EQ(url_normalized, other_observer.last_url());
2040}
2041
2042// Test that if a pending contents is deleted before it is shown, we don't
2043// crash.
2044TEST_F(WebContentsImplTest, PendingContents) {
2045  scoped_ptr<TestWebContents> other_contents(
2046      static_cast<TestWebContents*>(CreateTestWebContents()));
2047  contents()->AddPendingContents(other_contents.get());
2048  int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2049  other_contents.reset();
2050  EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2051}
2052
2053}  // namespace content
2054