frame_tree_browsertest.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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.
4
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"
19
20namespace content {
21
22class FrameTreeBrowserTest : public ContentBrowserTest {
23 public:
24  FrameTreeBrowserTest() {}
25
26 private:
27  DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
28};
29
30// Ensures FrameTree correctly reflects page structure during navigations.
31IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
32  host_resolver()->AddRule("*", "127.0.0.1");
33  ASSERT_TRUE(test_server()->Start());
34
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);
40
41  // Load doc without iframes. Verify FrameTree just has root.
42  // Frame tree:
43  //   Site-A Root
44  NavigateToURL(shell(), base_url.Resolve("blank.html"));
45  FrameTreeNode* root =
46      static_cast<WebContentsImpl*>(shell()->web_contents())->
47      GetFrameTree()->root();
48  EXPECT_EQ(0U, root->child_count());
49
50  // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
51  // Frame tree:
52  //   Site-A Root -- Site-A frame1
53  //              \-- Site-A frame2
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"));
59  observer1.Wait();
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());
63}
64
65// TODO(ajwong): Talk with nasko and merge this functionality with
66// FrameTreeShape.
67IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
68  ASSERT_TRUE(test_server()->Start());
69  NavigateToURL(shell(),
70                test_server()->GetURL("files/frame_tree/top.html"));
71
72  WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
73  FrameTreeNode* root = wc->GetFrameTree()->root();
74
75  // Check that the root node is properly created.
76  ASSERT_EQ(3UL, root->child_count());
77  EXPECT_EQ(std::string(), root->frame_name());
78
79  ASSERT_EQ(2UL, root->child_at(0)->child_count());
80  EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
81
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());
88
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"));
92
93  root = wc->GetFrameTree()->root();
94  EXPECT_EQ(0UL, root->child_count());
95  EXPECT_EQ(std::string(), root->frame_name());
96}
97
98// Test that we can navigate away if the previous renderer doesn't clean up its
99// child frames.
100IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
101  ASSERT_TRUE(test_server()->Start());
102  NavigateToURL(shell(),
103                test_server()->GetURL("files/frame_tree/top.html"));
104
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();
111
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());
116
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());
122}
123
124// Test that we can navigate away if the previous renderer doesn't clean up its
125// child frames.
126IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
127  host_resolver()->AddRule("*", "127.0.0.1");
128  ASSERT_TRUE(test_server()->Start());
129
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);
135
136  NavigateToURL(shell(),
137                test_server()->GetURL("files/frame_tree/top.html"));
138
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));
142
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());
147
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"));
152  tab_observer.Wait();
153
154  // The frame tree should now be cleared.
155  EXPECT_EQ(0UL, root->child_count());
156}
157
158}  // namespace content
159