blob: 0fe54a914849b5ba4ad4166c76bf722b74c41903 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cmath>
#include <map>
#include <string>
#include <vector>
#include "base/containers/contains.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/test/task_environment.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/privacy_sandbox_features.h"
#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/shared_storage_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/fenced_frame/fenced_frame_utils.h"
#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h"
#include "url/url_constants.h"
namespace storage {
namespace {
constexpr char kSimpleTestHost[] = "a.test";
constexpr char kSimplePagePath[] = "/simple.html";
constexpr char kCrossOriginHost[] = "b.test";
constexpr char kThirdOriginHost[] = "c.test";
constexpr char kFourthOriginHost[] = "d.test";
constexpr char kRemainingBudgetPrefix[] = "remaining budget: ";
constexpr char kErrorTypeHistogram[] =
"Storage.SharedStorage.Worklet.Error.Type";
constexpr char kEntriesQueuedCountHistogram[] =
"Storage.SharedStorage.AsyncIterator.EntriesQueuedCount";
constexpr char kReceivedEntriesBenchmarksHistogram[] =
"Storage.SharedStorage.AsyncIterator.ReceivedEntriesBenchmarks";
constexpr char kIteratedEntriesBenchmarksHistogram[] =
"Storage.SharedStorage.AsyncIterator.IteratedEntriesBenchmarks";
constexpr char kTimingDocumentAddModuleHistogram[] =
"Storage.SharedStorage.Document.Timing.AddModule";
constexpr char kTimingDocumentRunHistogram[] =
"Storage.SharedStorage.Document.Timing.Run";
constexpr char kTimingDocumentSelectUrlHistogram[] =
"Storage.SharedStorage.Document.Timing.SelectURL";
constexpr char kTimingDocumentAppendHistogram[] =
"Storage.SharedStorage.Document.Timing.Append";
constexpr char kTimingDocumentSetHistogram[] =
"Storage.SharedStorage.Document.Timing.Set";
constexpr char kTimingDocumentDeleteHistogram[] =
"Storage.SharedStorage.Document.Timing.Delete";
constexpr char kTimingDocumentClearHistogram[] =
"Storage.SharedStorage.Document.Timing.Clear";
constexpr char kTimingWorkletAppendHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Append";
constexpr char kTimingWorkletSetHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Set";
constexpr char kTimingWorkletGetHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Get";
constexpr char kTimingWorkletLengthHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Length";
constexpr char kTimingWorkletDeleteHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Delete";
constexpr char kTimingWorkletClearHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Clear";
constexpr char kTimingWorkletKeysHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Keys.Next";
constexpr char kTimingWorkletEntriesHistogram[] =
"Storage.SharedStorage.Worklet.Timing.Entries.Next";
constexpr char kWorkletNumPerPageHistogram[] =
"Storage.SharedStorage.Worklet.NumPerPage";
constexpr char kTimingRemainingBudgetHistogram[] =
"Storage.SharedStorage.Worklet.Timing.RemainingBudget";
const double kBudgetAllowed = 5.0;
#if BUILDFLAG(IS_ANDROID)
base::FilePath GetChromeTestDataDir() {
return base::FilePath(FILE_PATH_LITERAL("chrome/test/data"));
}
#endif
// With `WebContentsConsoleObserver`, we can only wait for the last message in a
// group.
base::RepeatingCallback<
bool(const content::WebContentsConsoleObserver::Message& message)>
MakeFilter(std::vector<std::string> possible_last_messages) {
return base::BindRepeating(
[](std::vector<std::string> possible_last_messages,
const content::WebContentsConsoleObserver::Message& message) {
return base::Contains(possible_last_messages,
base::UTF16ToUTF8(message.message));
},
std::move(possible_last_messages));
}
std::string GetSharedStorageDisabledErrorMessage() {
return base::StrCat({"a JavaScript error: \"Error: ",
content::GetSharedStorageDisabledMessage(), "\"\n"});
}
void DelayBy(base::TimeDelta delta) {
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), delta);
run_loop.Run();
}
// TODO(cammie): Find a way to ensure that histograms are available at the
// necessary time without having to resort to sleeping/polling.
void WaitForHistograms(std::vector<std::string> histogram_names) {
while (true) {
content::FetchHistogramsFromChildProcesses();
metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
std::vector<std::string> still_waiting;
for (const auto& name : histogram_names) {
if (!base::StatisticsRecorder::FindHistogram(name))
still_waiting.push_back(name);
}
histogram_names = std::move(still_waiting);
if (histogram_names.empty())
break;
DelayBy(base::Seconds(1));
}
}
// Return the active RenderFrameHost loaded in the last iframe in `parent_rfh`.
content::RenderFrameHost* LastChild(content::RenderFrameHost* parent_rfh) {
int child_end = 0;
while (ChildFrameAt(parent_rfh, child_end))
child_end++;
if (child_end == 0)
return nullptr;
return ChildFrameAt(parent_rfh, child_end - 1);
}
// Create an <iframe> inside `parent_rfh`, and navigate it toward `url`.
// This returns the new RenderFrameHost associated with new document created in
// the iframe.
content::RenderFrameHost* CreateIframe(content::RenderFrameHost* parent_rfh,
const GURL& url) {
EXPECT_EQ("iframe loaded",
content::EvalJs(parent_rfh, content::JsReplace(R"(
new Promise((resolve) => {
const iframe = document.createElement("iframe");
iframe.src = $1;
iframe.onload = _ => { resolve("iframe loaded"); };
document.body.appendChild(iframe);
}))",
url)));
return LastChild(parent_rfh);
}
} // namespace
class SharedStorageChromeBrowserTest : public InProcessBrowserTest {
public:
SharedStorageChromeBrowserTest() {
base::test::TaskEnvironment task_environment;
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{blink::features::kSharedStorageAPI,
privacy_sandbox::kPrivacySandboxSettings3,
features::kPrivacySandboxAdsAPIsOverride},
/*disabled_features=*/{});
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
https_server()->AddDefaultHandlers(GetChromeTestDataDir());
https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
content::SetupCrossSiteRedirector(https_server());
CHECK(https_server()->Start());
InitPrefs();
}
~SharedStorageChromeBrowserTest() override = default;
net::EmbeddedTestServer* https_server() { return &https_server_; }
void SetPrefs(bool enable_privacy_sandbox, bool allow_third_party_cookies) {
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kPrivacySandboxApisEnabledV2, enable_privacy_sandbox);
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kPrivacySandboxManuallyControlledV2, enable_privacy_sandbox);
browser()->profile()->GetPrefs()->SetInteger(
prefs::kCookieControlsMode,
static_cast<int>(
allow_third_party_cookies
? content_settings::CookieControlsMode::kOff
: content_settings::CookieControlsMode::kBlockThirdParty));
}
// Virtual so derived classes can initialize differently. For the base class,
// enables Privacy Sandbox and allows 3P cookies.
virtual void InitPrefs() {
SetPrefs(/*enable_privacy_sandbox=*/true,
/*allow_third_party_cookies*/ true);
}
content::WebContents* GetActiveWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
void AddSimpleModule(const content::ToRenderFrameHost& execution_target) {
content::WebContentsConsoleObserver add_module_console_observer(
GetActiveWebContents());
add_module_console_observer.SetFilter(
MakeFilter({"Finish executing simple_module.js"}));
std::string host =
execution_target.render_frame_host()->GetLastCommittedOrigin().host();
GURL module_script_url =
https_server()->GetURL(host, "/shared_storage/simple_module.js");
EXPECT_TRUE(content::ExecJs(
execution_target,
content::JsReplace("sharedStorage.worklet.addModule($1)",
module_script_url)));
add_module_console_observer.Wait();
EXPECT_LE(1u,
content::GetAttachedSharedStorageWorkletHostsCount(
execution_target.render_frame_host()->GetStoragePartition()));
EXPECT_EQ(0u,
content::GetKeepAliveSharedStorageWorkletHostsCount(
execution_target.render_frame_host()->GetStoragePartition()));
EXPECT_EQ(1u, add_module_console_observer.messages().size());
EXPECT_EQ(
"Finish executing simple_module.js",
base::UTF16ToUTF8(add_module_console_observer.messages()[0].message));
}
bool ExecuteScriptInWorklet(
const content::ToRenderFrameHost& execution_target,
const std::string& script,
const std::string& last_script_message) {
content::WebContentsConsoleObserver add_module_console_observer(
GetActiveWebContents());
add_module_console_observer.SetFilter(
MakeFilter({"Finish executing customizable_module.js"}));
base::StringPairs run_function_body_replacement;
run_function_body_replacement.push_back(
std::make_pair("{{RUN_FUNCTION_BODY}}", script));
std::string host =
execution_target.render_frame_host()->GetLastCommittedOrigin().host();
GURL module_script_url = https_server()->GetURL(
host, net::test_server::GetFilePathWithReplacements(
"/shared_storage/customizable_module.js",
run_function_body_replacement));
EXPECT_TRUE(content::ExecJs(
execution_target,
content::JsReplace("sharedStorage.worklet.addModule($1)",
module_script_url)));
add_module_console_observer.Wait();
EXPECT_LE(1u,
content::GetAttachedSharedStorageWorkletHostsCount(
execution_target.render_frame_host()->GetStoragePartition()));
EXPECT_EQ(0u,
content::GetKeepAliveSharedStorageWorkletHostsCount(
execution_target.render_frame_host()->GetStoragePartition()));
EXPECT_EQ(1u, add_module_console_observer.messages().size());
EXPECT_EQ(
"Finish executing customizable_module.js",
base::UTF16ToUTF8(add_module_console_observer.messages()[0].message));
content::WebContentsConsoleObserver script_console_observer(
GetActiveWebContents());
script_console_observer.SetFilter(MakeFilter(
{last_script_message, content::GetSharedStorageDisabledMessage()}));
content::EvalJsResult result = content::EvalJs(execution_target, R"(
sharedStorage.run('test-operation');
)");
script_console_observer.Wait();
EXPECT_EQ(1u, script_console_observer.messages().size());
EXPECT_EQ(last_script_message,
base::UTF16ToUTF8(script_console_observer.messages()[0].message));
return result.error.empty();
}
double RemainingBudget(const content::ToRenderFrameHost& execution_target,
bool should_add_module = false) {
if (should_add_module)
AddSimpleModule(execution_target);
content::WebContentsConsoleObserver budget_console_observer(
GetActiveWebContents());
const std::string kRemainingBudgetPrefixStr(kRemainingBudgetPrefix);
budget_console_observer.SetPattern(
base::StrCat({kRemainingBudgetPrefixStr, "*"}));
EXPECT_TRUE(ExecJs(execution_target, R"(
sharedStorage.run('remaining-budget-operation', {data: {}});
)"));
budget_console_observer.Wait();
EXPECT_EQ(1u, budget_console_observer.messages().size());
std::string console_message =
base::UTF16ToUTF8(budget_console_observer.messages()[0].message);
EXPECT_TRUE(base::StartsWith(console_message, kRemainingBudgetPrefixStr));
std::string result_string = console_message.substr(
kRemainingBudgetPrefixStr.size(),
console_message.size() - kRemainingBudgetPrefixStr.size());
double result = 0.0;
EXPECT_TRUE(base::StringToDouble(result_string, &result));
return result;
}
protected:
base::HistogramTester histogram_tester_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
};
struct SharedStorageChromeBrowserParams {
bool enable_privacy_sandbox;
bool allow_third_party_cookies;
};
// Used by `testing::PrintToStringParamName()`.
std::string PrintToString(const SharedStorageChromeBrowserParams& p) {
return base::StrCat(
{"PrivacySandbox", p.enable_privacy_sandbox ? "Enabled" : "Disabled",
"_3PCookies", p.allow_third_party_cookies ? "Allowed" : "Blocked"});
}
std::vector<SharedStorageChromeBrowserParams>
GetSharedStorageChromeBrowserParams() {
return std::vector<SharedStorageChromeBrowserParams>(
{{true, true}, {true, false}, {false, true}, {false, false}});
}
class SharedStoragePrefBrowserTest
: public SharedStorageChromeBrowserTest,
public testing::WithParamInterface<SharedStorageChromeBrowserParams> {
public:
bool SuccessExpected() {
return GetParam().enable_privacy_sandbox &&
GetParam().allow_third_party_cookies;
}
// Sets prefs as parametrized.
void InitPrefs() override {
SetPrefs(GetParam().enable_privacy_sandbox,
GetParam().allow_third_party_cookies);
}
void AddSimpleModuleWithPermissionBypassed(
const content::ToRenderFrameHost& execution_target) {
content::WebContentsConsoleObserver add_module_console_observer(
GetActiveWebContents());
add_module_console_observer.SetFilter(
MakeFilter({"Finish executing simple_module.js"}));
// We allow Shared Storage for `addModule()`.
content::SetBypassIsSharedStorageAllowed(/*allow=*/true);
EXPECT_TRUE(content::ExecJs(execution_target, R"(
sharedStorage.worklet.addModule('shared_storage/simple_module.js');
)"));
add_module_console_observer.Wait();
// Shared Storage is enabled in order to `addModule()`.
EXPECT_EQ(1u, add_module_console_observer.messages().size());
EXPECT_EQ(
"Finish executing simple_module.js",
base::UTF16ToUTF8(add_module_console_observer.messages()[0].message));
content::SetBypassIsSharedStorageAllowed(/*allow=*/false);
}
bool ExecuteScriptInWorkletWithOuterPermissionsBypassed(
const content::ToRenderFrameHost& execution_target,
const std::string& script,
const std::string& last_script_message) {
content::WebContentsConsoleObserver add_module_console_observer(
GetActiveWebContents());
add_module_console_observer.SetFilter(
MakeFilter({"Finish executing customizable_module.js"}));
base::StringPairs run_function_body_replacement;
run_function_body_replacement.push_back(
std::make_pair("{{RUN_FUNCTION_BODY}}", script));
std::string host =
execution_target.render_frame_host()->GetLastCommittedOrigin().host();
GURL module_script_url = https_server()->GetURL(
host, net::test_server::GetFilePathWithReplacements(
"/shared_storage/customizable_module.js",
run_function_body_replacement));
// We allow Shared Storage for `addModule()` and `run()`, but any operations
// nested within the script run by `run()` will have preferences applied
// according to test parameters. When the latter disallow Shared Storage, it
// siumlates the situation where preferences are updated to block Shared
// Storage during the course of a previously allowed `run()` call.
content::SetBypassIsSharedStorageAllowed(/*allow=*/true);
EXPECT_TRUE(content::ExecJs(
execution_target,
content::JsReplace("sharedStorage.worklet.addModule($1)",
module_script_url)));
add_module_console_observer.Wait();
EXPECT_EQ(1u,
content::GetAttachedSharedStorageWorkletHostsCount(
execution_target.render_frame_host()->GetStoragePartition()));
EXPECT_EQ(0u,
content::GetKeepAliveSharedStorageWorkletHostsCount(
execution_target.render_frame_host()->GetStoragePartition()));
EXPECT_EQ(1u, add_module_console_observer.messages().size());
EXPECT_EQ(
"Finish executing customizable_module.js",
base::UTF16ToUTF8(add_module_console_observer.messages()[0].message));
WaitForHistograms({kTimingDocumentAddModuleHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
content::WebContentsConsoleObserver script_console_observer(
GetActiveWebContents());
script_console_observer.SetFilter(MakeFilter(
{last_script_message, content::GetSharedStorageDisabledMessage()}));
content::EvalJsResult result = content::EvalJs(execution_target, R"(
sharedStorage.run('test-operation');
)");
script_console_observer.Wait();
EXPECT_EQ(1u, script_console_observer.messages().size());
if (SuccessExpected()) {
EXPECT_EQ(
last_script_message,
base::UTF16ToUTF8(script_console_observer.messages()[0].message));
} else {
EXPECT_EQ(
content::GetSharedStorageDisabledMessage(),
base::UTF16ToUTF8(script_console_observer.messages()[0].message));
}
WaitForHistograms({kTimingDocumentRunHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
content::SetBypassIsSharedStorageAllowed(/*allow=*/false);
return result.error.empty();
}
};
INSTANTIATE_TEST_SUITE_P(
All,
SharedStoragePrefBrowserTest,
testing::ValuesIn(GetSharedStorageChromeBrowserParams()),
testing::PrintToStringParamName());
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, AddModule) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
content::WebContentsConsoleObserver console_observer(GetActiveWebContents());
console_observer.SetFilter(MakeFilter({"Finish executing simple_module.js"}));
content::EvalJsResult result = content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.worklet.addModule('shared_storage/simple_module.js');
)");
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ("a JavaScript error: \"Error: sharedStorage is disabled\"\n",
result.error);
EXPECT_EQ(0u, console_observer.messages().size());
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
return;
}
console_observer.Wait();
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(result.error.empty());
EXPECT_EQ(1u, console_observer.messages().size());
EXPECT_EQ("Finish executing simple_module.js",
base::UTF16ToUTF8(console_observer.messages()[0].message));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kTimingDocumentAddModuleHistogram, kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, RunOperation) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
AddSimpleModuleWithPermissionBypassed(GetActiveWebContents());
content::WebContentsConsoleObserver run_op_console_observer(
GetActiveWebContents());
run_op_console_observer.SetFilter(
MakeFilter({"Finish executing \'test-operation\'"}));
content::EvalJsResult run_op_result =
content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.run(
'test-operation', {data: {'customKey': 'customValue'}});
)");
WaitForHistograms({kTimingDocumentAddModuleHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ(GetSharedStorageDisabledErrorMessage(), run_op_result.error);
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kErrorTypeHistogram, kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
return;
}
run_op_console_observer.Wait();
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(run_op_result.error.empty());
EXPECT_EQ(1u, run_op_console_observer.messages().size());
EXPECT_EQ("Finish executing \'test-operation\'",
base::UTF16ToUTF8(run_op_console_observer.messages()[0].message));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, RunURLSelectionOperation) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
AddSimpleModuleWithPermissionBypassed(GetActiveWebContents());
content::WebContentsConsoleObserver run_url_op_console_observer(
GetActiveWebContents());
run_url_op_console_observer.SetFilter(
MakeFilter({"Finish executing \'test-url-selection-operation\'"}));
content::EvalJsResult run_url_op_result =
content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.selectURL(
'test-url-selection-operation',
[{url: "fenced_frames/title0.html"},
{url: "fenced_frames/title1.html",
reportingMetadata: {"click": "fenced_frames/report1.html"}},
{url: "fenced_frames/title2.html"}],
{data: {'mockResult': 1}});
)");
WaitForHistograms({kTimingDocumentAddModuleHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ(GetSharedStorageDisabledErrorMessage(), run_url_op_result.error);
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kErrorTypeHistogram, kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
return;
}
run_url_op_console_observer.Wait();
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(run_url_op_result.error.empty());
EXPECT_TRUE(
blink::IsValidUrnUuidURL(GURL(run_url_op_result.ExtractString())));
EXPECT_EQ(1u, run_url_op_console_observer.messages().size());
EXPECT_EQ(
"Finish executing \'test-url-selection-operation\'",
base::UTF16ToUTF8(run_url_op_console_observer.messages()[0].message));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram,
kTimingDocumentSelectUrlHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentSelectUrlHistogram, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, Set) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
content::EvalJsResult set_result = content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.set('customKey', 'customValue');
)");
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ(GetSharedStorageDisabledErrorMessage(), set_result.error);
return;
}
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(set_result.error.empty());
WaitForHistograms({kTimingDocumentSetHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentSetHistogram, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, Append) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
content::EvalJsResult append_result =
content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.append('customKey', 'customValue');
)");
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ(GetSharedStorageDisabledErrorMessage(), append_result.error);
return;
}
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(append_result.error.empty());
WaitForHistograms({kTimingDocumentAppendHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAppendHistogram, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, Delete) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
content::EvalJsResult delete_result =
content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.delete('customKey');
)");
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ(GetSharedStorageDisabledErrorMessage(), delete_result.error);
return;
}
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(delete_result.error.empty());
WaitForHistograms({kTimingDocumentDeleteHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentDeleteHistogram, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, Clear) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
content::EvalJsResult clear_result =
content::EvalJs(GetActiveWebContents(), R"(
sharedStorage.clear();
)");
if (!SuccessExpected()) {
// Shared Storage will be disabled.
EXPECT_EQ(GetSharedStorageDisabledErrorMessage(), clear_result.error);
return;
}
// Privacy Sandbox is enabled and 3P cookies are allowed, so Shared Storage
// should be allowed.
EXPECT_TRUE(clear_result.error.empty());
WaitForHistograms({kTimingDocumentClearHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentClearHistogram, 1);
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletSet) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `set()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
console.log(await sharedStorage.set('key0', 'value0'));
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletSetHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletSetHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletAppend) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `append()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
console.log(await sharedStorage.append('key0', 'value0'));
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletAppendHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletAppendHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletDelete) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `delete()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
console.log(await sharedStorage.delete('key0'));
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletDeleteHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletDeleteHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletClear) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `clear()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
console.log(await sharedStorage.clear());
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletClearHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletClearHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletGet) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// To prevent failure in the case where Shared Storage is enabled, we set a
// key before retrieving it; but in the case here we expect failure, we test
// only `get()` to isolate the behavior and determine if the promise is
// rejected solely from that call.
std::string script = SuccessExpected() ? R"(
console.log(await sharedStorage.set('key0', 'value0'));
console.log(await sharedStorage.get('key0'));
console.log('Finished script');
)"
: R"(
console.log(await sharedStorage.get('key0'));
console.log('Finished script');
)";
// If `get()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), script, "Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletSetHistogram, kTimingWorkletGetHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletSetHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletGetHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletKeys) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `keys()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
for await (const key of sharedStorage.keys()) {
console.log(key);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletKeysHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletKeysHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletEntries) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `entries()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
for await (const [key, value] of sharedStorage.entries()) {
console.log(key + ';' + value);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletEntriesHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletEntriesHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletLength) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
// If `length()` fails due to Shared Storage being disabled, there will be a
// console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
console.log(await sharedStorage.length());
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingWorkletLengthHistogram});
histogram_tester_.ExpectTotalCount(kTimingWorkletLengthHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, WorkletRemainingBudget) {
EXPECT_TRUE(content::NavigateToURL(
GetActiveWebContents(),
https_server()->GetURL(kSimpleTestHost, kSimplePagePath)));
// If `remainingBudget()` fails due to Shared Storage being disabled, there
// will be a console message verified in the helper
// `ExecuteScriptInWorkletWithOuterPermissionsBypassed()` rather than an error
// message since it is wrapped in a `console.log()` call.
EXPECT_TRUE(ExecuteScriptInWorkletWithOuterPermissionsBypassed(
GetActiveWebContents(), R"(
console.log(await sharedStorage.remainingBudget());
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kWorkletNumPerPageHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
if (SuccessExpected()) {
WaitForHistograms({kTimingRemainingBudgetHistogram});
histogram_tester_.ExpectTotalCount(kTimingRemainingBudgetHistogram, 1);
}
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
WorkletKeysEntries_AllIterated) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(ExecuteScriptInWorklet(GetActiveWebContents(), R"(
for (let i = 0; i < 150; ++i) {
sharedStorage.set('key' + i.toString().padStart(3, '0'),
'value' + i.toString().padStart(3, '0'));
}
for await (const key of sharedStorage.keys()) {
console.log(key);
}
for await (const [key, value] of sharedStorage.entries()) {
console.log(key + ';' + value);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kWorkletNumPerPageHistogram, kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletKeysHistogram,
kTimingWorkletEntriesHistogram, kEntriesQueuedCountHistogram,
kReceivedEntriesBenchmarksHistogram,
kIteratedEntriesBenchmarksHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletKeysHistogram, 151);
histogram_tester_.ExpectTotalCount(kTimingWorkletEntriesHistogram, 151);
histogram_tester_.ExpectUniqueSample(kEntriesQueuedCountHistogram, 150, 2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 0,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 10,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 20,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 30,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 40,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 50,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 70,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 80,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 90,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 100,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 0,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 10,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 20,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 30,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 40,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 50,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 70,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 80,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 90,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 100,
2);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
WorkletKeysEntries_PartiallyIterated) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(ExecuteScriptInWorklet(GetActiveWebContents(), R"(
for (let i = 0; i < 300; ++i) {
sharedStorage.set('key' + i.toString().padStart(3, '0'),
'value' + i.toString().padStart(3, '0'));
}
var keys = sharedStorage.keys();
for (let i = 0; i < 150; ++i) {
let key_dict = await keys.next();
console.log(key_dict['value']);
}
var entries = sharedStorage.entries();
for (let i = 0; i < 101; ++i) {
let entry_dict = await entries.next();
console.log(entry_dict['value']);
}
var keys2 = sharedStorage.keys();
for (let i = 0; i < 243; ++i) {
let key_dict = await keys2.next();
console.log(key_dict['value']);
}
var entries = sharedStorage.entries();
for (let i = 0; i < 299; ++i) {
let entry_dict = await entries.next();
console.log(entry_dict['value']);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kWorkletNumPerPageHistogram, kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletKeysHistogram,
kTimingWorkletEntriesHistogram, kEntriesQueuedCountHistogram,
kReceivedEntriesBenchmarksHistogram,
kIteratedEntriesBenchmarksHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletKeysHistogram, 150 + 243);
histogram_tester_.ExpectTotalCount(kTimingWorkletEntriesHistogram, 101 + 299);
histogram_tester_.ExpectUniqueSample(kEntriesQueuedCountHistogram, 300, 4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 0,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 10,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 20,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 30,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 40,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 50,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 60,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 70,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 80,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 90,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 100,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 0,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 10,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 20,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 30,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 40,
3);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 50,
3);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 70,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 80,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 90,
1);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 100,
0);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
WorkletKeysEntries_AllIteratedLessThanTenKeys) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(ExecuteScriptInWorklet(GetActiveWebContents(), R"(
for (let i = 0; i < 5; ++i) {
sharedStorage.set('key' + i.toString().padStart(3, '0'),
'value' + i.toString().padStart(3, '0'));
}
for await (const key of sharedStorage.keys()) {
console.log(key);
}
for await (const [key, value] of sharedStorage.entries()) {
console.log(key + ';' + value);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kWorkletNumPerPageHistogram, kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletKeysHistogram,
kTimingWorkletEntriesHistogram, kEntriesQueuedCountHistogram,
kReceivedEntriesBenchmarksHistogram,
kIteratedEntriesBenchmarksHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletKeysHistogram, 6);
histogram_tester_.ExpectTotalCount(kTimingWorkletEntriesHistogram, 6);
histogram_tester_.ExpectUniqueSample(kEntriesQueuedCountHistogram, 5, 2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 0,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 10,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 20,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 30,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 40,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 50,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 70,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 80,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 90,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 100,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 0,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 10,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 20,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 30,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 40,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 50,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 70,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 80,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 90,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 100,
2);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
WorkletKeysEntries_PartiallyIteratedLessThanTenKeys) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(ExecuteScriptInWorklet(GetActiveWebContents(), R"(
for (let i = 0; i < 5; ++i) {
sharedStorage.set('key' + i.toString().padStart(3, '0'),
'value' + i.toString().padStart(3, '0'));
}
var keys = sharedStorage.keys();
for (let i = 0; i < 4; ++i) {
let key_dict = await keys.next();
console.log(key_dict['value']);
}
var entries = sharedStorage.entries();
for (let i = 0; i < 2; ++i) {
let entry_dict = await entries.next();
console.log(entry_dict['value']);
}
var keys2 = sharedStorage.keys();
for (let i = 0; i < 3; ++i) {
let key_dict = await keys2.next();
console.log(key_dict['value']);
}
var entries = sharedStorage.entries();
for (let i = 0; i < 1; ++i) {
let entry_dict = await entries.next();
console.log(entry_dict['value']);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kWorkletNumPerPageHistogram, kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletKeysHistogram,
kTimingWorkletEntriesHistogram, kEntriesQueuedCountHistogram,
kReceivedEntriesBenchmarksHistogram,
kIteratedEntriesBenchmarksHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletKeysHistogram, 4 + 3);
histogram_tester_.ExpectTotalCount(kTimingWorkletEntriesHistogram, 2 + 1);
histogram_tester_.ExpectUniqueSample(kEntriesQueuedCountHistogram, 5, 4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 0,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 10,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 20,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 30,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 40,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 50,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 60,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 70,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 80,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 90,
4);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 100,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 0,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 10,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 20,
4);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 30,
3);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 40,
3);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 50,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 70,
1);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 80,
1);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 90,
0);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
WorkletKeysEntries_AllIteratedNoKeys) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(ExecuteScriptInWorklet(GetActiveWebContents(), R"(
sharedStorage.set('key', 'value');
sharedStorage.delete('key');
for await (const key of sharedStorage.keys()) {
console.log(key);
}
for await (const [key, value] of sharedStorage.entries()) {
console.log(key + ';' + value);
}
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kWorkletNumPerPageHistogram, kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletKeysHistogram,
kTimingWorkletEntriesHistogram, kEntriesQueuedCountHistogram,
kReceivedEntriesBenchmarksHistogram,
kIteratedEntriesBenchmarksHistogram});
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletKeysHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletEntriesHistogram, 1);
histogram_tester_.ExpectUniqueSample(kEntriesQueuedCountHistogram, 0, 2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 0,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 10,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 20,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 30,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 40,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 50,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 60,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 70,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 80,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 90,
2);
histogram_tester_.ExpectBucketCount(kReceivedEntriesBenchmarksHistogram, 100,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 0,
2);
histogram_tester_.ExpectBucketCount(kIteratedEntriesBenchmarksHistogram, 10,
0);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
AddModule_InvalidScriptUrlError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
std::string invalid_url = "http://#";
content::EvalJsResult result = content::EvalJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", invalid_url));
EXPECT_EQ(
base::StrCat(
{"a JavaScript error: \"Error: The module script url is invalid.\n",
" at __const_std::string&_script__:1:24):\n",
" {sharedStorage.worklet.addModule(\"", invalid_url, "\")\n",
" ^^^^^\n"}),
result.error);
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
AddModule_CrossOriginScriptError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(kCrossOriginHost,
"/shared_storage/simple_module.js");
content::EvalJsResult result = content::EvalJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url));
EXPECT_EQ(
base::StrCat({"a JavaScript error: \"Error: Only same origin module ",
"script is allowed.",
"\n at __const_std::string&_script__:1:24):\n ",
"{sharedStorage.worklet.addModule(\"",
script_url.spec().substr(0, 38),
"\n ^^^^^\n"}),
result.error);
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
AddModule_LoadFailureError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/nonexistent_module.js");
content::EvalJsResult result = content::EvalJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url));
EXPECT_EQ(
base::StrCat({"a JavaScript error: \"Error: Failed to load ",
script_url.spec(), " HTTP status = 404 Not Found.\"\n"}),
result.error);
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
AddModule_UnexpectedRedirectError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/server-redirect?shared_storage/simple_module.js");
content::EvalJsResult result = content::EvalJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url));
EXPECT_EQ(
base::StrCat({"a JavaScript error: \"Error: Unexpected redirect on ",
script_url.spec(), ".\"\n"}),
result.error);
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
AddModule_EmptyResultError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module.js");
content::EvalJsResult result = content::EvalJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url));
EXPECT_EQ(base::StrCat({"a JavaScript error: \"Error: ", script_url.spec(),
":6 Uncaught ReferenceError: ",
"undefinedVariable is not defined.\"\n"}),
result.error);
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
AddModule_MultipleAddModuleError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(kSimpleTestHost,
"/shared_storage/simple_module.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
content::EvalJsResult result = content::EvalJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url));
EXPECT_EQ(base::StrCat({"a JavaScript error: \"Error: ",
"sharedStorage.worklet.addModule() can only ",
"be invoked once per browsing context.\"\n"}),
result.error);
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kAddModuleWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, Run_NotLoadedError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.run(
'test-operation', {data: {}});
)"));
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, Run_NotRegisteredError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(kSimpleTestHost,
"/shared_storage/simple_module.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.run(
'test-operation-1', {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, Run_FunctionError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module2.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.run(
'test-operation', {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, Run_NotAPromiseError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module3.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.run(
'test-operation', {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, Run_ScriptError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module4.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.run(
'test-operation', {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
Run_UnexpectedCustomDataError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module5.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.run(
'test-operation', {data: {'customField': 'customValue123'}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_NotLoadedError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
content::EvalJsResult result = content::EvalJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation-1',
[{url: "fenced_frames/title0.html"}], {data: {}});
)");
EXPECT_EQ(base::StrCat({"a JavaScript error: \"Error: ",
"sharedStorage.worklet.addModule() has to be ",
"called before sharedStorage.selectURL().\"\n"}),
result.error);
WaitForHistograms({kErrorTypeHistogram});
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLWebVisible, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_NotRegisteredError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(kSimpleTestHost,
"/shared_storage/simple_module.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation-1',
[{url: "fenced_frames/title0.html"}], {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_FunctionError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module2.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation',
[{url: "fenced_frames/title0.html"}], {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_NotAPromiseError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module3.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation',
[{url: "fenced_frames/title0.html"}], {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, SelectUrl_ScriptError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module4.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation',
[{url: "fenced_frames/title0.html"}], {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_UnexpectedCustomDataError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module5.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation',
[{url: "fenced_frames/title0.html"}],
{data: {'customField': 'customValue123'}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_OutOfRangeError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module6.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation-1',
[{url: "fenced_frames/title0.html"}], {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
SelectUrl_ReturnValueToIntError) {
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
GURL script_url = https_server()->GetURL(
kSimpleTestHost, "/shared_storage/erroneous_module6.js");
EXPECT_TRUE(content::ExecJs(
GetActiveWebContents(),
content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.selectURL(
'test-url-selection-operation-2',
[{url: "fenced_frames/title0.html"}], {data: {}});
)"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectUniqueSample(
kErrorTypeHistogram,
blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, DocumentTiming) {
base::test::ScopedRunLoopTimeout timeout(FROM_HERE, base::Seconds(60));
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
R"(
sharedStorage.set('key0', 'value0');
sharedStorage.set('key1', 'value1');
sharedStorage.set('key1', 'value111');
sharedStorage.set('key2', 'value2');
sharedStorage.set('key2', 'value222', {ignoreIfPresent: true});
sharedStorage.set('key3', 'value3');
sharedStorage.append('key3', 'value333');
sharedStorage.append('key2', 'value22');
sharedStorage.append('key4', 'value4');
sharedStorage.delete('key0');
sharedStorage.delete('key2');
sharedStorage.clear();
)"));
WaitForHistograms(
{kTimingDocumentSetHistogram, kTimingDocumentAppendHistogram,
kTimingDocumentDeleteHistogram, kTimingDocumentClearHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentSetHistogram, 6);
histogram_tester_.ExpectTotalCount(kTimingDocumentAppendHistogram, 3);
histogram_tester_.ExpectTotalCount(kTimingDocumentDeleteHistogram, 2);
histogram_tester_.ExpectTotalCount(kTimingDocumentClearHistogram, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, WorkletTiming) {
base::test::ScopedRunLoopTimeout timeout(FROM_HERE, base::Seconds(60));
NavigateParams params(
browser(), https_server()->GetURL(kSimpleTestHost, kSimplePagePath),
ui::PageTransition::PAGE_TRANSITION_LINK);
ui_test_utils::NavigateToURL(&params);
EXPECT_TRUE(ExecuteScriptInWorklet(GetActiveWebContents(),
R"(
sharedStorage.set('key0', 'value0');
sharedStorage.set('key1', 'value1');
sharedStorage.set('key1', 'value111');
sharedStorage.set('key2', 'value2');
sharedStorage.set('key2', 'value222', {ignoreIfPresent: true});
sharedStorage.set('key3', 'value3');
sharedStorage.append('key3', 'value333');
sharedStorage.append('key2', 'value22');
sharedStorage.append('key4', 'value4');
console.log(await sharedStorage.get('key0'));
console.log(await sharedStorage.get('key1'));
console.log(await sharedStorage.get('key2'));
console.log(await sharedStorage.get('key3'));
console.log(await sharedStorage.get('key4'));
console.log(await sharedStorage.length());
sharedStorage.delete('key0');
sharedStorage.delete('key2');
sharedStorage.clear();
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kTimingDocumentAddModuleHistogram, kTimingDocumentRunHistogram,
kTimingWorkletSetHistogram, kTimingWorkletAppendHistogram,
kTimingWorkletGetHistogram, kTimingWorkletLengthHistogram,
kTimingWorkletDeleteHistogram, kTimingWorkletClearHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletSetHistogram, 6);
histogram_tester_.ExpectTotalCount(kTimingWorkletAppendHistogram, 3);
histogram_tester_.ExpectTotalCount(kTimingWorkletGetHistogram, 5);
histogram_tester_.ExpectTotalCount(kTimingWorkletLengthHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingWorkletDeleteHistogram, 2);
histogram_tester_.ExpectTotalCount(kTimingWorkletClearHistogram, 1);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest, WorkletNumPerPage_Two) {
EXPECT_TRUE(content::NavigateToURL(
GetActiveWebContents(),
https_server()->GetURL(kSimpleTestHost, kSimplePagePath)));
content::RenderFrameHost* main_frame =
GetActiveWebContents()->GetPrimaryMainFrame();
EXPECT_TRUE(ExecuteScriptInWorklet(main_frame,
R"(
sharedStorage.set('key0', 'value0');
console.log('Finished script');
)",
"Finished script"));
content::RenderFrameHost* iframe = CreateIframe(
main_frame, https_server()->GetURL(kCrossOriginHost, kSimplePagePath));
EXPECT_TRUE(ExecuteScriptInWorklet(iframe,
R"(
sharedStorage.set('key0', 'value0');
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletSetHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 2);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 2);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 2, 1);
EXPECT_LE(1u,
histogram_tester_.GetAllSamples(kTimingWorkletSetHistogram).size());
}
IN_PROC_BROWSER_TEST_F(SharedStorageChromeBrowserTest,
WorkletNumPerPage_Three) {
EXPECT_TRUE(content::NavigateToURL(
GetActiveWebContents(),
https_server()->GetURL(kSimpleTestHost, kSimplePagePath)));
content::RenderFrameHost* main_frame =
GetActiveWebContents()->GetPrimaryMainFrame();
EXPECT_TRUE(ExecuteScriptInWorklet(main_frame,
R"(
sharedStorage.set('key0', 'value0');
console.log('Finished script');
)",
"Finished script"));
content::RenderFrameHost* iframe = CreateIframe(
main_frame, https_server()->GetURL(kCrossOriginHost, kSimplePagePath));
EXPECT_TRUE(ExecuteScriptInWorklet(iframe,
R"(
sharedStorage.set('key0', 'value0');
console.log('Finished script');
)",
"Finished script"));
content::RenderFrameHost* nested_iframe = CreateIframe(
iframe, https_server()->GetURL(kThirdOriginHost, kSimplePagePath));
EXPECT_TRUE(ExecuteScriptInWorklet(nested_iframe,
R"(
sharedStorage.set('key0', 'value0');
console.log('Finished script');
)",
"Finished script"));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms({kTimingDocumentAddModuleHistogram,
kTimingDocumentRunHistogram, kTimingWorkletSetHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 3);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 3);
histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 3, 1);
EXPECT_LE(1u,
histogram_tester_.GetAllSamples(kTimingWorkletSetHistogram).size());
}
struct SharedStorageFencedFrameChromeBrowserParams {
blink::features::FencedFramesImplementationType impl_type;
};
// Used by `testing::PrintToStringParamName()`.
std::string PrintToString(
const SharedStorageFencedFrameChromeBrowserParams& p) {
return (p.impl_type ==
blink::features::FencedFramesImplementationType::kShadowDOM)
? "ShadowDOM"
: "MPArch";
}
std::vector<SharedStorageFencedFrameChromeBrowserParams>
GetSharedStorageFencedFrameChromeBrowserParams() {
return std::vector<SharedStorageFencedFrameChromeBrowserParams>(
{{blink::features::FencedFramesImplementationType::kShadowDOM},
{blink::features::FencedFramesImplementationType::kMPArch}});
}
class SharedStorageFencedFrameChromeBrowserTest
: public SharedStorageChromeBrowserTest,
public testing::WithParamInterface<
SharedStorageFencedFrameChromeBrowserParams> {
public:
SharedStorageFencedFrameChromeBrowserTest() {
base::test::TaskEnvironment task_environment;
scoped_feature_list_.InitWithFeaturesAndParameters(
/*enabled_features=*/
{{blink::features::kSharedStorageAPI,
{{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)}}},
{blink::features::kFencedFrames,
{{"implementation_type",
GetParam().impl_type ==
blink::features::FencedFramesImplementationType::kShadowDOM
? "shadow_dom"
: "mparch"}}},
{privacy_sandbox::kPrivacySandboxSettings3, {}},
{features::kPrivacySandboxAdsAPIsOverride, {}}},
/*disabled_features=*/{});
}
~SharedStorageFencedFrameChromeBrowserTest() override = default;
content::RenderFrameHost* SelectURLAndCreateFencedFrame(
content::RenderFrameHost* render_frame_host,
bool should_add_module = true) {
if (should_add_module)
AddSimpleModule(render_frame_host);
content::WebContentsConsoleObserver run_url_op_console_observer(
GetActiveWebContents());
run_url_op_console_observer.SetFilter(
MakeFilter({"Finish executing \'test-url-selection-operation\'"}));
content::EvalJsResult run_url_op_result =
content::EvalJs(render_frame_host, R"(
sharedStorage.selectURL(
'test-url-selection-operation',
[{url: "fenced_frames/title0.html"},
{url: "fenced_frames/title1.html",
reportingMetadata: {"click": "fenced_frames/report1.html"}},
{url: "fenced_frames/title2.html"}],
{data: {'mockResult': 1}});
)");
run_url_op_console_observer.Wait();
EXPECT_TRUE(run_url_op_result.error.empty());
EXPECT_TRUE(
blink::IsValidUrnUuidURL(GURL(run_url_op_result.ExtractString())));
EXPECT_EQ(1u, run_url_op_console_observer.messages().size());
EXPECT_EQ(
"Finish executing \'test-url-selection-operation\'",
base::UTF16ToUTF8(run_url_op_console_observer.messages()[0].message));
return content::CreateFencedFrame(render_frame_host,
GURL(run_url_op_result.ExtractString()));
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
All,
SharedStorageFencedFrameChromeBrowserTest,
testing::ValuesIn(GetSharedStorageFencedFrameChromeBrowserParams()),
testing::PrintToStringParamName());
IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameChromeBrowserTest,
FencedFrameNavigateTop_BudgetWithdrawal) {
GURL main_url = https_server()->GetURL(kSimpleTestHost, kSimplePagePath);
EXPECT_TRUE(NavigateToURL(GetActiveWebContents(), main_url));
GURL iframe_url = https_server()->GetURL(kCrossOriginHost, kSimplePagePath);
content::RenderFrameHost* iframe =
CreateIframe(GetActiveWebContents()->GetPrimaryMainFrame(), iframe_url);
content::RenderFrameHost* fenced_frame_root_node =
SelectURLAndCreateFencedFrame(iframe);
EXPECT_DOUBLE_EQ(RemainingBudget(iframe), kBudgetAllowed);
GURL new_page_url = https_server()->GetURL(kThirdOriginHost, kSimplePagePath);
content::TestNavigationObserver top_navigation_observer(
GetActiveWebContents());
EXPECT_TRUE(ExecJs(fenced_frame_root_node,
content::JsReplace("window.open($1, '_unfencedTop')",
new_page_url.spec())));
top_navigation_observer.Wait();
content::RenderFrameHost* new_iframe =
CreateIframe(GetActiveWebContents()->GetPrimaryMainFrame(), iframe_url);
// After the top navigation, log(3) bits should have been withdrawn from the
// original shared storage origin.
EXPECT_DOUBLE_EQ(RemainingBudget(new_iframe, /*should_add_module=*/true),
kBudgetAllowed - std::log2(3));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kTimingDocumentAddModuleHistogram, kTimingDocumentSelectUrlHistogram,
kTimingDocumentRunHistogram, kTimingRemainingBudgetHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 2);
histogram_tester_.ExpectTotalCount(kTimingDocumentSelectUrlHistogram, 1);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 2);
histogram_tester_.ExpectTotalCount(kTimingRemainingBudgetHistogram, 2);
// In the MPArch case, some additional pageloads with worklet count 0 are
// recorded, so we do not use `ExpectUniqueSample()` here.
histogram_tester_.ExpectBucketCount(kWorkletNumPerPageHistogram, 1, 2);
EXPECT_EQ(2, histogram_tester_.GetTotalSum(kWorkletNumPerPageHistogram));
}
IN_PROC_BROWSER_TEST_P(
SharedStorageFencedFrameChromeBrowserTest,
TwoFencedFrames_DifferentURNs_EachNavigateOnce_BudgetWithdrawalTwice) {
GURL main_url = https_server()->GetURL(kSimpleTestHost, kSimplePagePath);
EXPECT_TRUE(NavigateToURL(GetActiveWebContents(), main_url));
GURL iframe_url = https_server()->GetURL(kCrossOriginHost, kSimplePagePath);
content::RenderFrameHost* iframe1 =
CreateIframe(GetActiveWebContents()->GetPrimaryMainFrame(), iframe_url);
content::RenderFrameHost* fenced_frame_root_node1 =
SelectURLAndCreateFencedFrame(iframe1);
EXPECT_DOUBLE_EQ(RemainingBudget(iframe1), kBudgetAllowed);
GURL new_page_url1 =
https_server()->GetURL(kThirdOriginHost, kSimplePagePath);
content::TestNavigationObserver top_navigation_observer1(
GetActiveWebContents());
EXPECT_TRUE(ExecJs(fenced_frame_root_node1,
content::JsReplace("window.open($1, '_unfencedTop')",
new_page_url1.spec())));
top_navigation_observer1.Wait();
content::RenderFrameHost* iframe2 =
CreateIframe(GetActiveWebContents()->GetPrimaryMainFrame(), iframe_url);
// After the top navigation, log(3) bits should have been withdrawn from the
// original shared storage origin.
EXPECT_DOUBLE_EQ(RemainingBudget(iframe2, /*should_add_module=*/true),
kBudgetAllowed - std::log2(3));
content::RenderFrameHost* fenced_frame_root_node2 =
SelectURLAndCreateFencedFrame(iframe2, /*should_add_module=*/false);
EXPECT_DOUBLE_EQ(RemainingBudget(iframe2), kBudgetAllowed - std::log2(3));
GURL new_page_url2 =
https_server()->GetURL(kFourthOriginHost, kSimplePagePath);
content::TestNavigationObserver top_navigation_observer2(
GetActiveWebContents());
EXPECT_TRUE(ExecJs(fenced_frame_root_node2,
content::JsReplace("window.open($1, '_unfencedTop')",
new_page_url2.spec())));
top_navigation_observer2.Wait();
content::RenderFrameHost* iframe3 =
CreateIframe(GetActiveWebContents()->GetPrimaryMainFrame(), iframe_url);
// After the top navigation, another log(3) bits should have been withdrawn
// from the original shared storage origin.
EXPECT_DOUBLE_EQ(RemainingBudget(iframe3, /*should_add_module=*/true),
kBudgetAllowed - std::log2(3) - std::log2(3));
// Navigate away to record `kWorkletNumPerPageHistogram` histogram.
EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
GURL(url::kAboutBlankURL)));
WaitForHistograms(
{kTimingDocumentAddModuleHistogram, kTimingDocumentSelectUrlHistogram,
kTimingDocumentRunHistogram, kTimingRemainingBudgetHistogram,
kWorkletNumPerPageHistogram});
histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 3);
histogram_tester_.ExpectTotalCount(kTimingDocumentSelectUrlHistogram, 2);
histogram_tester_.ExpectTotalCount(kTimingDocumentRunHistogram, 4);
histogram_tester_.ExpectTotalCount(kTimingRemainingBudgetHistogram, 4);
// In the MPArch case, some additional pageloads with worklet count 0 are
// recorded, so we do not use `ExpectUniqueSample()` here.
histogram_tester_.ExpectBucketCount(kWorkletNumPerPageHistogram, 1, 3);
EXPECT_EQ(3, histogram_tester_.GetTotalSum(kWorkletNumPerPageHistogram));
}
} // namespace storage