blob: 3b03a1f518891a267d89ea25c1033ce7cde670ba [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/notimplemented.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/to_string.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/renderer.mojom.h"
#include "content/public/test/browser_test.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/shell/browser/shell.h"
#include "net/base/features.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "third_party/blink/public/common/features.h"
#include "url/gurl.h"
#if !BUILDFLAG(IS_FUCHSIA)
namespace {
// See the definition of `v8::internal::ScriptCompileTimerScope::CacheBehaviour`
// in `v8/src/codegen/compiler.cc` for the correspondence.
int CacheBehaviourNameToInt(std::string_view name) {
if (name == "kProduceCodeCache") {
return 0;
}
if (name == "kHitIsolateCacheWhenNoCache") {
return 1;
}
if (name == "kConsumeCodeCache") {
return 2;
}
if (name == "kNoCacheBecauseScriptTooSmall") {
return 5;
}
if (name == "kNoCacheBecauseCacheTooCold") {
return 6;
}
if (name == "kHitIsolateCacheWhenProduceCodeCache") {
return 14;
}
if (name == "kHitIsolateCacheWhenConsumeCodeCache") {
return 15;
}
if (name == "kNoCacheBecauseInlineScriptCacheTooCold") {
return 22;
}
// TODO: Add other values if necessary.
NOTIMPLEMENTED();
return -1;
}
int GetProduceCacheCount(const base::HistogramTester& histogram_tester) {
return histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kProduceCodeCache")) +
histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kHitIsolateCacheWhenProduceCodeCache"));
}
int GetConsumeCacheCount(const base::HistogramTester& histogram_tester) {
return histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kConsumeCodeCache")) +
histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kHitIsolateCacheWhenConsumeCodeCache"));
}
} // namespace
namespace content {
class InlineScriptCodeCacheBrowserTestBase : public ContentBrowserTest {
public:
InlineScriptCodeCacheBrowserTestBase() = default;
protected:
void InitFeatures(bool use_persistent_cache,
const base::FieldTrialParams& extra_params) {
base::FieldTrialParams params = extra_params;
base::FieldTrialParams default_params = {{"timeout", "1s"}};
params.merge(default_params);
std::vector<base::test::FeatureRefAndParams> enabled_features = {
{net::features::kSplitCacheByNetworkIsolationKey, {}},
{net::features::kSplitCodeCacheByNetworkIsolationKey, {}},
{blink::features::kInlineScriptCache, params}};
std::vector<base::test::FeatureRef> disabled_features;
if (use_persistent_cache) {
enabled_features.push_back(
{blink::features::kUsePersistentCacheForCodeCache, {}});
} else {
disabled_features.push_back(
blink::features::kUsePersistentCacheForCodeCache);
}
scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features,
disabled_features);
}
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
IsolateAllSitesForTesting(command_line);
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&InlineScriptCodeCacheBrowserTestBase::RequestHandler,
base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
}
std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
const net::test_server::HttpRequest& request) {
GURL absolute_url = embedded_test_server()->GetURL(request.relative_url);
if (absolute_url.GetPath() == "/inline-script.html" ||
absolute_url.GetPath() == "/same-inline-script.html") {
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
std::string title = absolute_url.GetPath() == "/inline-script.html"
? "A Page"
: "A PageDifferent Page";
// Run a short, heavy script before the test script to warmup connection
// to the inline script cache backend.
std::string content =
base::StrCat({"<html><head><title>", title, "</title></head>",
"<body><script type='text/javascript'>",
GenerateUniqueHeavyJavascriptSource(),
"</script><script type='text/javascript'>",
GetCacheableLongStaticJavascriptSource(),
"</script></body></html>"});
http_response->set_content(content);
http_response->set_content_type("text/html");
return http_response;
}
if (absolute_url.GetPath() == "/default-cachehint.html" ||
absolute_url.GetPath() == "/eager-cachehint.html" ||
absolute_url.GetPath() == "/never-cachehint.html") {
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
std::string cachehint_value = "default";
if (absolute_url.GetPath() == "/eager-cachehint.html") {
cachehint_value = "eager";
} else if (absolute_url.GetPath() == "/never-cachehint.html") {
cachehint_value = "never";
}
std::string content = base::StrCat(
{"<html><head><title>Title</title></head><body>",
"<script type='text/javascript'>",
GenerateUniqueHeavyJavascriptSource(),
"</script><script type='text/javascript' cachehint='",
cachehint_value, "'>", GetCacheableLongStaticJavascriptSource(),
"</script></body></html>\n"});
http_response->set_content(content);
http_response->set_content_type("text/html");
return http_response;
}
if (absolute_url.GetPath() == "/short-inline-script.html") {
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
// HTML with a very short inline script.
std::string short_script = "/*short*/";
EXPECT_LT(short_script.length(),
blink::features::kInlineScriptCacheMinScriptLength.Get());
std::string content =
base::StrCat({"<html><head><title>Title</title></head><body>",
"<script type='text/javascript'>", short_script,
"</script></body></html>\n"});
http_response->set_content(content);
http_response->set_content_type("text/html");
return http_response;
}
if (absolute_url.GetPath() == "/empty.html") {
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
http_response->set_content("<html><body></body></html>");
http_response->set_content_type("text/html");
return http_response;
}
return nullptr;
}
void PurgeResourceCacheFromTheMainFrame() {
base::RunLoop loop;
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root()
->current_frame_host()
->GetProcess()
->GetRendererInterface()
->PurgeResourceCache(loop.QuitClosure());
loop.Run();
}
void LoadIframe(const GURL& url) {
EXPECT_TRUE(
ExecJs(shell()->web_contents(),
JsReplace("const iframe = document.createElement('iframe');"
"iframe.src = $1;"
"document.body.appendChild(iframe);",
url)));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
}
void PurgeResourceCacheFromTheFirstSubFrame() {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
CHECK(root->child_count() != 0);
base::RunLoop loop;
root->child_at(root->child_count() - 1)
->current_frame_host()
->GetProcess()
->GetRendererInterface()
->PurgeResourceCache(loop.QuitClosure());
loop.Run();
}
private:
std::string GenerateUniqueHeavyJavascriptSource() {
++served_count_;
// A time-consuming script to run.
std::string source =
base::StrCat({"const a=[...Array(10000000).keys()];let s=",
base::NumberToString(served_count_), ";",
"for(let i=0;i<a.length;i++)s+=i*(i+1)-a[i];"
"console.log(s);"});
EXPECT_LT(source.length(),
blink::features::kInlineScriptCacheMinScriptLength.Get());
return source;
}
// A script longer enough to be cached.
std::string GetCacheableLongStaticJavascriptSource() {
return base::StrCat(
{"function testFunction() {\n",
std::string(blink::features::kInlineScriptCacheMinScriptLength.Get(),
'/'),
"\nreturn 42;\n}"});
}
base::test::ScopedFeatureList scoped_feature_list_;
uint32_t served_count_ = 0;
};
class InlineScriptCodeCacheBrowserTest
: public InlineScriptCodeCacheBrowserTestBase,
public testing::WithParamInterface<bool> {
public:
InlineScriptCodeCacheBrowserTest() { InitFeatures(GetParam(), {}); }
};
INSTANTIATE_TEST_SUITE_P(All,
InlineScriptCodeCacheBrowserTest,
testing::Bool());
class InlineScriptCacheHintBrowserTest
: public InlineScriptCodeCacheBrowserTestBase,
public testing::WithParamInterface<std::tuple<bool, bool>> {
public:
InlineScriptCacheHintBrowserTest() {
bool use_persistent_cache = std::get<0>(GetParam());
bool enable_for_default_hint = std::get<1>(GetParam());
InitFeatures(use_persistent_cache,
{{"enable_for_default_hint",
enable_for_default_hint ? "true" : "false"}});
}
};
INSTANTIATE_TEST_SUITE_P(All,
InlineScriptCacheHintBrowserTest,
testing::Combine(testing::Bool(), testing::Bool()));
// TODO(crbug.com/498265776): Test is expected to time out on some slow
// builders.
#if defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
((BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)) && !defined(NDEBUG))
#define MAYBE_DefaultCacheHint DISABLED_DefaultCacheHint
#else
#define MAYBE_DefaultCacheHint DefaultCacheHint
#endif
IN_PROC_BROWSER_TEST_P(InlineScriptCacheHintBrowserTest,
MAYBE_DefaultCacheHint) {
GURL url =
embedded_test_server()->GetURL("example.com", "/default-cachehint.html");
// Step 1: Load the page first time.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
if (std::get<1>(GetParam())) {
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseInlineScriptCacheTooCold"),
1);
}
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 2: Reload to produce cache.
{
bool produced = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
if (GetProduceCacheCount(histogram_tester) == 1) {
produced = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
if (std::get<1>(GetParam())) {
EXPECT_TRUE(produced) << "Failed to produce cache";
} else {
EXPECT_FALSE(produced) << "Cache should not be produced";
}
}
}
// TODO(crbug.com/498265776): Test is expected to time out on some slow
// builders.
#if defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
(BUILDFLAG(IS_WIN) && !defined(NDEBUG))
#define MAYBE_EagerCacheHint DISABLED_EagerCacheHint
#else
#define MAYBE_EagerCacheHint EagerCacheHint
#endif
IN_PROC_BROWSER_TEST_P(InlineScriptCacheHintBrowserTest, MAYBE_EagerCacheHint) {
GURL url =
embedded_test_server()->GetURL("example.com", "/eager-cachehint.html");
// Step 1: Load the page first time.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseInlineScriptCacheTooCold"), 1);
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 2: Reload to produce cache.
{
bool produced = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
if (GetProduceCacheCount(histogram_tester) == 1) {
produced = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(produced) << "Failed to produce cache";
}
}
// TODO(crbug.com/498265776): Test is expected to time out on some slow
// builders.
#if defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
((BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)) && !defined(NDEBUG))
#define MAYBE_NeverCacheHint DISABLED_NeverCacheHint
#else
#define MAYBE_NeverCacheHint NeverCacheHint
#endif
IN_PROC_BROWSER_TEST_P(InlineScriptCacheHintBrowserTest, MAYBE_NeverCacheHint) {
GURL url =
embedded_test_server()->GetURL("example.com", "/never-cachehint.html");
// Load multiple times, expect NO cache produced.
const int num_tries = 3;
base::HistogramTester histogram_tester;
for (int i = 0; i < num_tries; i++) {
ASSERT_TRUE(NavigateToURL(shell(), url));
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
FetchHistogramsFromChildProcesses();
EXPECT_EQ(GetProduceCacheCount(histogram_tester), 0);
EXPECT_EQ(GetConsumeCacheCount(histogram_tester), 0);
}
// TODO(crbug.com/498265776): Test is failing on ChromeOS and Linux MSan.
// TODO(crbug.com/499507137): Disabled everywhere due to flakiness.
IN_PROC_BROWSER_TEST_P(InlineScriptCodeCacheBrowserTest,
DISABLED_CacheProducedOnSecondAttempt) {
GURL url =
embedded_test_server()->GetURL("example.com", "/inline-script.html");
// Step 1: Load the page first time. No cache is used.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseInlineScriptCacheTooCold"), 1);
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 2: Reload the page. The script will be compiled from source and then
// producing the cache to store it on persistent storage.
{
bool produced = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
if (GetProduceCacheCount(histogram_tester) == 1) {
produced = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(produced) << "Failed to produce cache";
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 3: Reload the page again. The script will be compiled from code cache.
{
bool consumed = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
if (GetConsumeCacheCount(histogram_tester) == 1) {
consumed = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(consumed) << "Failed to consume cache";
}
}
// TODO(crbug.com/498265776): Test is failing on ChromeOS and Linux MSan.
// TODO(crbug.com/499208353): Disabled everywhere for flakiness.
IN_PROC_BROWSER_TEST_P(InlineScriptCodeCacheBrowserTest,
DISABLED_CacheSharedOnDifferentPage) {
GURL url_1 =
embedded_test_server()->GetURL("example.com", "/inline-script.html");
GURL url_2 =
embedded_test_server()->GetURL("example.com", "/same-inline-script.html");
// Step 1: Load the page first time. No cache is used.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url_1));
FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseInlineScriptCacheTooCold"), 1);
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 2: Reload the page. The script will be compiled from source and then
// producing the cache to store it on persistent storage.
{
bool produced = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url_1));
FetchHistogramsFromChildProcesses();
if (GetProduceCacheCount(histogram_tester) == 1) {
produced = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(produced) << "Failed to produce cache";
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 3: Load the different URL with the same NIK and the same inline
// script. The script will be compiled from code cache.
{
bool consumed = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url_2));
FetchHistogramsFromChildProcesses();
if (GetConsumeCacheCount(histogram_tester) == 1) {
consumed = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(consumed) << "Failed to consume cache";
}
}
#if BUILDFLAG(IS_LINUX) && defined(MEMORY_SANITIZER)
// TODO(https://crbug.com/498800334): Flaky.
#define MAYBE_NotProducedForShortScript DISABLED_NotProducedForShortScript
#else
#define MAYBE_NotProducedForShortScript NotProducedForShortScript
#endif
IN_PROC_BROWSER_TEST_P(InlineScriptCodeCacheBrowserTest,
MAYBE_NotProducedForShortScript) {
// Even after multiple page loads, the code cache should not be produced for
// short scripts.
const int num_tries = 3;
base::HistogramTester histogram_tester;
for (int i = 0; i < num_tries; i++) {
// Use different query parameters so that BFCache would not work.
GURL url = embedded_test_server()->GetURL(
"example.com", base::StrCat({"/short-inline-script.html?i=",
base::NumberToString(i)}));
ASSERT_TRUE(NavigateToURL(shell(), url));
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseScriptTooSmall"), num_tries);
}
// TODO(crbug.com/498265776): Test is failing on ChromeOS and Linux MSan.
// TODO(crbug.com/499371224): Disabled everywhere for flakiness.
IN_PROC_BROWSER_TEST_P(InlineScriptCodeCacheBrowserTest,
DISABLED_IsolatedByNik) {
GURL top_domain_a =
embedded_test_server()->GetURL("a.example", "/empty.html");
GURL iframe_domain_b =
embedded_test_server()->GetURL("b.example", "/inline-script.html");
GURL top_domain_c =
embedded_test_server()->GetURL("c.example", "/empty.html");
// Step 1: Load top_domain_a and embed iframe_domain_b. Cache is cold.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), top_domain_a));
LoadIframe(iframe_domain_b);
FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseInlineScriptCacheTooCold"), 1);
}
PurgeResourceCacheFromTheMainFrame();
PurgeResourceCacheFromTheFirstSubFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 2: Reload the same setup (top A, iframe B). Cache should be produced
// or it could hit the Isolate cache if the process is reused.
{
bool produced = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), top_domain_a));
LoadIframe(iframe_domain_b);
FetchHistogramsFromChildProcesses();
if (GetProduceCacheCount(histogram_tester) == 1) {
produced = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
PurgeResourceCacheFromTheFirstSubFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(produced) << "Failed to produce cache";
}
PurgeResourceCacheFromTheMainFrame();
PurgeResourceCacheFromTheFirstSubFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 3: Load top_domain_c and embed iframe_domain_b.
// Since NIK splits cache, there should be no inline script cache created by
// domain A while it could hit the Isolate cache if the process is reused.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), top_domain_c));
LoadIframe(iframe_domain_b);
FetchHistogramsFromChildProcesses();
int no_cache_count =
histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt(
"kNoCacheBecauseInlineScriptCacheTooCold")) +
histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kHitIsolateCacheWhenNoCache"));
EXPECT_EQ(no_cache_count, 1);
}
}
// TODO(crbug.com/498265776): Test timed out on some slow builders like MSan,
// TSan, and Win 10 (dbg).
#if defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
(BUILDFLAG(IS_WIN) && !defined(NDEBUG))
#define MAYBE_ProducedCacheHitsOnAnotherProcess \
DISABLED_ProducedCacheHitsOnAnotherProcess
#else
#define MAYBE_ProducedCacheHitsOnAnotherProcess \
ProducedCacheHitsOnAnotherProcess
#endif
IN_PROC_BROWSER_TEST_P(InlineScriptCodeCacheBrowserTest,
MAYBE_ProducedCacheHitsOnAnotherProcess) {
GURL url = embedded_test_server()->GetURL("a.example", "/inline-script.html");
// Step 1: Load the page first time.
{
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kNoCacheBecauseInlineScriptCacheTooCold"), 1);
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Step 2: Reload the page to produce the cache.
{
bool produced = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
if (GetProduceCacheCount(histogram_tester) == 1) {
produced = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(produced) << "Failed to produce cache";
}
// Step 3: Try recreating the window to ensure the next load happens in a
// new renderer process. If fail, skip the step 4.
// TODO(crbug.com/512201557): Make sure to use another process or to clear
// every in-memory cache of the process for test reliability.
const ChildProcessId process_id_before_recreate =
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
RecreateWindow();
const ChildProcessId process_id_after_recreate =
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
if (process_id_before_recreate != process_id_after_recreate) {
// Step 4: Load the page again. Since it's a new process, it cannot hit the
// in-memory Isolate cache. It must strictly hit the persistent code cache.
bool consumed = false;
for (int i = 0; i < 5; i++) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(NavigateToURL(shell(), url));
FetchHistogramsFromChildProcesses();
const int persistent_consume_count = histogram_tester.GetBucketCount(
"V8.CompileScript.CacheBehaviour",
CacheBehaviourNameToInt("kConsumeCodeCache"));
if (persistent_consume_count == 1) {
consumed = true;
break;
}
PurgeResourceCacheFromTheMainFrame();
ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
}
EXPECT_TRUE(consumed) << "Failed to consume persistent code cache "
"(kConsumeCodeCache) in the new process.";
}
}
} // namespace content
#endif // !BUILDFLAG(IS_FUCHSIA)