blob: 8e426c5d26f6c8be2626396eb77bcc3bbbb61c33 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/frame_host/back_forward_cache.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
namespace content {
namespace {
// Test about the BackForwardCache.
class BackForwardCacheBrowserTest : public ContentBrowserTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
feature_list_.InitAndEnableFeature(features::kBackForwardCache);
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
}
WebContentsImpl* web_contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
RenderFrameHostImpl* current_frame_host() {
return web_contents()->GetFrameTree()->root()->current_frame_host();
}
private:
base::test::ScopedFeatureList feature_list_;
};
} // namespace
// Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Basic) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1) Navigate to A.
NavigateToURL(shell(), url_a);
RenderFrameHostImpl* rfh_a = current_frame_host();
RenderFrameDeletedObserver delete_rfh_a(rfh_a);
// 2) Navigate to B.
NavigateToURL(shell(), url_b);
RenderFrameHostImpl* rfh_b = current_frame_host();
RenderFrameDeletedObserver delete_rfh_b(rfh_b);
EXPECT_FALSE(delete_rfh_a.deleted());
EXPECT_TRUE(rfh_a->is_in_back_forward_cache());
EXPECT_FALSE(rfh_b->is_in_back_forward_cache());
// 3) Go back to A.
web_contents()->GetController().GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_FALSE(delete_rfh_a.deleted());
EXPECT_FALSE(delete_rfh_b.deleted());
EXPECT_EQ(rfh_a, current_frame_host());
EXPECT_FALSE(rfh_a->is_in_back_forward_cache());
EXPECT_TRUE(rfh_b->is_in_back_forward_cache());
}
// Navigate from A(B) to C and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicIframe) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
// 1) Navigate to A(B).
NavigateToURL(shell(), url_a);
RenderFrameHostImpl* rfh_a = current_frame_host();
RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
RenderFrameDeletedObserver delete_rfh_a(rfh_a);
RenderFrameDeletedObserver delete_rfh_b(rfh_b);
// 2) Navigate to C.
NavigateToURL(shell(), url_c);
RenderFrameHostImpl* rfh_c = current_frame_host();
RenderFrameDeletedObserver delete_rfh_c(rfh_c);
EXPECT_FALSE(delete_rfh_a.deleted());
EXPECT_FALSE(delete_rfh_b.deleted());
EXPECT_TRUE(rfh_a->is_in_back_forward_cache());
EXPECT_TRUE(rfh_b->is_in_back_forward_cache());
EXPECT_FALSE(rfh_c->is_in_back_forward_cache());
// 3) Go back to A(B).
web_contents()->GetController().GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_FALSE(delete_rfh_a.deleted());
EXPECT_FALSE(delete_rfh_b.deleted());
EXPECT_FALSE(delete_rfh_c.deleted());
EXPECT_EQ(rfh_a, current_frame_host());
EXPECT_FALSE(rfh_a->is_in_back_forward_cache());
EXPECT_FALSE(rfh_b->is_in_back_forward_cache());
EXPECT_TRUE(rfh_c->is_in_back_forward_cache());
}
// Ensure flushing the BackForwardCache works properly.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BackForwardCacheFlush) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1) Navigate to A.
NavigateToURL(shell(), url_a);
RenderFrameHostImpl* rfh_a = current_frame_host();
RenderFrameDeletedObserver delete_rfh_a(rfh_a);
// 2) Navigate to B.
NavigateToURL(shell(), url_b);
RenderFrameHostImpl* rfh_b = current_frame_host();
RenderFrameDeletedObserver delete_rfh_b(rfh_b);
EXPECT_FALSE(delete_rfh_a.deleted());
// 3) Flush A.
web_contents()->GetController().back_forward_cache().Flush();
EXPECT_TRUE(delete_rfh_a.deleted());
EXPECT_FALSE(delete_rfh_b.deleted());
// 4) Go back to a new A.
web_contents()->GetController().GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(delete_rfh_a.deleted());
EXPECT_FALSE(delete_rfh_b.deleted());
// 5) Flush B.
web_contents()->GetController().back_forward_cache().Flush();
EXPECT_TRUE(delete_rfh_b.deleted());
}
// Check the visible URL in the omnibox is properly updated when restoring a
// document from the BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VisibleURL) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1) Go to A.
NavigateToURL(shell(), url_a);
// 2) Go to B.
NavigateToURL(shell(), url_b);
// 3) Go back to A.
web_contents()->GetController().GoBack();
EXPECT_EQ(url_a, web_contents()->GetVisibleURL());
// 4) Go forward to B.
web_contents()->GetController().GoForward();
EXPECT_EQ(url_b, web_contents()->GetVisibleURL());
}
// Test documents are evicted from the BackForwardCache at some point.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheEviction) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
NavigateToURL(shell(), url_a); // BackForwardCache size is 0.
RenderFrameHostImpl* rfh_a = current_frame_host();
RenderFrameDeletedObserver delete_rfh_a(rfh_a);
NavigateToURL(shell(), url_b); // BackForwardCache size is 1.
RenderFrameHostImpl* rfh_b = current_frame_host();
RenderFrameDeletedObserver delete_rfh_b(rfh_b);
// The number of document the BackForwardCache can hold per tab.
static constexpr size_t kBackForwardCacheLimit = 3;
for (size_t i = 2; i < kBackForwardCacheLimit; ++i) {
NavigateToURL(shell(), i % 2 ? url_b : url_a);
// After |i+1| navigations, |i| documents went into the BackForwardCache.
// When |i| is greater than the BackForwardCache size limit, they are
// evicted:
EXPECT_EQ(i >= kBackForwardCacheLimit + 1, delete_rfh_a.deleted());
EXPECT_EQ(i >= kBackForwardCacheLimit + 2, delete_rfh_b.deleted());
}
}
} // namespace content