Home | History | Annotate | Download | only in frame_host
      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 
     20 namespace content {
     21 
     22 class 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.
     31 IN_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.
     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"));
     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.
    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"));
    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.
    126 IN_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