1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/frame_host/frame_tree.h"
6 #include "content/browser/frame_host/frame_tree_node.h"
7 #include "content/browser/renderer_host/render_view_host_impl.h"
8 #include "content/browser/web_contents/web_contents_impl.h"
9 #include "content/public/browser/notification_service.h"
10 #include "content/public/browser/notification_types.h"
11 #include "content/public/common/url_constants.h"
12 #include "content/public/test/browser_test_utils.h"
13 #include "content/public/test/content_browser_test.h"
14 #include "content/public/test/content_browser_test_utils.h"
15 #include "content/public/test/test_navigation_observer.h"
16 #include "content/public/test/test_utils.h"
17 #include "content/shell/browser/shell.h"
18 #include "net/dns/mock_host_resolver.h"
22 class FrameTreeBrowserTest
: public ContentBrowserTest
{
24 FrameTreeBrowserTest() {}
27 DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest
);
30 // Ensures FrameTree correctly reflects page structure during navigations.
31 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest
, FrameTreeShape
) {
32 host_resolver()->AddRule("*", "127.0.0.1");
33 ASSERT_TRUE(test_server()->Start());
35 GURL base_url
= test_server()->GetURL("files/site_isolation/");
36 GURL::Replacements replace_host
;
37 std::string
host_str("A.com"); // Must stay in scope with replace_host.
38 replace_host
.SetHostStr(host_str
);
39 base_url
= base_url
.ReplaceComponents(replace_host
);
41 // Load doc without iframes. Verify FrameTree just has root.
44 NavigateToURL(shell(), base_url
.Resolve("blank.html"));
46 static_cast<WebContentsImpl
*>(shell()->web_contents())->
47 GetFrameTree()->root();
48 EXPECT_EQ(0U, root
->child_count());
50 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
52 // Site-A Root -- Site-A frame1
54 WindowedNotificationObserver
observer1(
55 content::NOTIFICATION_LOAD_STOP
,
56 content::Source
<NavigationController
>(
57 &shell()->web_contents()->GetController()));
58 NavigateToURL(shell(), base_url
.Resolve("frames-X-X.html"));
60 ASSERT_EQ(2U, root
->child_count());
61 EXPECT_EQ(0U, root
->child_at(0)->child_count());
62 EXPECT_EQ(0U, root
->child_at(1)->child_count());
65 // TODO(ajwong): Talk with nasko and merge this functionality with
67 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest
, FrameTreeShape2
) {
68 ASSERT_TRUE(test_server()->Start());
69 NavigateToURL(shell(),
70 test_server()->GetURL("files/frame_tree/top.html"));
72 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
73 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
75 // Check that the root node is properly created.
76 ASSERT_EQ(3UL, root
->child_count());
77 EXPECT_EQ(std::string(), root
->frame_name());
79 ASSERT_EQ(2UL, root
->child_at(0)->child_count());
80 EXPECT_STREQ("1-1-name", root
->child_at(0)->frame_name().c_str());
82 // Verify the deepest node exists and has the right name.
83 ASSERT_EQ(2UL, root
->child_at(2)->child_count());
84 EXPECT_EQ(1UL, root
->child_at(2)->child_at(1)->child_count());
85 EXPECT_EQ(0UL, root
->child_at(2)->child_at(1)->child_at(0)->child_count());
86 EXPECT_STREQ("3-1-name",
87 root
->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
89 // Navigate to about:blank, which should leave only the root node of the frame
90 // tree in the browser process.
91 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
93 root
= wc
->GetFrameTree()->root();
94 EXPECT_EQ(0UL, root
->child_count());
95 EXPECT_EQ(std::string(), root
->frame_name());
98 // Test that we can navigate away if the previous renderer doesn't clean up its
100 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest
, FrameTreeAfterCrash
) {
101 ASSERT_TRUE(test_server()->Start());
102 NavigateToURL(shell(),
103 test_server()->GetURL("files/frame_tree/top.html"));
105 // Crash the renderer so that it doesn't send any FrameDetached messages.
106 RenderProcessHostWatcher
crash_observer(
107 shell()->web_contents(),
108 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
109 NavigateToURL(shell(), GURL(kChromeUICrashURL
));
110 crash_observer
.Wait();
112 // The frame tree should be cleared.
113 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
114 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
115 EXPECT_EQ(0UL, root
->child_count());
117 // Navigate to a new URL.
118 GURL
url(test_server()->GetURL("files/title1.html"));
119 NavigateToURL(shell(), url
);
120 EXPECT_EQ(0UL, root
->child_count());
121 EXPECT_EQ(url
, root
->current_url());
124 // Test that we can navigate away if the previous renderer doesn't clean up its
126 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest
, NavigateWithLeftoverFrames
) {
127 host_resolver()->AddRule("*", "127.0.0.1");
128 ASSERT_TRUE(test_server()->Start());
130 GURL base_url
= test_server()->GetURL("files/site_isolation/");
131 GURL::Replacements replace_host
;
132 std::string
host_str("A.com"); // Must stay in scope with replace_host.
133 replace_host
.SetHostStr(host_str
);
134 base_url
= base_url
.ReplaceComponents(replace_host
);
136 NavigateToURL(shell(),
137 test_server()->GetURL("files/frame_tree/top.html"));
139 // Hang the renderer so that it doesn't send any FrameDetached messages.
140 // (This navigation will never complete, so don't wait for it.)
141 shell()->LoadURL(GURL(kChromeUIHangURL
));
143 // Check that the frame tree still has children.
144 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
145 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
146 ASSERT_EQ(3UL, root
->child_count());
148 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
149 // wait for the previous navigation to stop.
150 TestNavigationObserver
tab_observer(wc
, 1);
151 shell()->LoadURL(base_url
.Resolve("blank.html"));
154 // The frame tree should now be cleared.
155 EXPECT_EQ(0UL, root
->child_count());
158 } // namespace content