Index: content/browser/frame_host/render_frame_host_manager_browsertest.cc |
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc |
index 9de16f8e9c0be905594f840c66bddc33e4f83358..aec9dac07487b881587c7c7623cf0a40b5503dfd 100644 |
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc |
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc |
@@ -35,6 +35,7 @@ |
#include "content/shell/browser/shell.h" |
#include "net/base/net_util.h" |
#include "net/dns/mock_host_resolver.h" |
+#include "net/test/embedded_test_server/embedded_test_server.h" |
#include "net/test/spawned_test_server/spawned_test_server.h" |
using base::ASCIIToUTF16; |
@@ -87,6 +88,13 @@ class RenderFrameHostManagerTest : public ContentBrowserTest { |
foo_host_port_.set_host(foo_com_); |
} |
+ void StartEmbeddedServer() { |
+ // Support multiple sites on the embedded test server. |
+ host_resolver()->AddRule("*", "127.0.0.1"); |
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
+ SetupCrossSiteRedirector(embedded_test_server()); |
+ } |
+ |
// Returns a URL on foo.com with the given path. |
GURL GetCrossSiteURL(const std::string& path) { |
GURL cross_site_url(test_server()->GetURL(path)); |
@@ -1722,4 +1730,80 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, |
shell()->web_contents()->GetRenderProcessHost()->GetID(), file)); |
} |
+// This class implements waiting for RenderFrameHost destruction. It relies on |
+// the fact that RenderFrameDeleted event is fired when RenderFrameHost is |
+// destroyed. |
+// Note: RenderFrameDeleted is also fired when the process associated with the |
+// RenderFrameHost crashes, so this cannot be used in cases where process dying |
+// is expected. |
+class RenderFrameHostDestructionObserver : public WebContentsObserver { |
+ public: |
+ explicit RenderFrameHostDestructionObserver(RenderFrameHost* rfh) |
+ : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)), |
+ message_loop_runner_(new MessageLoopRunner), |
+ deleted_(false), |
+ render_frame_host_(rfh) {} |
+ ~RenderFrameHostDestructionObserver() override {} |
+ |
+ void Wait() { |
+ if (deleted_) |
+ return; |
+ |
+ message_loop_runner_->Run(); |
+ } |
+ |
+ // WebContentsObserver implementation: |
+ void RenderFrameDeleted(RenderFrameHost* rfh) override { |
+ if (rfh == render_frame_host_) { |
+ CHECK(!deleted_); |
+ deleted_ = true; |
+ } |
+ |
+ if (deleted_ && message_loop_runner_->loop_running()) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, message_loop_runner_->QuitClosure()); |
+ } |
+ } |
+ |
+ private: |
+ scoped_refptr<MessageLoopRunner> message_loop_runner_; |
+ bool deleted_; |
+ RenderFrameHost* render_frame_host_; |
+}; |
+ |
+// Ensures that no RenderFrameHost/RenderViewHost objects are leaked when |
+// doing a simple cross-process navigation. |
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, |
+ CleanupOnCrossProcessNavigation) { |
+ StartEmbeddedServer(); |
+ |
+ // Do an initial navigation and capture objects we expect to be cleaned up |
+ // on cross-process navigation. |
+ GURL start_url = embedded_test_server()->GetURL("/title1.html"); |
+ NavigateToURL(shell(), start_url); |
+ |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ int32 orig_site_instance_id = |
+ root->current_frame_host()->GetSiteInstance()->GetId(); |
+ int initial_process_id = |
+ root->current_frame_host()->GetSiteInstance()->GetProcess()->GetID(); |
+ int initial_rfh_id = root->current_frame_host()->GetRoutingID(); |
+ int initial_rvh_id = |
+ root->current_frame_host()->render_view_host()->GetRoutingID(); |
+ |
+ // Navigate cross-process and ensure that cleanup is performed as expected. |
+ GURL cross_site_url = |
+ embedded_test_server()->GetURL("foo.com", "/title2.html"); |
+ RenderFrameHostDestructionObserver rfh_observer(root->current_frame_host()); |
+ NavigateToURL(shell(), cross_site_url); |
+ rfh_observer.Wait(); |
+ |
+ EXPECT_NE(orig_site_instance_id, |
+ root->current_frame_host()->GetSiteInstance()->GetId()); |
+ EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id, initial_rfh_id)); |
+ EXPECT_FALSE(RenderViewHost::FromID(initial_process_id, initial_rvh_id)); |
+} |
+ |
} // namespace content |