Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1522)

Unified Diff: content/browser/tab_contents/render_view_host_manager_unittest.cc

Issue 8587029: Fixed race-condition in RenderViewHost(Manager) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Uploaded with correct base branch Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/tab_contents/render_view_host_manager_unittest.cc
diff --git a/content/browser/tab_contents/render_view_host_manager_unittest.cc b/content/browser/tab_contents/render_view_host_manager_unittest.cc
index c2d7117f20aaf2e258f675d7530327dfd57c18a6..211fd487e33538c9198df90465b4714cddf7963b 100644
--- a/content/browser/tab_contents/render_view_host_manager_unittest.cc
+++ b/content/browser/tab_contents/render_view_host_manager_unittest.cc
@@ -272,6 +272,134 @@ TEST_F(RenderViewHostManagerTest, Navigate) {
content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
}
+// Tests the Navigate function. In this unit test we verify that the Navigate
+// function can handle a new navigation event before the previous navigation
+// has been committed. This is also a regression test for
+// http://crbug.com/104600.
+TEST_F(RenderViewHostManagerTest, NavigateWithEarlyReNavigation) {
+ TestNotificationTracker notifications;
+
+ SiteInstance* instance = SiteInstance::CreateSiteInstance(profile());
+
+ TestTabContents tab_contents(profile(), instance);
+ notifications.ListenFor(
+ content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+ content::Source<NavigationController>(&tab_contents.controller()));
+
+ // Create.
+ RenderViewHostManager manager(&tab_contents, &tab_contents);
+
+ manager.Init(profile(), instance, MSG_ROUTING_NONE);
+
+ // 1) The first navigation. --------------------------
+ const GURL kUrl1("http://www.google.com/");
+ NavigationEntry entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
+ GURL() /* referrer */, string16() /* title */,
+ content::PAGE_TRANSITION_TYPED,
+ false /* is_renderer_init */);
+ RenderViewHost* host = manager.Navigate(entry1);
+
+ // The RenderViewHost created in Init will be reused.
+ EXPECT_TRUE(host == manager.current_host());
+ EXPECT_FALSE(manager.pending_render_view_host());
+
+ // We should observe a notification.
+ EXPECT_TRUE(notifications.Check1AndReset(
+ content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+ notifications.Reset();
+
+ // Commit.
+ manager.DidNavigateMainFrame(host);
+
+ // Commit to SiteInstance should be delayed until RenderView commit.
+ EXPECT_TRUE(host == manager.current_host());
+ ASSERT_TRUE(host);
+ EXPECT_FALSE(host->site_instance()->has_site());
+ host->site_instance()->SetSite(kUrl1);
+
+ // 2) Cross-site navigate to next site. -------------------------
+ const GURL kUrl2("http://www.example.com");
+ NavigationEntry entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
+ GURL() /* referrer */, string16() /* title */,
+ content::PAGE_TRANSITION_TYPED,
+ false /* is_renderer_init */);
+ RenderViewHost* host2 = manager.Navigate(entry2);
+
+ // A new RenderViewHost should be created.
+ EXPECT_TRUE(manager.pending_render_view_host());
+ ASSERT_EQ(host2, manager.pending_render_view_host());
+
+ // Check that the navigation is still suspended because the old RVH
+ // is not swapped out, yet.
+ MockRenderProcessHost* test_process_host2 =
+ static_cast<MockRenderProcessHost*>(host2->process());
+ test_process_host2->sink().ClearMessages();
+ host2->NavigateToURL(kUrl2);
+ EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
+ ViewMsg_Navigate::ID));
+
+ // Allow closing the current Render View (precondition for swapping out
+ // the RVH): Simulate response from RenderView for ViewMsg_ShouldClose sent by
+ // FirePageBeforeUnload
+ TestRenderViewHost* test_host = static_cast<TestRenderViewHost*>(host);
+ MockRenderProcessHost* test_process_host =
+ static_cast<MockRenderProcessHost*>(test_host->process());
+ EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
+ ViewMsg_ShouldClose::ID));
+ test_host->SendShouldCloseACK(true);
+
+ // CrossSiteResourceHandler::StartCrossSiteTransition can trigger a
+ // call of RenderViewHostManager::OnCrossSiteResponse before
+ // RenderViewHostManager::DidNavigateMainFrame is called. In this case the
+ // RVH is swapped out.
+ manager.OnCrossSiteResponse(host2->process()->GetID(),
+ host2->GetPendingRequestId());
+ EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
+ ViewMsg_SwapOut::ID));
+ test_host->OnSwapOutACK();
+
+ EXPECT_EQ(host, manager.current_host());
+ EXPECT_TRUE(manager.current_host()->is_swapped_out());
+ EXPECT_EQ(host2, manager.pending_render_view_host());
+ // There should be still no navigation messages being sent.
+ EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
+ ViewMsg_Navigate::ID));
+
+ // 3) Cross-site navigate to next site before 2) has committed. --------------
+ const GURL kUrl3("http://webkit.org/");
+ NavigationEntry entry3(NULL /* instance */, -1 /* page_id */, kUrl3,
+ GURL() /* referrer */, string16() /* title */,
+ content::PAGE_TRANSITION_TYPED,
+ false /* is_renderer_init */);
+ RenderViewHost* host3 = manager.Navigate(entry3);
+
+ // A new RenderViewHost should be created.
+ EXPECT_TRUE(manager.pending_render_view_host());
+ ASSERT_EQ(host3, manager.pending_render_view_host());
+
+ // The navigation should not be suspended because the RVH host2 has been
Charlie Reis 2011/11/21 19:29:02 host2 isn't swapped out. It's the old pending RVH
battre 2011/11/21 20:59:45 Done.
+ // swapped out already. Therefore, the RVH should send a navigation event
+ // immediately.
+ MockRenderProcessHost* test_process_host3 =
+ static_cast<MockRenderProcessHost*>(host3->process());
+ test_process_host3->sink().ClearMessages();
+ host3->NavigateToURL(kUrl3);
Charlie Reis 2011/11/21 19:29:02 Since it's not obvious from reading the test, plea
battre 2011/11/21 20:59:45 Done.
+ EXPECT_TRUE(test_process_host3->sink().GetUniqueMessageMatching(
+ ViewMsg_Navigate::ID));
battre 2011/11/21 17:11:57 This expectation fails without the fix in render_v
+
+ // Commit.
+ manager.DidNavigateMainFrame(host3);
+ EXPECT_TRUE(host3 == manager.current_host());
+ ASSERT_TRUE(host3);
+ EXPECT_TRUE(host3->site_instance()->has_site());
+ // Check the pending RenderViewHost has been committed.
+ EXPECT_FALSE(manager.pending_render_view_host());
+
+ // We should observe a notification.
+ EXPECT_TRUE(notifications.Check1AndReset(
+ content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+}
+
// Tests WebUI creation.
TEST_F(RenderViewHostManagerTest, WebUI) {
BrowserThreadImpl ui_thread(BrowserThread::UI, MessageLoop::current());

Powered by Google App Engine
This is Rietveld 408576698