blob: 5dd08cc0a049a644abc8fac35d1b6887c10def04 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <tuple>
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/extension_features.h"
#include "extensions/common/value_builder.h"
#include "extensions/test/test_extension_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
constexpr char kWorkerJS[] = R"(
function verifyData(data) {
if (data.byteLength != 16)
return `Improper byteLength: ${data.byteLength}`;
const bufView = new Uint8Array(data);
for (let i = 0; i < 16; i++) {
if (bufView[i] != i % 2) {
return `Data mismatch at index ${i}: Expected: ${i % 2}, got: ${
bufView[i]}`;
}
}
return 'PASS';
}
self.addEventListener('message', e => {
try {
postMessage(verifyData(e.data));
} catch (e) {
postMessage(e.message);
}
});
)";
constexpr char kBackgroundJS_SabDisallowed[] = R"(
chrome.test.runTests([
function sendSharedArrayBufferToWorker() {
try {
let sab = new SharedArrayBuffer(16);
chrome.test.fail('SAB construction succeeded unexpectedly')
} catch (e) {
chrome.test.succeed();
}
}
]);
)";
constexpr char kBackgroundJS_SabAllowed[] = R"(
chrome.test.runTests([
function sendSharedArrayBufferToWorker() {
let sab = new SharedArrayBuffer(16);
let bufView = new Uint8Array(sab);
for (let i = 0; i < 16; i++)
bufView[i] = (i % 2);
const workerUrl = chrome.runtime.getURL('worker.js');
let worker = new Worker(workerUrl);
worker.onmessage = e => {
chrome.test.assertEq('PASS', e.data);
chrome.test.succeed();
};
worker.postMessage(sab);
chrome.test.assertEq(16, sab.byteLength);
// The worker will ack on receiving the SharedArrayBuffer causing the test
// to terminate.
}
]);
)";
// Parameterized on tuple of
// <is_sab_allowed_unconditionally, is_cross_origin_isolated, is_platform_app>.
class SharedArrayBufferTest
: public ExtensionApiTest,
public ::testing::WithParamInterface<std::tuple<bool, bool, bool>> {
public:
SharedArrayBufferTest() {
std::vector<base::test::FeatureRef> enabled_features, disabled_features;
const bool is_sab_allowed_unconditionally = std::get<0>(GetParam());
if (is_sab_allowed_unconditionally) {
enabled_features.push_back(
extensions_features::kAllowSharedArrayBuffersUnconditionally);
} else {
disabled_features.push_back(
extensions_features::kAllowSharedArrayBuffersUnconditionally);
}
feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
TestExtensionDir& test_dir() { return test_dir_; }
private:
base::test::ScopedFeatureList feature_list_;
TestExtensionDir test_dir_;
};
IN_PROC_BROWSER_TEST_P(SharedArrayBufferTest, TransferToWorker) {
ASSERT_TRUE(StartEmbeddedTestServer());
bool is_sab_allowed_unconditionally;
bool is_cross_origin_isolated;
bool is_platform_app;
std::tie(is_sab_allowed_unconditionally, is_cross_origin_isolated,
is_platform_app) = GetParam();
DictionaryBuilder builder;
builder.Set("manifest_version", 2)
.Set("name", "SharedArrayBuffer")
.Set("version", "1.1");
if (is_cross_origin_isolated) {
builder
.Set("cross_origin_opener_policy",
DictionaryBuilder().Set("value", "same-origin").Build())
.Set("cross_origin_embedder_policy",
DictionaryBuilder().Set("value", "require-corp").Build());
}
DictionaryBuilder background_builder;
background_builder.Set("scripts",
ListBuilder().Append("background.js").Build());
if (is_platform_app) {
builder.Set("app", DictionaryBuilder()
.Set("background", background_builder.Build())
.Build());
} else {
builder.Set("background", background_builder.Build());
}
test_dir().WriteManifest(builder.ToJSON());
const bool expect_sab_allowed =
is_cross_origin_isolated || is_sab_allowed_unconditionally;
if (expect_sab_allowed) {
test_dir().WriteFile(FILE_PATH_LITERAL("background.js"),
kBackgroundJS_SabAllowed);
test_dir().WriteFile(FILE_PATH_LITERAL("worker.js"), kWorkerJS);
} else {
test_dir().WriteFile(FILE_PATH_LITERAL("background.js"),
kBackgroundJS_SabDisallowed);
}
ASSERT_TRUE(RunExtensionTest(test_dir().Pack(),
{.launch_as_platform_app = is_platform_app},
{} /* load_options */))
<< message_;
}
INSTANTIATE_TEST_SUITE_P(
,
SharedArrayBufferTest,
::testing::Combine(::testing::Bool(), ::testing::Bool(), ::testing::Bool()),
[](const testing::TestParamInfo<std::tuple<bool, bool, bool>>& info) {
bool is_sab_allowed_unconditionally;
bool is_cross_origin_isolated;
bool is_platform_app;
std::tie(is_sab_allowed_unconditionally, is_cross_origin_isolated,
is_platform_app) = info.param;
return base::StringPrintf("%s_%s_%s",
is_sab_allowed_unconditionally
? "SabAllowedEnabled"
: "SabAllowedDisabled",
is_cross_origin_isolated ? "COI" : "NonCOI",
is_platform_app ? "App" : "Extension");
});
} // namespace extensions