Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / frame_host / frame_tree_browsertest.cc
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 "base/command_line.h"
6 #include "content/browser/frame_host/frame_tree.h"
7 #include "content/browser/frame_host/frame_tree_node.h"
8 #include "content/browser/renderer_host/render_view_host_impl.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/public/browser/notification_service.h"
11 #include "content/public/browser/notification_types.h"
12 #include "content/public/common/content_switches.h"
13 #include "content/public/common/url_constants.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test.h"
16 #include "content/public/test/content_browser_test_utils.h"
17 #include "content/public/test/test_navigation_observer.h"
18 #include "content/public/test/test_utils.h"
19 #include "content/shell/browser/shell.h"
20 #include "content/test/content_browser_test_utils_internal.h"
21 #include "net/dns/mock_host_resolver.h"
22
23 namespace content {
24
25 class FrameTreeBrowserTest : public ContentBrowserTest {
26  public:
27   FrameTreeBrowserTest() {}
28
29  private:
30   DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
31 };
32
33 // Ensures FrameTree correctly reflects page structure during navigations.
34 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
35   host_resolver()->AddRule("*", "127.0.0.1");
36   ASSERT_TRUE(test_server()->Start());
37
38   GURL base_url = test_server()->GetURL("files/site_isolation/");
39   GURL::Replacements replace_host;
40   std::string host_str("A.com");  // Must stay in scope with replace_host.
41   replace_host.SetHostStr(host_str);
42   base_url = base_url.ReplaceComponents(replace_host);
43
44   // Load doc without iframes. Verify FrameTree just has root.
45   // Frame tree:
46   //   Site-A Root
47   NavigateToURL(shell(), base_url.Resolve("blank.html"));
48   FrameTreeNode* root =
49       static_cast<WebContentsImpl*>(shell()->web_contents())->
50       GetFrameTree()->root();
51   EXPECT_EQ(0U, root->child_count());
52
53   // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
54   // Frame tree:
55   //   Site-A Root -- Site-A frame1
56   //              \-- Site-A frame2
57   WindowedNotificationObserver observer1(
58       content::NOTIFICATION_LOAD_STOP,
59       content::Source<NavigationController>(
60           &shell()->web_contents()->GetController()));
61   NavigateToURL(shell(), base_url.Resolve("frames-X-X.html"));
62   observer1.Wait();
63   ASSERT_EQ(2U, root->child_count());
64   EXPECT_EQ(0U, root->child_at(0)->child_count());
65   EXPECT_EQ(0U, root->child_at(1)->child_count());
66 }
67
68 // TODO(ajwong): Talk with nasko and merge this functionality with
69 // FrameTreeShape.
70 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
71   ASSERT_TRUE(test_server()->Start());
72   NavigateToURL(shell(),
73                 test_server()->GetURL("files/frame_tree/top.html"));
74
75   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
76   FrameTreeNode* root = wc->GetFrameTree()->root();
77
78   // Check that the root node is properly created.
79   ASSERT_EQ(3UL, root->child_count());
80   EXPECT_EQ(std::string(), root->frame_name());
81
82   ASSERT_EQ(2UL, root->child_at(0)->child_count());
83   EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
84
85   // Verify the deepest node exists and has the right name.
86   ASSERT_EQ(2UL, root->child_at(2)->child_count());
87   EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
88   EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
89   EXPECT_STREQ("3-1-name",
90       root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
91
92   // Navigate to about:blank, which should leave only the root node of the frame
93   // tree in the browser process.
94   NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
95
96   root = wc->GetFrameTree()->root();
97   EXPECT_EQ(0UL, root->child_count());
98   EXPECT_EQ(std::string(), root->frame_name());
99 }
100
101 // Test that we can navigate away if the previous renderer doesn't clean up its
102 // child frames.
103 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
104   ASSERT_TRUE(test_server()->Start());
105   NavigateToURL(shell(),
106                 test_server()->GetURL("files/frame_tree/top.html"));
107
108   // Ensure the view and frame are live.
109   RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
110   RenderFrameHostImpl* rfh =
111       static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
112   EXPECT_TRUE(rvh->IsRenderViewLive());
113   EXPECT_TRUE(rfh->IsRenderFrameLive());
114
115   // Crash the renderer so that it doesn't send any FrameDetached messages.
116   RenderProcessHostWatcher crash_observer(
117       shell()->web_contents(),
118       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
119   NavigateToURL(shell(), GURL(kChromeUICrashURL));
120   crash_observer.Wait();
121
122   // The frame tree should be cleared.
123   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
124   FrameTreeNode* root = wc->GetFrameTree()->root();
125   EXPECT_EQ(0UL, root->child_count());
126
127   // Ensure the view and frame aren't live anymore.
128   EXPECT_FALSE(rvh->IsRenderViewLive());
129   EXPECT_FALSE(rfh->IsRenderFrameLive());
130
131   // Navigate to a new URL.
132   GURL url(test_server()->GetURL("files/title1.html"));
133   NavigateToURL(shell(), url);
134   EXPECT_EQ(0UL, root->child_count());
135   EXPECT_EQ(url, root->current_url());
136
137   // Ensure the view and frame are live again.
138   EXPECT_TRUE(rvh->IsRenderViewLive());
139   EXPECT_TRUE(rfh->IsRenderFrameLive());
140 }
141
142 // Test that we can navigate away if the previous renderer doesn't clean up its
143 // child frames.
144 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
145   host_resolver()->AddRule("*", "127.0.0.1");
146   ASSERT_TRUE(test_server()->Start());
147
148   GURL base_url = test_server()->GetURL("files/site_isolation/");
149   GURL::Replacements replace_host;
150   std::string host_str("A.com");  // Must stay in scope with replace_host.
151   replace_host.SetHostStr(host_str);
152   base_url = base_url.ReplaceComponents(replace_host);
153
154   NavigateToURL(shell(),
155                 test_server()->GetURL("files/frame_tree/top.html"));
156
157   // Hang the renderer so that it doesn't send any FrameDetached messages.
158   // (This navigation will never complete, so don't wait for it.)
159   shell()->LoadURL(GURL(kChromeUIHangURL));
160
161   // Check that the frame tree still has children.
162   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
163   FrameTreeNode* root = wc->GetFrameTree()->root();
164   ASSERT_EQ(3UL, root->child_count());
165
166   // Navigate to a new URL.  We use LoadURL because NavigateToURL will try to
167   // wait for the previous navigation to stop.
168   TestNavigationObserver tab_observer(wc, 1);
169   shell()->LoadURL(base_url.Resolve("blank.html"));
170   tab_observer.Wait();
171
172   // The frame tree should now be cleared.
173   EXPECT_EQ(0UL, root->child_count());
174 }
175
176 // Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
177 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
178   host_resolver()->AddRule("*", "127.0.0.1");
179   ASSERT_TRUE(test_server()->Start());
180   GURL main_url(test_server()->GetURL("files/frame_tree/top.html"));
181   NavigateToURL(shell(), main_url);
182
183   // It is safe to obtain the root frame tree node here, as it doesn't change.
184   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
185                             ->GetFrameTree()->root();
186
187   // The root and subframe should each have a live RenderFrame.
188   EXPECT_TRUE(
189       root->current_frame_host()->render_view_host()->IsRenderViewLive());
190   EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
191   EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
192
193   // Load a same-site page into iframe and it should still be live.
194   GURL http_url(test_server()->GetURL("files/title1.html"));
195   NavigateFrameToURL(root->child_at(0), http_url);
196   EXPECT_TRUE(
197       root->current_frame_host()->render_view_host()->IsRenderViewLive());
198   EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
199   EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
200 }
201
202 class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
203  public:
204   CrossProcessFrameTreeBrowserTest() {}
205
206   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
207     command_line->AppendSwitch(switches::kSitePerProcess);
208   }
209
210  private:
211   DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
212 };
213
214 // Ensure that we can complete a cross-process subframe navigation.
215 #if defined(OS_ANDROID)
216 #define MAYBE_CreateCrossProcessSubframeProxies DISABLED_CreateCrossProcessSubframeProxies
217 #else
218 #define MAYBE_CreateCrossProcessSubframeProxies CreateCrossProcessSubframeProxies
219 #endif
220 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
221                        MAYBE_CreateCrossProcessSubframeProxies) {
222   host_resolver()->AddRule("*", "127.0.0.1");
223   ASSERT_TRUE(test_server()->Start());
224   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
225   NavigateToURL(shell(), main_url);
226
227   // It is safe to obtain the root frame tree node here, as it doesn't change.
228   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
229                             ->GetFrameTree()->root();
230
231   // There should not be a proxy for the root's own SiteInstance.
232   SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
233   EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
234
235   // Load same-site page into iframe.
236   GURL http_url(test_server()->GetURL("files/title1.html"));
237   NavigateFrameToURL(root->child_at(0), http_url);
238
239   // These must stay in scope with replace_host.
240   GURL::Replacements replace_host;
241   std::string foo_com("foo.com");
242
243   // Load cross-site page into iframe.
244   GURL cross_site_url(test_server()->GetURL("files/title2.html"));
245   replace_host.SetHostStr(foo_com);
246   cross_site_url = cross_site_url.ReplaceComponents(replace_host);
247   NavigateFrameToURL(root->child_at(0), cross_site_url);
248
249   // Ensure that we have created a new process for the subframe.
250   ASSERT_EQ(1U, root->child_count());
251   FrameTreeNode* child = root->child_at(0);
252   SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
253   RenderViewHost* rvh = child->current_frame_host()->render_view_host();
254   RenderProcessHost* rph = child->current_frame_host()->GetProcess();
255
256   EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
257   EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
258   EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
259
260   // Ensure that the root node has a proxy for the child node's SiteInstance.
261   EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
262
263   // Also ensure that the child has a proxy for the root node's SiteInstance.
264   EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
265
266   // The nodes should not have proxies for their own SiteInstance.
267   EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
268   EXPECT_FALSE(
269       child->render_manager()->GetRenderFrameProxyHost(child_instance));
270
271   // Ensure that the RenderViews and RenderFrames are all live.
272   EXPECT_TRUE(
273       root->current_frame_host()->render_view_host()->IsRenderViewLive());
274   EXPECT_TRUE(
275       child->current_frame_host()->render_view_host()->IsRenderViewLive());
276   EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
277   EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
278 }
279
280 }  // namespace content