#include "content/browser/interest_group/auction_process_manager.h"
#include <cstddef>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/run_until.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "content/browser/interest_group/bidding_and_auction_server_key_fetcher.h"
#include "content/browser/interest_group/data_decoder_manager.h"
#include "content/browser/interest_group/interest_group_features.h"
#include "content/browser/interest_group/trusted_signals_cache_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/service_worker/service_worker_process_manager.h"
#include "content/common/features.h"
#include "content/public/browser/frame_tree_node_id.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/site_isolation_mode.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/services/auction_worklet/public/mojom/auction_shared_storage_host.mojom.h"
#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h"
#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
#include "content/services/auction_worklet/public/mojom/in_progress_auction_download.mojom.h"
#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
#include "content/services/auction_worklet/public/mojom/trusted_signals_cache.mojom.h"
#include "content/test/test_content_browser_client.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/ip_address_space.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
using RequestWorkletServiceOutcome =
AuctionProcessManager::RequestWorkletServiceOutcome;
const size_t kMaxSellerProcesses = AuctionProcessManager::kMaxSellerProcesses;
const size_t kMaxBidderProcesses = AuctionProcessManager::kMaxBidderProcesses;
constexpr std::string_view kCacheMessage =
"The cache failed with the right error.";
base::OnceClosure NeverInvokedClosure() {
return base::BindOnce([]() { ADD_FAILURE() << "This should not be called"; });
}
template <class AuctionManagerBaseType>
class TestAuctionProcessManager
: public AuctionManagerBaseType,
public auction_worklet::mojom::AuctionWorkletService {
public:
struct ReceiverContext {
explicit ReceiverContext(
base::WeakPtr<AuctionProcessManager::WorkletProcess> worklet_process)
: worklet_process(std::move(worklet_process)) {}
base::WeakPtr<AuctionProcessManager::WorkletProcess> worklet_process;
mojo::Remote<auction_worklet::mojom::TrustedSignalsCache> cache_remote;
raw_ptr<base::RunLoop> wait_for_cache_remote_run_loop;
};
explicit TestAuctionProcessManager(
TrustedSignalsCacheImpl* trusted_signals_cache)
: AuctionManagerBaseType(trusted_signals_cache) {}
TestAuctionProcessManager(const TestAuctionProcessManager&) = delete;
const TestAuctionProcessManager& operator=(const TestAuctionProcessManager&) =
delete;
~TestAuctionProcessManager() override = default;
void SetTrustedSignalsCache(
mojo::PendingRemote<auction_worklet::mojom::TrustedSignalsCache>
trusted_signals_cache) override {
ReceiverContext& context = receiver_set_.current_context();
ASSERT_FALSE(context.cache_remote);
context.cache_remote.Bind(std::move(trusted_signals_cache));
if (context.wait_for_cache_remote_run_loop) {
context.wait_for_cache_remote_run_loop->Quit();
context.wait_for_cache_remote_run_loop = nullptr;
}
}
void LoadBidderWorklet(
mojo::PendingReceiver<auction_worklet::mojom::BidderWorklet>
bidder_worklet_receiver,
std::vector<
mojo::PendingRemote<auction_worklet::mojom::AuctionSharedStorageHost>>
shared_storage_hosts,
bool pause_for_debugger_on_start,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
pending_url_loader_factory,
mojo::PendingRemote<auction_worklet::mojom::AuctionNetworkEventsHandler>
auction_network_events_handler,
auction_worklet::mojom::InProgressAuctionDownloadPtr script_load,
auction_worklet::mojom::InProgressAuctionDownloadPtr wasm_load,
const std::optional<GURL>& trusted_bidding_signals_url,
const std::string& trusted_bidding_signals_slot_size_param,
const url::Origin& top_window_origin,
auction_worklet::mojom::AuctionWorkletPermissionsPolicyStatePtr
permissions_policy_state,
std::optional<uint16_t> experiment_id,
auction_worklet::mojom::TrustedSignalsPublicKeyPtr public_key) override {
NOTREACHED();
}
void LoadSellerWorklet(
mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
seller_worklet,
std::vector<
mojo::PendingRemote<auction_worklet::mojom::AuctionSharedStorageHost>>
shared_storage_hosts,
bool should_pause_on_start,
mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory,
mojo::PendingRemote<auction_worklet::mojom::AuctionNetworkEventsHandler>
auction_network_events_handler,
auction_worklet::mojom::InProgressAuctionDownloadPtr script_load,
const std::optional<GURL>& trusted_scoring_signals_url,
const url::Origin& top_window_origin,
auction_worklet::mojom::AuctionWorkletPermissionsPolicyStatePtr
permissions_policy_state,
std::optional<uint16_t> experiment_id,
std::optional<bool> send_creative_scanning_metadata,
auction_worklet::mojom::TrustedSignalsPublicKeyPtr public_key,
mojo::PendingRemote<auction_worklet::mojom::LoadSellerWorkletClient>
trusted_signals_url_allowed) override {
NOTREACHED();
}
void ClosePipes() {
receiver_set_.Clear();
base::RunLoop().RunUntilIdle();
}
size_t ProcessCreationOrder(
const AuctionProcessManager::ProcessHandle& handle) {
EXPECT_TRUE(handle.worklet_process_for_testing());
for (size_t i = 0u; i < launched_processes_.size(); ++i) {
if (handle.worklet_process_for_testing() ==
launched_processes_[i].get()) {
return i;
}
}
ADD_FAILURE() << "Worklet process not found";
return -1;
}
void SimulateReadyProcess(size_t creation_index) {
if constexpr (std::is_same<AuctionManagerBaseType,
InRendererAuctionProcessManager>::value) {
NOTREACHED();
return;
}
if (launched_processes_.size() <= creation_index) {
ADD_FAILURE() << "Process unexpectedly doesn't exist: " << creation_index;
return;
}
launched_processes_[creation_index]->OnLaunchedWithProcess(
base::Process::Current());
return;
}
void ExpectNoCacheRemote(const AuctionProcessManager::ProcessHandle& handle) {
ASSERT_TRUE(handle.worklet_process_for_testing());
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(handle.worklet_process_for_testing());
ReceiverContext* context = FindContextForProcess(handle);
ASSERT_TRUE(context);
EXPECT_FALSE(context->cache_remote);
}
auction_worklet::mojom::TrustedSignalsCache* WaitForCacheRemote(
const AuctionProcessManager::ProcessHandle& handle) {
CHECK(handle.worklet_process_for_testing());
ReceiverContext* context = FindContextForProcess(handle);
if (!context) {
return nullptr;
}
if (!context->cache_remote) {
base::RunLoop run_loop;
context->wait_for_cache_remote_run_loop = &run_loop;
context = nullptr;
run_loop.Run();
context = FindContextForProcess(handle);
if (!context) {
return nullptr;
}
}
EXPECT_TRUE(context->cache_remote.is_bound());
EXPECT_TRUE(context->cache_remote.is_connected());
return context->cache_remote.get();
}
private:
AuctionProcessManager::WorkletProcess::ProcessContext CreateProcessInternal(
AuctionProcessManager::WorkletProcess& worklet_process) override {
launched_processes_.emplace_back(worklet_process.GetWeakPtrForTesting());
if constexpr (std::is_same<AuctionManagerBaseType,
InRendererAuctionProcessManager>::value) {
static_cast<MockRenderProcessHost*>(
worklet_process.site_instance()->GetOrCreateProcessForTesting())
->OverrideBinderForTesting(
auction_worklet::mojom::AuctionWorkletService::Name_,
base::BindRepeating(&TestAuctionProcessManager<
AuctionManagerBaseType>::BindInterface,
weak_ptr_factory_.GetWeakPtr(),
worklet_process.GetWeakPtrForTesting()));
return AuctionManagerBaseType::CreateProcessInternal(worklet_process);
} else {
mojo::PendingRemote<auction_worklet::mojom::AuctionWorkletService>
service;
receiver_set_.Add(
this, service.InitWithNewPipeAndPassReceiver(),
ReceiverContext(worklet_process.GetWeakPtrForTesting()));
return AuctionProcessManager::WorkletProcess::ProcessContext(
std::move(service));
}
}
void BindInterface(
base::WeakPtr<AuctionProcessManager::WorkletProcess> worklet_process,
mojo::ScopedMessagePipeHandle pipe) {
receiver_set_.Add(
this,
mojo::PendingReceiver<auction_worklet::mojom::AuctionWorkletService>(
std::move(pipe)),
ReceiverContext(worklet_process));
}
ReceiverContext* FindContextForProcess(
const AuctionProcessManager::ProcessHandle& handle) {
CHECK(handle.worklet_process_for_testing());
for (const auto& receiver : receiver_set_.GetAllContexts()) {
if (receiver.second->worklet_process.get() ==
handle.worklet_process_for_testing()) {
return receiver.second;
}
}
ADD_FAILURE() << "Context associated with process not found.";
return nullptr;
}
std::vector<base::WeakPtr<AuctionProcessManager::WorkletProcess>>
launched_processes_;
mojo::ReceiverSet<auction_worklet::mojom::AuctionWorkletService,
ReceiverContext>
receiver_set_;
base::WeakPtrFactory<TestAuctionProcessManager<AuctionManagerBaseType>>
weak_ptr_factory_{this};
};
class TestCacheClient
: public auction_worklet::mojom::TrustedSignalsCacheClient {
public:
explicit TestCacheClient(auction_worklet::mojom::TrustedSignalsCache* cache)
: cache_(cache) {}
~TestCacheClient() override = default;
void RequestSignalsExpectingSuccess(
base::UnguessableToken compression_group_token) {
run_loop_ = std::make_unique<base::RunLoop>();
cache_->GetTrustedSignals(compression_group_token,
receiver_.BindNewPipeAndPassRemote());
run_loop_->Run();
run_loop_.reset();
}
private:
void OnSuccess(auction_worklet::mojom::TrustedSignalsCompressionScheme
compression_scheme,
mojo_base::BigBuffer foo) override {
ADD_FAILURE() << "Valid signals should never be received in these tests";
run_loop_->Quit();
}
void OnError(const std::string& error_message) override {
EXPECT_EQ(error_message, kCacheMessage);
run_loop_->Quit();
}
std::unique_ptr<base::RunLoop> run_loop_;
raw_ptr<auction_worklet::mojom::TrustedSignalsCache> cache_;
mojo::Receiver<auction_worklet::mojom::TrustedSignalsCacheClient> receiver_{
this};
};
class PartialSiteIsolationContentBrowserClient
: public TestContentBrowserClient {
public:
bool ShouldEnableStrictSiteIsolation() override { return false; }
bool ShouldDisableSiteIsolation(
SiteIsolationMode site_isolation_mode) override {
switch (site_isolation_mode) {
case SiteIsolationMode::kStrictSiteIsolation:
return true;
case SiteIsolationMode::kPartialSiteIsolation:
return false;
}
}
};
enum class ProcessMode {
kDedicated,
kInRendererSitePerProcess,
kInRendererSharedProcess,
};
class AuctionProcessManagerTest
: public testing::TestWithParam<
std::tuple<AuctionProcessManager::WorkletType, ProcessMode>> {
protected:
AuctionProcessManagerTest() {
SiteIsolationPolicy::DisableFlagCachingForTesting();
std::vector<base::test::FeatureRefAndParams> enabled_features{
{features::kFledgeStartAnticipatoryProcesses,
{{"AnticipatoryProcessHoldTime", "10s"}}}};
std::vector<base::test::FeatureRef> disabled_features;
switch (GetProcessMode()) {
case ProcessMode::kDedicated:
break;
case ProcessMode::kInRendererSitePerProcess:
scoped_command_line_.GetProcessCommandLine()->AppendSwitch(
switches::kSitePerProcess);
break;
case ProcessMode::kInRendererSharedProcess:
disabled_features.emplace_back(
features::kOriginKeyedProcessesByDefault);
scoped_command_line_.GetProcessCommandLine()->RemoveSwitch(
switches::kSitePerProcess);
original_browser_client_ =
content::SetBrowserClientForTesting(&browser_client_);
break;
}
RenderProcessHostImpl::set_render_process_host_factory_for_testing(
&rph_factory_);
feature_list_.InitWithFeaturesAndParameters(enabled_features,
disabled_features);
SiteInstance::StartIsolatingSite(
&test_browser_context_, kIsolatedOrigin.GetURL(),
ChildProcessSecurityPolicy::IsolatedOriginSource::TEST);
site_instance1_ = SiteInstance::Create(&test_browser_context_);
site_instance2_ = SiteInstance::Create(&test_browser_context_);
CreateAuctionProcessManager(&trusted_signals_cache_);
}
virtual ~AuctionProcessManagerTest() {
if (original_browser_client_) {
content::SetBrowserClientForTesting(original_browser_client_);
}
RenderProcessHostImpl::set_render_process_host_factory_for_testing(nullptr);
}
void CreateAuctionProcessManager(
TrustedSignalsCacheImpl* trusted_signals_cache) {
auction_process_manager_ = nullptr;
switch (GetProcessMode()) {
case ProcessMode::kDedicated:
dedicated_process_manager_.emplace(trusted_signals_cache);
auction_process_manager_ = &dedicated_process_manager_.value();
break;
case ProcessMode::kInRendererSitePerProcess:
case ProcessMode::kInRendererSharedProcess:
in_renderer_process_manager_.emplace(trusted_signals_cache);
auction_process_manager_ = &in_renderer_process_manager_.value();
break;
}
}
void ClosePipes() {
if (dedicated_process_manager_) {
dedicated_process_manager_->ClosePipes();
} else {
in_renderer_process_manager_->ClosePipes();
}
}
size_t ProcessCreationOrder(
const AuctionProcessManager::ProcessHandle& handle) {
if (dedicated_process_manager_) {
return dedicated_process_manager_->ProcessCreationOrder(handle);
} else {
return in_renderer_process_manager_->ProcessCreationOrder(handle);
}
}
auction_worklet::mojom::TrustedSignalsCache* WaitForCacheRemote(
const AuctionProcessManager::ProcessHandle& handle) {
if (dedicated_process_manager_) {
return dedicated_process_manager_->WaitForCacheRemote(handle);
} else {
return in_renderer_process_manager_->WaitForCacheRemote(handle);
}
}
void ExpectNoCacheRemote(const AuctionProcessManager::ProcessHandle& handle) {
if (dedicated_process_manager_) {
dedicated_process_manager_->ExpectNoCacheRemote(handle);
} else {
in_renderer_process_manager_->ExpectNoCacheRemote(handle);
}
}
void ValidateCacheRemote(const AuctionProcessManager::ProcessHandle& handle,
const url::Origin& origin) {
auto* cache_remote = WaitForCacheRemote(handle);
ASSERT_TRUE(cache_remote);
std::unique_ptr<TrustedSignalsCacheImpl::Handle> trusted_signals_handle;
int partition_id_ignored = 0;
switch (GetWorkletType()) {
case AuctionProcessManager::WorkletType::kBidder:
trusted_signals_handle =
trusted_signals_cache_.RequestTrustedBiddingSignals(
nullptr, FrameTreeNodeId(1),
{"devtools_auction_id"},
url::Origin::Create(GURL("https://main-frame-origin.test")),
network::mojom::IPAddressSpace::kPublic, origin,
"Interest Group Name",
blink::InterestGroup::ExecutionMode::kCompatibilityMode,
url::Origin::Create(GURL("https://joinin-origin.test")),
GURL("https://trusted-signals-url/"),
url::Origin::Create(GURL("https://coordinator.test")),
{}, {},
std::nullopt, partition_id_ignored);
break;
case AuctionProcessManager::WorkletType::kSeller:
trusted_signals_handle =
trusted_signals_cache_.RequestTrustedScoringSignals(
nullptr, FrameTreeNodeId(1),
{"devtools_auction_id"},
url::Origin::Create(GURL("https://main-frame-origin.test")),
network::mojom::IPAddressSpace::kPublic, origin,
GURL("https://trusted-signals-url/"),
url::Origin::Create(GURL("https://coordinator.test")),
url::Origin::Create(GURL("https://bidder.test")),
url::Origin::Create(GURL("https://joining-origin.test")),
GURL("https://render-url.test"), {},
{}, std::nullopt,
partition_id_ignored);
break;
}
TestCacheClient cache_client(cache_remote);
cache_client.RequestSignalsExpectingSuccess(
trusted_signals_handle->compression_group_token());
}
void SimulateReadyProcess(size_t creation_index) {
CHECK(dedicated_process_manager_);
dedicated_process_manager_->SimulateReadyProcess(creation_index);
}
void MaybeStartAnticipatoryProcess(
const url::Origin& origin,
std::optional<AuctionProcessManager::WorkletType> worklet_type =
std::nullopt) {
auction_process_manager_->MaybeStartAnticipatoryProcess(
origin, site_instance1_.get(), worklet_type.value_or(GetWorkletType()));
}
std::string RequestWorkletServiceOutcomeUmaName(
std::optional<AuctionProcessManager::WorkletType> worklet_type =
std::nullopt) {
return base::StrCat({"Ads.InterestGroup.Auction.",
worklet_type.value_or(GetWorkletType()) ==
AuctionProcessManager::WorkletType::kSeller
? "Seller."
: "Buyer.",
"RequestWorkletServiceOutcome"});
}
void RequestWorkletService(
AuctionProcessManager::ProcessHandle* process_handle,
const url::Origin& origin,
AuctionProcessManager::WorkletType worklet_type,
bool expect_success,
RequestWorkletServiceOutcome expected_outcome) {
base::HistogramTester histogram_tester;
bool success = auction_process_manager_->RequestWorkletService(
worklet_type, origin, site_instance1_.get(), process_handle,
base::DoNothing());
EXPECT_EQ(expect_success, success);
histogram_tester.ExpectUniqueSample(
RequestWorkletServiceOutcomeUmaName(worklet_type), expected_outcome,
1u);
}
std::unique_ptr<AuctionProcessManager::ProcessHandle>
GetServiceOfTypeExpectSuccess(
AuctionProcessManager::WorkletType worklet_type,
const url::Origin& origin,
scoped_refptr<SiteInstance> site_instance = nullptr) {
if (!site_instance) {
site_instance = site_instance1_;
}
auto process_handle =
std::make_unique<AuctionProcessManager::ProcessHandle>();
EXPECT_TRUE(auction_process_manager_->RequestWorkletService(
worklet_type, origin, std::move(site_instance), process_handle.get(),
NeverInvokedClosure()));
EXPECT_TRUE(process_handle->GetService());
return process_handle;
}
std::unique_ptr<AuctionProcessManager::ProcessHandle> GetServiceExpectSuccess(
const url::Origin& origin) {
return GetServiceOfTypeExpectSuccess(GetWorkletType(), origin);
}
size_t GetMaxProcesses() const {
switch (GetWorkletType()) {
case AuctionProcessManager::WorkletType::kSeller:
return kMaxSellerProcesses;
case AuctionProcessManager::WorkletType::kBidder:
return kMaxBidderProcesses;
}
}
ProcessMode GetProcessMode() const {
return std::get<ProcessMode>(GetParam());
}
AuctionProcessManager::WorkletType GetWorkletType() const {
return std::get<AuctionProcessManager::WorkletType>(GetParam());
}
AuctionProcessManager::WorkletType GetOtherWorkletType() const {
switch (GetWorkletType()) {
case AuctionProcessManager::WorkletType::kSeller:
return AuctionProcessManager::WorkletType::kBidder;
case AuctionProcessManager::WorkletType::kBidder:
return AuctionProcessManager::WorkletType::kSeller;
}
}
size_t GetPendingRequestsOfWorkletType() {
switch (GetWorkletType()) {
case AuctionProcessManager::WorkletType::kSeller:
return auction_process_manager_->GetPendingSellerRequestsForTesting();
case AuctionProcessManager::WorkletType::kBidder:
return auction_process_manager_->GetPendingBidderRequestsForTesting();
}
}
size_t GetActiveProcessesOfWorkletType(
std::optional<AuctionProcessManager::WorkletType> type = std::nullopt) {
switch (type.value_or(GetWorkletType())) {
case AuctionProcessManager::WorkletType::kSeller:
return auction_process_manager_->GetSellerProcessCountForTesting();
case AuctionProcessManager::WorkletType::kBidder:
return auction_process_manager_->GetBidderProcessCountForTesting();
}
}
void CheckOnlyIdleProcessesWithCount(size_t expected_idle_process_count) {
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
expected_idle_process_count);
EXPECT_EQ(auction_process_manager_->GetBidderProcessCountForTesting(), 0u);
EXPECT_EQ(auction_process_manager_->GetSellerProcessCountForTesting(), 0u);
}
const url::Origin kIsolatedOrigin =
url::Origin::Create(GURL("https://bank.test"));
const url::Origin kOriginA = url::Origin::Create(GURL("https://a.test"));
const url::Origin kOriginB = url::Origin::Create(GURL("https://b.test"));
const url::Origin kOriginC = url::Origin::Create(GURL("https://c.test"));
BrowserTaskEnvironment task_environment_{
content::BrowserTaskEnvironment::TimeSource::MOCK_TIME};
base::test::ScopedFeatureList feature_list_;
base::test::ScopedCommandLine scoped_command_line_;
MockRenderProcessHostFactory rph_factory_;
TestBrowserContext test_browser_context_;
PartialSiteIsolationContentBrowserClient browser_client_;
raw_ptr<ContentBrowserClient> original_browser_client_;
scoped_refptr<SiteInstance> site_instance1_;
scoped_refptr<SiteInstance> site_instance2_;
DataDecoderManager data_decoder_manager_;
TrustedSignalsCacheImpl trusted_signals_cache_{
&data_decoder_manager_,
base::BindRepeating(
[](const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) {
std::move(callback).Run(
base::unexpected(std::string(kCacheMessage)));
})};
std::optional<TestAuctionProcessManager<DedicatedAuctionProcessManager>>
dedicated_process_manager_;
std::optional<TestAuctionProcessManager<InRendererAuctionProcessManager>>
in_renderer_process_manager_;
raw_ptr<AuctionProcessManager> auction_process_manager_;
};
using SitePerProcessAuctionProcessManagerTest = AuctionProcessManagerTest;
INSTANTIATE_TEST_SUITE_P(
All,
SitePerProcessAuctionProcessManagerTest,
testing::Combine(
testing::Values(AuctionProcessManager::WorkletType::kSeller,
AuctionProcessManager::WorkletType::kBidder),
testing::Values(ProcessMode::kDedicated,
ProcessMode::kInRendererSitePerProcess)));
using SharedRendererInRendererAuctionProcessManagerTest =
AuctionProcessManagerTest;
INSTANTIATE_TEST_SUITE_P(
All,
SharedRendererInRendererAuctionProcessManagerTest,
testing::Combine(
testing::Values(AuctionProcessManager::WorkletType::kSeller,
AuctionProcessManager::WorkletType::kBidder),
testing::Values(ProcessMode::kInRendererSharedProcess)));
TEST_P(SitePerProcessAuctionProcessManagerTest, Basic) {
auto worklet = GetServiceExpectSuccess(kOriginA);
EXPECT_TRUE(worklet->GetService());
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType());
EXPECT_EQ(0u, GetActiveProcessesOfWorkletType(GetOtherWorkletType()));
EXPECT_EQ(0u, auction_process_manager_->GetIdleProcessCountForTesting());
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
MultipleRequestsForDifferentProcesses) {
auto worlket_a = GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA);
auto worklet_b = GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginB);
auto worklet_of_other_type_a =
GetServiceOfTypeExpectSuccess(GetOtherWorkletType(), kOriginA);
auto worklet_of_other_type_b =
GetServiceOfTypeExpectSuccess(GetOtherWorkletType(), kOriginB);
EXPECT_EQ(2u, GetActiveProcessesOfWorkletType(
AuctionProcessManager::WorkletType::kBidder));
EXPECT_EQ(2u, GetActiveProcessesOfWorkletType(
AuctionProcessManager::WorkletType::kSeller));
EXPECT_EQ(0u, auction_process_manager_->GetIdleProcessCountForTesting());
EXPECT_NE(worlket_a->GetService(), worklet_b->GetService());
EXPECT_NE(worlket_a->GetService(), worklet_of_other_type_a->GetService());
EXPECT_NE(worlket_a->GetService(), worklet_of_other_type_b->GetService());
EXPECT_NE(worklet_b->GetService(), worklet_of_other_type_a->GetService());
EXPECT_NE(worklet_b->GetService(), worklet_of_other_type_b->GetService());
EXPECT_NE(worklet_of_other_type_a->GetService(),
worklet_of_other_type_b->GetService());
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
MultipleRequestsForSameProcess) {
auto process_a1 = GetServiceExpectSuccess(kOriginA);
EXPECT_TRUE(process_a1->GetService());
auto process_a2 = GetServiceExpectSuccess(kOriginA);
EXPECT_EQ(process_a1->GetService(), process_a2->GetService());
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType());
auto process_a3 = GetServiceExpectSuccess(kOriginA);
EXPECT_EQ(process_a1->GetService(), process_a3->GetService());
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType());
std::unique_ptr<AuctionProcessManager::ProcessHandle> other_process_a1 =
GetServiceOfTypeExpectSuccess(GetOtherWorkletType(), kOriginA);
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType());
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType(GetOtherWorkletType()));
EXPECT_NE(process_a1->GetService(), other_process_a1->GetService());
}
TEST_P(SitePerProcessAuctionProcessManagerTest, LimitExceeded) {
CHECK_GE(GetMaxProcesses(), 3u);
struct Operation {
enum class Op {
kRequestHandles,
kDestroyHandle,
kDestroyHandleAndNextInQueue,
};
Op op;
std::optional<size_t> num_handles;
std::optional<size_t> index;
size_t expected_total_handles;
bool hit_limit_after_requesting_handles;
};
const Operation kOperationList[] = {
{Operation::Op::kRequestHandles,
GetMaxProcesses(),
std::nullopt,
GetMaxProcesses(),
false},
{Operation::Op::kDestroyHandle, std::nullopt,
1u, GetMaxProcesses() - 1},
{Operation::Op::kRequestHandles,
1,
std::nullopt,
GetMaxProcesses(),
false},
{Operation::Op::kDestroyHandle, std::nullopt,
0u, GetMaxProcesses() - 1},
{Operation::Op::kRequestHandles,
1,
std::nullopt,
GetMaxProcesses(),
false},
{Operation::Op::kDestroyHandle, std::nullopt,
GetMaxProcesses() - 1,
GetMaxProcesses() - 1},
{Operation::Op::kRequestHandles,
1,
std::nullopt,
GetMaxProcesses(),
false},
{Operation::Op::kRequestHandles,
3,
std::nullopt,
GetMaxProcesses() + 3,
true},
{Operation::Op::kDestroyHandle, std::nullopt,
GetMaxProcesses(),
GetMaxProcesses() + 2},
{Operation::Op::kDestroyHandle, std::nullopt,
GetMaxProcesses() + 1,
GetMaxProcesses() + 1},
{Operation::Op::kRequestHandles,
4,
std::nullopt,
GetMaxProcesses() + 5,
true},
{Operation::Op::kDestroyHandleAndNextInQueue,
std::nullopt, 0u,
GetMaxProcesses() + 3},
{Operation::Op::kDestroyHandle, std::nullopt,
GetMaxProcesses() - 1,
GetMaxProcesses() + 2},
{Operation::Op::kDestroyHandle, std::nullopt,
0u, GetMaxProcesses() + 1},
{Operation::Op::kDestroyHandle, std::nullopt,
1u, GetMaxProcesses()},
};
struct ProcessHandleData {
std::unique_ptr<AuctionProcessManager::ProcessHandle> process_handle =
std::make_unique<AuctionProcessManager::ProcessHandle>();
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
};
std::vector<ProcessHandleData> data;
int num_origins = 0;
for (const auto& operation : kOperationList) {
switch (operation.op) {
case Operation::Op::kRequestHandles:
for (size_t i = 0; i < *operation.num_handles; ++i) {
size_t original_size = data.size();
data.emplace_back(ProcessHandleData());
url::Origin distinct_origin = url::Origin::Create(
GURL(base::StringPrintf("https://%i.test", ++num_origins)));
base::HistogramTester histogram_tester;
ASSERT_EQ(original_size < GetMaxProcesses(),
auction_process_manager_->RequestWorkletService(
GetWorkletType(), distinct_origin, site_instance1_,
data.back().process_handle.get(),
data.back().run_loop->QuitClosure()));
RequestWorkletServiceOutcome expected_result =
operation.hit_limit_after_requesting_handles
? RequestWorkletServiceOutcome::kHitProcessLimit
: RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess;
histogram_tester.ExpectUniqueSample(
RequestWorkletServiceOutcomeUmaName(), expected_result,
1);
}
break;
case Operation::Op::kDestroyHandle: {
size_t original_size = data.size();
ASSERT_GT(data.size(), *operation.index);
data.erase(data.begin() + *operation.index);
if (*operation.index < GetMaxProcesses() &&
original_size > GetMaxProcesses()) {
data[GetMaxProcesses() - 1].run_loop->Run();
EXPECT_TRUE(data[GetMaxProcesses() - 1].process_handle->GetService());
}
break;
}
case Operation::Op::kDestroyHandleAndNextInQueue: {
ASSERT_GT(data.size(), *operation.index);
ASSERT_GT(data.size(), GetMaxProcesses() + 1);
data.erase(data.begin() + *operation.index);
data.erase(data.begin() + GetMaxProcesses());
data[GetMaxProcesses() - 1].run_loop->Run();
EXPECT_TRUE(data[GetMaxProcesses() - 1].process_handle->GetService());
break;
}
}
EXPECT_EQ(operation.expected_total_handles, data.size());
for (size_t i = 0; i < data.size() && i < GetMaxProcesses(); ++i) {
EXPECT_TRUE(data[i].process_handle->GetService());
for (size_t j = 0; j < i; ++j) {
EXPECT_NE(data[i].process_handle->GetService(),
data[j].process_handle->GetService());
}
}
base::RunLoop().RunUntilIdle();
for (size_t i = GetMaxProcesses(); i < data.size(); ++i) {
EXPECT_FALSE(data[i].run_loop->AnyQuitCalled());
EXPECT_FALSE(data[i].process_handle->GetService());
}
}
}
TEST_P(SitePerProcessAuctionProcessManagerTest, ProcessSharing) {
DCHECK_GT(GetMaxProcesses(), 1u);
std::vector<std::list<std::unique_ptr<AuctionProcessManager::ProcessHandle>>>
processes(GetMaxProcesses());
for (size_t origin_index = 0; origin_index < GetMaxProcesses();
++origin_index) {
url::Origin origin = url::Origin::Create(
GURL(base::StringPrintf("https://%zu.test", origin_index)));
base::HistogramTester histogram_tester;
for (size_t i = 0; i < 2 * GetMaxProcesses(); ++i) {
processes[origin_index].emplace_back(GetServiceExpectSuccess(origin));
EXPECT_EQ(processes[origin_index].back()->GetService(),
processes[origin_index].front()->GetService());
EXPECT_EQ(origin_index + 1, GetActiveProcessesOfWorkletType());
}
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess, 1);
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kUsedExistingDedicatedProcess,
2 * GetMaxProcesses() - 1);
for (size_t origin_index2 = 0; origin_index2 < origin_index;
++origin_index2) {
EXPECT_NE(processes[origin_index].front()->GetService(),
processes[origin_index2].front()->GetService());
}
}
base::RunLoop run_loop_delayed_a1;
auto process_delayed_a1 =
std::make_unique<AuctionProcessManager::ProcessHandle>();
ASSERT_FALSE(auction_process_manager_->RequestWorkletService(
GetWorkletType(), kOriginA, site_instance1_, process_delayed_a1.get(),
run_loop_delayed_a1.QuitClosure()));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(run_loop_delayed_a1.AnyQuitCalled());
EXPECT_FALSE(process_delayed_a1->GetService());
EXPECT_EQ(GetMaxProcesses(), GetActiveProcessesOfWorkletType());
base::RunLoop run_loop_delayed_a2;
auto process_delayed_a2 =
std::make_unique<AuctionProcessManager::ProcessHandle>();
ASSERT_FALSE(auction_process_manager_->RequestWorkletService(
GetWorkletType(), kOriginA, site_instance1_, process_delayed_a2.get(),
run_loop_delayed_a2.QuitClosure()));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(run_loop_delayed_a2.AnyQuitCalled());
EXPECT_FALSE(process_delayed_a2->GetService());
EXPECT_EQ(GetMaxProcesses(), GetActiveProcessesOfWorkletType());
base::RunLoop run_loop_delayed_b;
auto process_delayed_b =
std::make_unique<AuctionProcessManager::ProcessHandle>();
ASSERT_FALSE(auction_process_manager_->RequestWorkletService(
GetWorkletType(), kOriginB, site_instance1_, process_delayed_b.get(),
run_loop_delayed_b.QuitClosure()));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(run_loop_delayed_b.AnyQuitCalled());
EXPECT_FALSE(process_delayed_b->GetService());
EXPECT_EQ(GetMaxProcesses(), GetActiveProcessesOfWorkletType());
while (processes[0].size() > 1u) {
processes[0].pop_front();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(run_loop_delayed_a1.AnyQuitCalled());
EXPECT_FALSE(process_delayed_a1->GetService());
EXPECT_FALSE(run_loop_delayed_a2.AnyQuitCalled());
EXPECT_FALSE(process_delayed_a2->GetService());
EXPECT_FALSE(run_loop_delayed_b.AnyQuitCalled());
EXPECT_FALSE(process_delayed_b->GetService());
EXPECT_EQ(GetMaxProcesses(), GetActiveProcessesOfWorkletType());
}
processes[0].pop_front();
EXPECT_FALSE(run_loop_delayed_a1.AnyQuitCalled());
EXPECT_FALSE(process_delayed_a1->GetService());
EXPECT_FALSE(run_loop_delayed_a2.AnyQuitCalled());
EXPECT_FALSE(process_delayed_a2->GetService());
EXPECT_FALSE(run_loop_delayed_b.AnyQuitCalled());
EXPECT_FALSE(process_delayed_b->GetService());
run_loop_delayed_a1.Run();
run_loop_delayed_a2.Run();
EXPECT_TRUE(process_delayed_a1->GetService());
EXPECT_TRUE(process_delayed_a2->GetService());
EXPECT_EQ(process_delayed_a1->GetService(), process_delayed_a2->GetService());
EXPECT_FALSE(run_loop_delayed_b.AnyQuitCalled());
EXPECT_FALSE(process_delayed_b->GetService());
EXPECT_EQ(GetMaxProcesses(), GetActiveProcessesOfWorkletType());
process_delayed_a2.reset();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(run_loop_delayed_b.AnyQuitCalled());
EXPECT_FALSE(process_delayed_b->GetService());
process_delayed_a1.reset();
EXPECT_FALSE(run_loop_delayed_b.AnyQuitCalled());
EXPECT_FALSE(process_delayed_b->GetService());
run_loop_delayed_b.Run();
EXPECT_TRUE(process_delayed_b->GetService());
EXPECT_EQ(GetMaxProcesses(), GetActiveProcessesOfWorkletType());
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
DestroyHandlesWithPendingRequests) {
std::list<std::unique_ptr<AuctionProcessManager::ProcessHandle>> processes;
for (size_t i = 0; i < GetMaxProcesses(); ++i) {
url::Origin origin =
url::Origin::Create(GURL(base::StringPrintf("https://%zu.test", i)));
processes.emplace_back(GetServiceExpectSuccess(origin));
}
auto pending_process1 =
std::make_unique<AuctionProcessManager::ProcessHandle>();
ASSERT_FALSE(auction_process_manager_->RequestWorkletService(
GetWorkletType(), kOriginA, site_instance1_, pending_process1.get(),
NeverInvokedClosure()));
EXPECT_EQ(1u, GetPendingRequestsOfWorkletType());
pending_process1.reset();
EXPECT_EQ(0u, GetPendingRequestsOfWorkletType());
base::RunLoop().RunUntilIdle();
auto pending_process2 =
std::make_unique<AuctionProcessManager::ProcessHandle>();
ASSERT_FALSE(auction_process_manager_->RequestWorkletService(
GetWorkletType(), kOriginA, site_instance1_, pending_process2.get(),
NeverInvokedClosure()));
auto pending_process3 =
std::make_unique<AuctionProcessManager::ProcessHandle>();
base::RunLoop pending_process3_run_loop;
ASSERT_FALSE(auction_process_manager_->RequestWorkletService(
GetWorkletType(), kOriginB, site_instance1_, pending_process3.get(),
pending_process3_run_loop.QuitClosure()));
EXPECT_EQ(2u, GetPendingRequestsOfWorkletType());
processes.pop_front();
EXPECT_EQ(1u, GetPendingRequestsOfWorkletType());
pending_process2.reset();
pending_process3_run_loop.Run();
EXPECT_TRUE(pending_process3->GetService());
EXPECT_EQ(0u, auction_process_manager_->GetPendingSellerRequestsForTesting());
}
TEST_P(SitePerProcessAuctionProcessManagerTest, ProcessCrash) {
auto process = GetServiceExpectSuccess(kOriginA);
auction_worklet::mojom::AuctionWorkletService* service =
process->GetService();
EXPECT_TRUE(service);
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType());
ClosePipes();
EXPECT_EQ(0u, GetActiveProcessesOfWorkletType());
auto process2 = GetServiceExpectSuccess(kOriginA);
auction_worklet::mojom::AuctionWorkletService* service2 =
process2->GetService();
EXPECT_TRUE(service2);
EXPECT_NE(service, service2);
EXPECT_NE(process, process2);
EXPECT_EQ(1u, GetActiveProcessesOfWorkletType());
}
TEST_P(SitePerProcessAuctionProcessManagerTest, DisconnectBeforeDelete) {
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceExpectSuccess(kOriginA);
ClosePipes();
task_environment_.RunUntilIdle();
handle_a1.reset();
task_environment_.RunUntilIdle();
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
DoesNotStartAnticipatoryProcessIfFeatureDisabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kFledgeStartAnticipatoryProcesses);
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(0);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
ProcessLimitIsRespected_AnticipatoryProcessesOnly) {
for (size_t i = 0; i < GetMaxProcesses(); ++i) {
url::Origin origin =
url::Origin::Create(GURL(base::StringPrintf("https://%i.test", i)));
MaybeStartAnticipatoryProcess(origin, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1 + i);
}
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(GetMaxProcesses());
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
ProcessLimitIsRespected_ActiveAndAnticipatoryProcesses) {
MaybeStartAnticipatoryProcess(url::Origin::Create(GURL("https://0.test")),
GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
std::vector<std::unique_ptr<AuctionProcessManager::ProcessHandle>> handles;
for (size_t i = 0; i < GetMaxProcesses() - 1; ++i) {
url::Origin origin =
url::Origin::Create(GURL(base::StringPrintf("https://%i.test", i)));
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
RequestWorkletService(handles.back().get(), origin, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), handles.size());
origin =
url::Origin::Create(GURL(base::StringPrintf("https://%i.test", i + 1)));
MaybeStartAnticipatoryProcess(origin, GetWorkletType());
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), handles.size());
}
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), GetMaxProcesses() - 1);
MaybeStartAnticipatoryProcess(kOriginB, GetOtherWorkletType());
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 2u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), GetMaxProcesses() - 1);
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
RequestWorkletService(
handles.back().get(),
url::Origin::Create(
GURL(base::StringPrintf("https://%i.test", GetMaxProcesses() - 1))),
GetWorkletType(),
true, RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), GetMaxProcesses());
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
RequestWorkletService(handles.back().get(), kOriginB, GetWorkletType(),
false,
RequestWorkletServiceOutcome::kHitProcessLimit);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), GetMaxProcesses());
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
if (GetProcessMode() == ProcessMode::kDedicated) {
RequestWorkletService(handles.back().get(), kOriginC, GetOtherWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
} else {
RequestWorkletService(handles.back().get(), kOriginB, GetOtherWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
}
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), GetMaxProcesses());
handles.clear();
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 0u);
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
RequestWorkletService(
handles.back().get(), url::Origin::Create(GURL("https://worklet2.test")),
GetWorkletType(),
true,
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
MaybeStartAnticipatoryProcess(
url::Origin::Create(GURL("https://worklet3.test")), GetWorkletType());
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
DoNotStartMultipleProcessesSameOriginAndType) {
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
CanStartProcessesWithSameOriginIfOneIsSellerAndOneIsBuyer) {
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
MaybeStartAnticipatoryProcess(kOriginA, GetOtherWorkletType());
CheckOnlyIdleProcessesWithCount(2);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
DoNotStartProcessWithSameOriginAndTypeAsExistingProcess) {
AuctionProcessManager::ProcessHandle process_handle;
RequestWorkletService(
&process_handle, kOriginA, GetWorkletType(), true,
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
TryToUseAnticipatoryProcessOfSameOrDifferentOriginAndType) {
for (const auto& origin_to_request : {kOriginA, kOriginB}) {
SCOPED_TRACE(origin_to_request);
for (AuctionProcessManager::WorkletType worklet_type_to_request :
{GetWorkletType(), GetOtherWorkletType()}) {
SCOPED_TRACE(static_cast<int>(worklet_type_to_request));
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
if (GetProcessMode() == ProcessMode::kDedicated ||
(origin_to_request == kOriginA &&
worklet_type_to_request == GetWorkletType())) {
AuctionProcessManager::ProcessHandle handle;
RequestWorkletService(&handle, origin_to_request,
worklet_type_to_request,
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(worklet_type_to_request), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
0u);
} else {
AuctionProcessManager::ProcessHandle handle;
RequestWorkletService(
&handle, origin_to_request, worklet_type_to_request,
true,
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(worklet_type_to_request), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
1u);
AuctionProcessManager::ProcessHandle handle2;
RequestWorkletService(&handle2, kOriginA, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
0u);
}
CheckOnlyIdleProcessesWithCount(0);
}
}
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
ReassignsOrDestroysIdleProcessOfSameTypeOnlyAfterReachingLimit) {
MaybeStartAnticipatoryProcess(kOriginA, GetOtherWorkletType());
CheckOnlyIdleProcessesWithCount(1);
for (size_t i = 0; i < GetMaxProcesses(); ++i) {
url::Origin origin =
url::Origin::Create(GURL(base::StringPrintf("https://%i.test", i)));
MaybeStartAnticipatoryProcess(origin, GetWorkletType());
CheckOnlyIdleProcessesWithCount(2 + i);
}
std::vector<std::unique_ptr<AuctionProcessManager::ProcessHandle>> handles;
for (size_t i = 0; i < GetMaxProcesses(); ++i) {
url::Origin origin =
url::Origin::Create(GURL(base::StringPrintf("https://%i_2.test", i)));
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
if (GetProcessMode() == ProcessMode::kDedicated) {
RequestWorkletService(handles.back().get(), origin, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(ProcessCreationOrder(*handles.back()), i + 1u);
} else {
RequestWorkletService(
handles.back().get(), origin, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess);
EXPECT_EQ(ProcessCreationOrder(*handles.back()),
GetMaxProcesses() + i + 1u);
}
EXPECT_EQ(GetActiveProcessesOfWorkletType(), i + 1u);
}
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
ProcessesCanBeAssignedInDifferentOrderFromHowTheyWereMade) {
std::vector<std::tuple<url::Origin, AuctionProcessManager::WorkletType>>
origins_and_types;
for (url::Origin origin : {kOriginA, kOriginB, kOriginC}) {
for (AuctionProcessManager::WorkletType type :
{GetWorkletType(), GetOtherWorkletType()}) {
origins_and_types.emplace_back(origin, type);
MaybeStartAnticipatoryProcess(origin, type);
}
}
std::vector<std::unique_ptr<AuctionProcessManager::ProcessHandle>> handles;
for (size_t i = 0; i < origins_and_types.size(); i++) {
size_t inverse_index = origins_and_types.size() - 1 - i;
const auto& origin_and_type = origins_and_types[inverse_index];
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle =
std::make_unique<AuctionProcessManager::ProcessHandle>();
RequestWorkletService(
handle.get(), std::get<url::Origin>(origin_and_type),
std::get<AuctionProcessManager::WorkletType>(origin_and_type),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
if (GetProcessMode() == ProcessMode::kDedicated) {
EXPECT_EQ(ProcessCreationOrder(*handle), i);
} else {
EXPECT_EQ(ProcessCreationOrder(*handle), inverse_index);
}
EXPECT_EQ(GetActiveProcessesOfWorkletType(
AuctionProcessManager::WorkletType::kBidder) +
GetActiveProcessesOfWorkletType(
AuctionProcessManager::WorkletType::kSeller),
i + 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
inverse_index);
handles.push_back(std::move(handle));
}
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
DoesNotRecreateAnticipatoryProcessForOriginAfterAssigned) {
url::Origin origins[] = {kOriginA, kOriginB, kOriginC};
for (const url::Origin& origin_to_request_service : origins) {
CheckOnlyIdleProcessesWithCount(0);
for (const url::Origin& origin_for_anticipatory_process : origins) {
MaybeStartAnticipatoryProcess(origin_for_anticipatory_process,
GetWorkletType());
}
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 3u);
AuctionProcessManager::ProcessHandle handle;
RequestWorkletService(&handle, origin_to_request_service, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 2u);
for (const url::Origin& origin_for_anticipatory_process : origins) {
MaybeStartAnticipatoryProcess(origin_for_anticipatory_process,
GetWorkletType());
}
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 2u);
task_environment_.FastForwardBy(
features::kFledgeStartAnticipatoryProcessExpirationTime.Get());
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
}
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
RemovesProcessAfterExpirationTime) {
base::HistogramTester histogram_tester;
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
task_environment_.FastForwardBy(
features::kFledgeStartAnticipatoryProcessExpirationTime.Get() -
base::Milliseconds(1));
CheckOnlyIdleProcessesWithCount(1);
task_environment_.FastForwardBy(base::Milliseconds(1));
CheckOnlyIdleProcessesWithCount(0);
histogram_tester.ExpectUniqueSample(
"Ads.InterestGroup.Auction.IdleProcessExpired", true, 1);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
CorrectProcessGetsDeletedAfterExpiration) {
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
task_environment_.FastForwardBy(base::Milliseconds(1));
MaybeStartAnticipatoryProcess(kOriginB, GetWorkletType());
CheckOnlyIdleProcessesWithCount(2);
task_environment_.FastForwardBy(
features::kFledgeStartAnticipatoryProcessExpirationTime.Get() -
base::Milliseconds(2));
CheckOnlyIdleProcessesWithCount(2);
task_environment_.FastForwardBy(base::Milliseconds(1));
CheckOnlyIdleProcessesWithCount(1);
MaybeStartAnticipatoryProcess(kOriginB, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(2);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
DoesNotRemoveActiveProcessAfterExpirationTime) {
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(1);
AuctionProcessManager::ProcessHandle handle;
base::HistogramTester histogram_tester;
RequestWorkletService(&handle, kOriginA, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
task_environment_.FastForwardBy(
features::kFledgeStartAnticipatoryProcessExpirationTime.Get());
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
histogram_tester.ExpectUniqueSample(
"Ads.InterestGroup.Auction.IdleProcessExpired", false, 1);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
PrioritizesReadyIdleUnboundProcess) {
if (GetProcessMode() != ProcessMode::kDedicated) {
return;
}
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
MaybeStartAnticipatoryProcess(kOriginB, GetOtherWorkletType());
MaybeStartAnticipatoryProcess(kOriginC, GetWorkletType());
CheckOnlyIdleProcessesWithCount(3);
const size_t kLastCreatedProcessIndex = 2;
SimulateReadyProcess(kLastCreatedProcessIndex);
AuctionProcessManager::ProcessHandle handle1, handle2;
RequestWorkletService(&handle1, kOriginA, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
kLastCreatedProcessIndex);
EXPECT_EQ(ProcessCreationOrder(handle1), kLastCreatedProcessIndex);
RequestWorkletService(&handle2, kOriginB, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 2u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
EXPECT_EQ(ProcessCreationOrder(handle2), 0u);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
PrioritizesEarliestReadyUnboundIdleProcess) {
if (GetProcessMode() != ProcessMode::kDedicated) {
return;
}
std::vector<url::Origin> origins = {kOriginA, kOriginB, kOriginC};
for (const auto& origin : origins) {
MaybeStartAnticipatoryProcess(origin, GetWorkletType());
}
CheckOnlyIdleProcessesWithCount(3);
for (size_t i = 0; i < origins.size(); ++i) {
SimulateReadyProcess(i);
}
std::vector<std::unique_ptr<AuctionProcessManager::ProcessHandle>> handles;
for (size_t i = 0; i < origins.size(); ++i) {
handles.emplace_back(
std::make_unique<AuctionProcessManager::ProcessHandle>());
RequestWorkletService(handles.back().get(), origins[i], GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), i + 1);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 2 - i);
EXPECT_EQ(ProcessCreationOrder(*handles.back()), i);
}
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
PrioritizesReadyUnboundIdleProcessOfSameTypeIfOverLimit) {
if (GetProcessMode() != ProcessMode::kDedicated) {
return;
}
MaybeStartAnticipatoryProcess(kOriginA, GetOtherWorkletType());
CheckOnlyIdleProcessesWithCount(1);
for (size_t i = 0; i < GetMaxProcesses(); ++i) {
url::Origin origin =
url::Origin::Create(GURL(base::StringPrintf("https://%i.test", i)));
MaybeStartAnticipatoryProcess(origin, GetWorkletType());
CheckOnlyIdleProcessesWithCount(2 + i);
}
SimulateReadyProcess(GetMaxProcesses());
SimulateReadyProcess(0);
AuctionProcessManager::ProcessHandle handle1, handle2, handle3;
RequestWorkletService(&handle1, kOriginA, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
GetMaxProcesses());
EXPECT_EQ(ProcessCreationOrder(handle1), GetMaxProcesses());
RequestWorkletService(&handle2, kOriginB, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 2u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
GetMaxProcesses() - 1);
EXPECT_EQ(ProcessCreationOrder(handle2), 1u);
RequestWorkletService(&handle3, kOriginC, GetOtherWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(GetActiveProcessesOfWorkletType(), 2u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(GetOtherWorkletType()), 1u);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(),
GetMaxProcesses() - 2);
EXPECT_EQ(ProcessCreationOrder(handle3), 0u);
}
TEST_P(SitePerProcessAuctionProcessManagerTest, ProcessDeleteBeforeHandle) {
if (GetProcessMode() == ProcessMode::kDedicated) {
return;
}
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceExpectSuccess(kOriginA);
ASSERT_FALSE(rph_factory_.GetProcesses()->empty());
for (std::unique_ptr<MockRenderProcessHost>& proc :
*rph_factory_.GetProcesses()) {
proc.reset();
}
task_environment_.RunUntilIdle();
handle_a1.reset();
task_environment_.RunUntilIdle();
}
TEST_P(SitePerProcessAuctionProcessManagerTest, PidLookup) {
auto handle = GetServiceExpectSuccess(kOriginA);
base::ProcessId expected_pid = base::Process::Current().Pid();
base::RunLoop run_loop0, run_loop1;
bool got_pid0 = false, got_pid1 = false;
std::optional<base::ProcessId> pid0 =
handle->GetPid(base::BindLambdaForTesting(
[&run_loop0, &got_pid0, expected_pid](base::ProcessId pid) {
EXPECT_EQ(expected_pid, pid);
got_pid0 = true;
run_loop0.Quit();
}));
EXPECT_FALSE(pid0.has_value());
std::optional<base::ProcessId> pid1 =
handle->GetPid(base::BindLambdaForTesting(
[&run_loop1, &got_pid1, expected_pid](base::ProcessId pid) {
EXPECT_EQ(expected_pid, pid);
got_pid1 = true;
run_loop1.Quit();
}));
EXPECT_FALSE(pid1.has_value());
if (dedicated_process_manager_) {
SimulateReadyProcess(0);
} else {
for (std::unique_ptr<MockRenderProcessHost>& proc :
*rph_factory_.GetProcesses()) {
proc->SimulateReady();
}
}
run_loop0.Run();
EXPECT_TRUE(got_pid0);
run_loop1.Run();
EXPECT_TRUE(got_pid1);
std::optional<base::ProcessId> pid2 =
handle->GetPid(base::BindOnce([](base::ProcessId pid) {
ADD_FAILURE() << "Should not get to callback in pid2 case";
}));
EXPECT_EQ(expected_pid, pid2);
auto handle2 = GetServiceExpectSuccess(kOriginA);
std::optional<base::ProcessId> pid3 =
handle2->GetPid(base::BindOnce([](base::ProcessId pid) {
ADD_FAILURE() << "Should not get to callback in pid2 case";
}));
EXPECT_EQ(expected_pid, pid3);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
PidLookupRendererProcessAlreadyRunning) {
if (GetProcessMode() == ProcessMode::kDedicated) {
return;
}
scoped_refptr<SiteInstance> frame_site_instance =
site_instance1_->GetRelatedSiteInstance(kOriginA.GetURL());
frame_site_instance->GetOrCreateProcessForTesting()->Init();
for (std::unique_ptr<MockRenderProcessHost>& proc :
*rph_factory_.GetProcesses()) {
proc->SimulateReady();
}
auto handle = GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
frame_site_instance);
base::ProcessId expected_pid = base::Process::Current().Pid();
std::optional<base::ProcessId> pid0 =
handle->GetPid(base::BindOnce([](base::ProcessId pid) {
ADD_FAILURE() << "Should not get to callback in pid0 case";
}));
ASSERT_TRUE(pid0.has_value());
EXPECT_EQ(expected_pid, pid0.value());
std::optional<base::ProcessId> pid1 =
handle->GetPid(base::BindOnce([](base::ProcessId pid) {
ADD_FAILURE() << "Should not get to callback in pid1 case";
}));
ASSERT_TRUE(pid1.has_value());
EXPECT_EQ(expected_pid, pid1.value());
}
TEST_P(SharedRendererInRendererAuctionProcessManagerTest,
MultipleSiteInstances) {
base::HistogramTester histogram_tester;
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance1_);
int id_a1 = handle_a1->GetRenderProcessHostForTesting()->GetDeprecatedID();
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance2_);
int id_a2 = handle_a2->GetRenderProcessHostForTesting()->GetDeprecatedID();
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginB,
site_instance1_);
int id_b1 = handle_b1->GetRenderProcessHostForTesting()->GetDeprecatedID();
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginB,
site_instance2_);
int id_b2 = handle_b2->GetRenderProcessHostForTesting()->GetDeprecatedID();
EXPECT_NE(id_a1, id_a2);
EXPECT_EQ(id_a1, id_b1);
EXPECT_NE(id_a1, id_b2);
EXPECT_NE(id_a2, id_b1);
EXPECT_EQ(id_a2, id_b2);
EXPECT_NE(id_b1, id_b2);
histogram_tester.ExpectUniqueSample(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kUsedSharedProcess, 4);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_i1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kIsolatedOrigin,
site_instance1_);
int id_i1 = handle_i1->GetRenderProcessHostForTesting()->GetDeprecatedID();
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_i2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kIsolatedOrigin,
site_instance2_);
int id_i2 = handle_i2->GetRenderProcessHostForTesting()->GetDeprecatedID();
EXPECT_EQ(id_i1, id_i2);
EXPECT_NE(id_i1, id_a1);
EXPECT_NE(id_i1, id_a2);
EXPECT_NE(id_i1, id_b1);
EXPECT_NE(id_i1, id_b2);
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess, 1);
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kUsedExistingDedicatedProcess, 1);
}
TEST_P(SharedRendererInRendererAuctionProcessManagerTest,
MaybeStartAnticipatoryProcess_DoesNotStartIfSharedProcessPossible) {
MaybeStartAnticipatoryProcess(kOriginA, GetWorkletType());
CheckOnlyIdleProcessesWithCount(0);
}
TEST_P(SharedRendererInRendererAuctionProcessManagerTest,
MaybeStartAnticipatoryProcess_StartsProcessForIsolatedOrigin) {
MaybeStartAnticipatoryProcess(kIsolatedOrigin);
CheckOnlyIdleProcessesWithCount(1);
AuctionProcessManager::ProcessHandle handle1, handle2;
RequestWorkletService(&handle1, kOriginA, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedSharedProcess);
CheckOnlyIdleProcessesWithCount(1);
RequestWorkletService(&handle2, kIsolatedOrigin, GetWorkletType(),
true,
RequestWorkletServiceOutcome::kUsedIdleProcess);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
EXPECT_EQ(GetActiveProcessesOfWorkletType(GetWorkletType()), 1u);
}
TEST_P(SitePerProcessAuctionProcessManagerTest, MultipleSiteInstances) {
base::HistogramTester histogram_tester;
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance1_);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance2_);
EXPECT_EQ(handle_a1->worklet_process_for_testing(),
handle_a2->worklet_process_for_testing());
EXPECT_EQ(handle_a1->GetService(), handle_a2->GetService());
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginB,
site_instance1_);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginB,
site_instance2_);
EXPECT_EQ(handle_b1->worklet_process_for_testing(),
handle_b2->worklet_process_for_testing());
EXPECT_EQ(handle_b1->GetService(), handle_b2->GetService());
EXPECT_NE(handle_a1->worklet_process_for_testing(),
handle_b1->worklet_process_for_testing());
EXPECT_NE(handle_a1->GetService(), handle_b1->GetService());
if (GetProcessMode() != ProcessMode::kDedicated) {
EXPECT_NE(handle_a1->GetRenderProcessHostForTesting()->GetDeprecatedID(),
handle_b1->GetRenderProcessHostForTesting()->GetDeprecatedID());
}
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess, 2);
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kUsedExistingDedicatedProcess, 2);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_i1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kIsolatedOrigin,
site_instance1_);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_i2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kIsolatedOrigin,
site_instance2_);
EXPECT_EQ(handle_i1->worklet_process_for_testing(),
handle_i2->worklet_process_for_testing());
EXPECT_EQ(handle_i1->GetService(), handle_i2->GetService());
if (GetProcessMode() != ProcessMode::kDedicated) {
EXPECT_NE(handle_i1->GetRenderProcessHostForTesting()->GetDeprecatedID(),
handle_a1->GetRenderProcessHostForTesting()->GetDeprecatedID());
EXPECT_NE(handle_i1->GetRenderProcessHostForTesting()->GetDeprecatedID(),
handle_b1->GetRenderProcessHostForTesting()->GetDeprecatedID());
}
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kCreatedNewDedicatedProcess, 3);
histogram_tester.ExpectBucketCount(
RequestWorkletServiceOutcomeUmaName(),
RequestWorkletServiceOutcome::kUsedExistingDedicatedProcess, 3);
}
TEST_P(SharedRendererInRendererAuctionProcessManagerTest, PolicyChange) {
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance1_);
EXPECT_FALSE(
handle_a1->site_instance_for_testing()->RequiresDedicatedProcess());
RenderProcessHost* shared_process =
handle_a1->GetRenderProcessHostForTesting();
SiteInstance::StartIsolatingSite(
&test_browser_context_, kOriginA.GetURL(),
ChildProcessSecurityPolicy::IsolatedOriginSource::TEST);
site_instance1_ = SiteInstance::Create(&test_browser_context_);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a2 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance1_);
EXPECT_TRUE(
handle_a2->site_instance_for_testing()->RequiresDedicatedProcess());
EXPECT_NE(handle_a2->GetRenderProcessHostForTesting(), shared_process);
handle_a1.reset();
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a3 =
GetServiceOfTypeExpectSuccess(GetWorkletType(), kOriginA,
site_instance1_);
EXPECT_TRUE(
handle_a3->site_instance_for_testing()->RequiresDedicatedProcess());
EXPECT_EQ(handle_a2->GetRenderProcessHostForTesting(),
handle_a3->GetRenderProcessHostForTesting());
EXPECT_EQ(handle_a2->worklet_process_for_testing(),
handle_a3->worklet_process_for_testing());
}
TEST_P(SitePerProcessAuctionProcessManagerTest, TrustedSignalsCache) {
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceExpectSuccess(kOriginA);
ValidateCacheRemote(*handle_a1, kOriginA);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a2 =
GetServiceExpectSuccess(kOriginA);
EXPECT_EQ(handle_a1->GetService(), handle_a2->GetService());
ValidateCacheRemote(*handle_a2, kOriginA);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b =
GetServiceExpectSuccess(kOriginB);
EXPECT_NE(handle_a1->GetService(), handle_b->GetService());
ValidateCacheRemote(*handle_b, kOriginB);
}
TEST_P(SitePerProcessAuctionProcessManagerTest,
TrustedSignalsCacheSentToAnticipatoryProcess) {
MaybeStartAnticipatoryProcess(kOriginA);
MaybeStartAnticipatoryProcess(kOriginA);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 1u);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceExpectSuccess(kOriginA);
ValidateCacheRemote(*handle_a1, kOriginA);
EXPECT_EQ(auction_process_manager_->GetIdleProcessCountForTesting(), 0u);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a2 =
GetServiceExpectSuccess(kOriginA);
EXPECT_EQ(handle_a1->GetService(), handle_a2->GetService());
ValidateCacheRemote(*handle_a2, kOriginA);
MaybeStartAnticipatoryProcess(kOriginA);
ValidateCacheRemote(*handle_a1, kOriginA);
}
TEST_P(SitePerProcessAuctionProcessManagerTest, TrustedSignalsCacheDisabled) {
CreateAuctionProcessManager(nullptr);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a =
GetServiceExpectSuccess(kOriginA);
ExpectNoCacheRemote(*handle_a);
MaybeStartAnticipatoryProcess(kOriginB);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b =
GetServiceExpectSuccess(kOriginB);
ExpectNoCacheRemote(*handle_b);
}
TEST_P(SharedRendererInRendererAuctionProcessManagerTest, TrustedSignalsCache) {
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a1 =
GetServiceExpectSuccess(kOriginA);
ValidateCacheRemote(*handle_a1, kOriginA);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_a2 =
GetServiceExpectSuccess(kOriginA);
EXPECT_NE(handle_a1->GetService(), handle_a2->GetService());
ValidateCacheRemote(*handle_a2, kOriginA);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle_b =
GetServiceExpectSuccess(kOriginB);
ValidateCacheRemote(*handle_b, kOriginB);
}
TEST_P(SharedRendererInRendererAuctionProcessManagerTest,
TrustedSignalsCacheDisabled) {
CreateAuctionProcessManager(nullptr);
std::unique_ptr<AuctionProcessManager::ProcessHandle> handle =
GetServiceExpectSuccess(kOriginA);
ExpectNoCacheRemote(*handle);
}
}
}