blob: 54db18824e5b1b213fa60a4ddd712f6ec1eb7862 [file] [log] [blame]
// Copyright 2022 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 "content/browser/web_contents/web_contents_impl.h"
#include "content/common/content_navigation_policy.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/shell/common/shell_switches.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
namespace content {
class PerformanceTimelineBackForwardCacheRestorationBrowserTest
: public ContentBrowserTest {
protected:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
ContentBrowserTest::SetUpOnMainThread();
}
WebContentsImpl* web_contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
RenderFrameHostImpl* current_frame_host() {
return web_contents()->GetPrimaryFrameTree().root()->current_frame_host();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kEnableBlinkTestFeatures, "NavigationId");
command_line->AppendSwitch(switches::kExposeInternalsForTesting);
}
EvalJsResult GetBackForwardCacheRestorationEntriesByObserver() const {
std::string script = R"(
(
async ()=>Promise.all([entryTypesPromise, typePromise])
)();
)";
return EvalJs(shell(), script);
}
EvalJsResult GetDroppedEntriesCount() const {
std::string script = R"(
(
async ()=> {
let promise = new Promise(resolve=>{
new PerformanceObserver((list, observer, options) => {
resolve(options['droppedEntriesCount']);
}).observe({ type: 'back-forward-cache-restoration',
buffered: true });
});
return await promise;
}
)();
)";
return EvalJs(shell(), script);
}
EvalJsResult SetBackForwardCacheRestorationBufferSize(int size) const {
std::string script = R"(
internals.setBackForwardCacheRestorationBufferSize($1);
)";
script = content::JsReplace(script, size);
return EvalJs(shell(), script);
}
EvalJsResult RegisterPerformanceObservers(int max_size) const {
std::string script = R"(
let entryTypesEntries = [];
var entryTypesPromise = new Promise(resolve=>{
new PerformanceObserver((list) => {
const entries = list.getEntries().filter(
e => e.entryType == 'back-forward-cache-restoration').map(
e=>e.toJSON());;
if (entries.length > 0) {
entryTypesEntries = entryTypesEntries.concat(entries);
}
if(entryTypesEntries.length>=$1){
resolve(entryTypesEntries);
}
}).observe({ entryTypes: ['back-forward-cache-restoration'] });
});
let typeEntries = [];
var typePromise = new Promise(resolve=>{
new PerformanceObserver((list) => {
const entries = list.getEntries().filter(
e => e.entryType == 'back-forward-cache-restoration').map(
e=>e.toJSON());
if (entries.length > 0) {
typeEntries = typeEntries.concat(entries);
}
if(typeEntries.length>=$1){
resolve(typeEntries);
}
}).observe({type: 'back-forward-cache-restoration'});
});
)";
script = content::JsReplace(script, max_size);
return EvalJs(shell(), script);
}
void CheckEntry(const base::Value::List lst, int num_of_loops) const {
for (int i = 0; i < num_of_loops; i++) {
auto* dict = lst[i].GetIfDict();
EXPECT_TRUE(dict);
EXPECT_EQ("", *dict->FindString("name"));
EXPECT_EQ("back-forward-cache-restoration",
*dict->FindString("entryType"));
int expected_navigation_id =
i + 2; // Navigation id starts from 1. It get incremented before a
// BackForwardCacheRestoration instance is created.
EXPECT_EQ(expected_navigation_id, dict->FindInt("navigationId").value());
EXPECT_LE(dict->FindDouble("pageshowEventStart").value(),
dict->FindDouble("pageshowEventEnd").value());
}
}
};
IN_PROC_BROWSER_TEST_F(
PerformanceTimelineBackForwardCacheRestorationBrowserTest,
Create) {
if (!IsBackForwardCacheEnabled())
return;
ASSERT_TRUE(embedded_test_server()->Start());
const GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
const GURL url2(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
RenderFrameHostImplWrapper rfh(current_frame_host());
int buffer_size = 10;
int num_of_loops = 12;
SetBackForwardCacheRestorationBufferSize(buffer_size);
RegisterPerformanceObservers(num_of_loops);
for (int i = 0; i < num_of_loops; i++) {
// Navigate away
ASSERT_TRUE(NavigateToURL(shell(), url2));
// Verify `rfh` is stored in back/forward cache.
ASSERT_TRUE(rfh->IsInBackForwardCache());
// Navigate back.
ASSERT_TRUE(HistoryGoBack(web_contents()));
}
auto result = std::move(GetBackForwardCacheRestorationEntriesByObserver()
.ExtractList()
.GetList());
CheckEntry(std::move(result[0].GetList()), num_of_loops);
CheckEntry(std::move(result[1].GetList()), num_of_loops);
// Size of back forward restoration buffer is smaller than the number of back
// forward restoration instances expected by 2. Therefore the
// droppedEntriesCount is expected to be 2.
EXPECT_EQ(2, GetDroppedEntriesCount().ExtractInt());
}
} // namespace content