blob: c0108c59ca06aa8ea652655e25e31e35fc89de65 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/interest_group/mock_auction_process_manager.h"
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/functional/bind.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/time/time.h"
#include "content/browser/interest_group/auction_process_manager.h"
#include "content/public/browser/site_instance.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/private_aggregation_request.mojom.h"
#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/interest_group/auction_config.h"
#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
MockBidderWorklet::MockBidderWorklet(
mojo::PendingReceiver<auction_worklet::mojom::BidderWorklet>
pending_receiver,
const std::map<std::string, base::TimeDelta>& expected_per_buyer_timeouts)
: expected_per_buyer_timeouts_(expected_per_buyer_timeouts),
receiver_(this, std::move(pending_receiver)) {
receiver_.set_disconnect_handler(
base::BindOnce(&MockBidderWorklet::OnPipeClosed, base::Unretained(this)));
}
MockBidderWorklet::~MockBidderWorklet() {
// `send_pending_signals_requests_called_` should always be called if any
// bids are generated, except in the unlikely event that the Mojo pipe is
// closed before a posted task is executed (this cannot be simulated by
// closing a pipe in tests, due to vagaries of timing of the two messages).
if (generate_bid_called_) {
// Flush the receiver in case the message is pending on the pipe. This
// doesn't happen when the auction has run successfully, where the auction
// only completes when all messages have been received, but may happen in
// failure cases where the message is sent, but the AuctionRunner is torn
// down early.
if (receiver_.is_bound()) {
receiver_.FlushForTesting();
}
EXPECT_TRUE(send_pending_signals_requests_called_);
}
}
void MockBidderWorklet::BeginGenerateBid(
auction_worklet::mojom::BidderWorkletNonSharedParamsPtr
bidder_worklet_non_shared_params,
auction_worklet::mojom::KAnonymityBidMode kanon_mode,
const url::Origin& interest_group_join_origin,
const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
const absl::optional<GURL>& direct_from_seller_auction_signals,
const url::Origin& browser_signal_seller_origin,
const absl::optional<url::Origin>& browser_signal_top_level_seller_origin,
auction_worklet::mojom::BiddingBrowserSignalsPtr bidding_browser_signals,
base::Time auction_start_time,
uint64_t trace_id,
mojo::PendingAssociatedRemote<auction_worklet::mojom::GenerateBidClient>
generate_bid_client,
mojo::PendingAssociatedReceiver<
auction_worklet::mojom::GenerateBidFinalizer> bid_finalizer) {
generate_bid_called_ = true;
// While the real BidderWorklet implementation supports multiple pending
// callbacks, this class does not.
DCHECK(!generate_bid_client_);
// per_buyer_timeout passed that will be passed to FinishGenerateBid()
// should not be empty, because auction_config's all_buyers_timeout (which
// is the key of '*' in perBuyerTimeouts) is set in the AuctionRunnerTest.
// Figure out what it should expect here (and save it into the receiver set
// as context info) since the bidder name isn't easily available at
// FinishGenerateBid time.
auto it =
expected_per_buyer_timeouts_.find(bidder_worklet_non_shared_params->name);
CHECK(it != expected_per_buyer_timeouts_.end());
base::TimeDelta expected_per_buyer_timeout = it->second;
// Single auctions should invoke all GenerateBid() calls on a worklet
// before invoking SendPendingSignalsRequests().
EXPECT_FALSE(send_pending_signals_requests_called_);
finalizer_receiver_set_.Add(this, std::move(bid_finalizer),
expected_per_buyer_timeout);
generate_bid_client_.Bind(std::move(generate_bid_client));
}
void MockBidderWorklet::SendPendingSignalsRequests() {
// This allows multiple calls.
send_pending_signals_requests_called_ = true;
}
void MockBidderWorklet::ReportWin(
auction_worklet::mojom::ReportingIdField reporting_id_field,
const std::string& reporting_id,
const absl::optional<std::string>& auction_signals_json,
const absl::optional<std::string>& per_buyer_signals_json,
const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
const absl::optional<GURL>& direct_from_seller_auction_signals,
const std::string& seller_signals_json,
const GURL& browser_signal_render_url,
double browser_signal_bid,
const absl::optional<blink::AdCurrency>& browser_signal_bid_currency,
double browser_signal_highest_scoring_other_bid,
const absl::optional<blink::AdCurrency>&
browser_signal_highest_scoring_other_bid_currency,
bool browser_signal_made_highest_scoring_other_bid,
absl::optional<double> browser_signal_ad_cost,
absl::optional<uint16_t> browser_signal_modeling_signals,
uint8_t browser_signal_join_count,
uint8_t browser_signal_recency,
const url::Origin& browser_signal_seller_origin,
const absl::optional<url::Origin>& browser_signal_top_level_seller_origin,
uint32_t bidding_signals_data_version,
bool has_bidding_signals_data_version,
uint64_t trace_id,
ReportWinCallback report_win_callback) {
// While the real BidderWorklet implementation supports multiple pending
// callbacks, this class does not.
DCHECK(!report_win_callback_);
report_win_callback_ = std::move(report_win_callback);
if (report_win_run_loop_) {
report_win_run_loop_->Quit();
}
}
void MockBidderWorklet::ConnectDevToolsAgent(
mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent) {
ADD_FAILURE()
<< "ConnectDevToolsAgent should not be called on MockBidderWorklet";
}
void MockBidderWorklet::FinishGenerateBid(
const absl::optional<std::string>& auction_signals_json,
const absl::optional<std::string>& per_buyer_signals_json,
const absl::optional<base::TimeDelta> per_buyer_timeout,
const absl::optional<blink::AdCurrency>& per_buyer_currency,
const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
const absl::optional<GURL>& direct_from_seller_auction_signals) {
// per_buyer_timeout passed to GenerateBid() should not be empty, because
// auction_config's all_buyers_timeout (which is the key of '*' in
// perBuyerTimeouts) is set in the AuctionRunnerTest.
ASSERT_TRUE(per_buyer_timeout.has_value());
// The actual expected value is stashed by BeginGenerateBid into the
// context.
EXPECT_EQ(per_buyer_timeout.value(),
finalizer_receiver_set_.current_context());
if (generate_bid_run_loop_) {
generate_bid_run_loop_->Quit();
}
}
void MockBidderWorklet::WaitForGenerateBid() {
if (!generate_bid_client_) {
generate_bid_run_loop_ = std::make_unique<base::RunLoop>();
generate_bid_run_loop_->Run();
generate_bid_run_loop_.reset();
DCHECK(generate_bid_client_);
}
}
void MockBidderWorklet::SetBidderTrustedSignalsFetchLatency(
base::TimeDelta delta) {
trusted_signals_fetch_latency_ = delta;
}
void MockBidderWorklet::SetBiddingLatency(base::TimeDelta delta) {
bidding_latency_ = delta;
}
void MockBidderWorklet::InvokeGenerateBidCallback(
absl::optional<double> bid,
const absl::optional<blink::AdCurrency>& bid_currency,
const blink::AdDescriptor& ad_descriptor,
auction_worklet::mojom::BidderWorkletKAnonEnforcedBidPtr mojo_kanon_bid,
absl::optional<std::vector<blink::AdDescriptor>> ad_component_descriptors,
base::TimeDelta duration,
const absl::optional<uint32_t>& bidding_signals_data_version,
const absl::optional<GURL>& debug_loss_report_url,
const absl::optional<GURL>& debug_win_report_url,
std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
pa_requests,
auction_worklet::mojom::GenerateBidDependencyLatenciesPtr
dependency_latencies,
auction_worklet::mojom::RejectReason reject_reason) {
WaitForGenerateBid();
base::RunLoop run_loop;
generate_bid_client_->OnBiddingSignalsReceived(
/*priority_vector=*/{},
/*trusted_signals_fetch_latency=*/trusted_signals_fetch_latency_,
run_loop.QuitClosure());
run_loop.Run();
if (!dependency_latencies) {
dependency_latencies =
auction_worklet::mojom::GenerateBidDependencyLatencies::New(
/*code_ready_latency=*/absl::nullopt,
/*config_promises_latency=*/absl::nullopt,
/*direct_from_seller_signals_latency=*/absl::nullopt,
/*trusted_bidding_signals_latency=*/absl::nullopt);
}
if (!bid.has_value()) {
generate_bid_client_->OnGenerateBidComplete(
/*bid=*/nullptr,
/*kanon_bid=*/std::move(mojo_kanon_bid),
/*bidding_signals_data_version=*/0,
/*has_bidding_signals_data_version=*/false, debug_loss_report_url,
/*debug_win_report_url=*/absl::nullopt,
/*set_priority=*/0,
/*has_set_priority=*/false,
/*update_priority_signals_overrides=*/
base::flat_map<std::string,
auction_worklet::mojom::PrioritySignalsDoublePtr>(),
/*pa_requests=*/std::move(pa_requests),
/*non_kanon_pa_requests=*/{},
/*bidding_latency=*/bidding_latency_,
/*generate_bid_dependency_latencies=*/std::move(dependency_latencies),
reject_reason,
/*errors=*/std::vector<std::string>());
return;
}
generate_bid_client_->OnGenerateBidComplete(
auction_worklet::mojom::BidderWorkletBid::New(
"ad", *bid, bid_currency, /*ad_cost=*/absl::nullopt,
std::move(ad_descriptor), ad_component_descriptors,
/*modeling_signals=*/absl::nullopt, duration),
/*kanon_bid=*/std::move(mojo_kanon_bid),
bidding_signals_data_version.value_or(0),
bidding_signals_data_version.has_value(), debug_loss_report_url,
debug_win_report_url,
/*set_priority=*/0,
/*has_set_priority=*/false,
/*update_priority_signals_overrides=*/
base::flat_map<std::string,
auction_worklet::mojom::PrioritySignalsDoublePtr>(),
/*pa_requests=*/std::move(pa_requests),
/*non_kanon_pa_requests=*/{},
/*bidding_latency=*/bidding_latency_,
/*generate_bid_dependency_latencies=*/std::move(dependency_latencies),
reject_reason,
/*errors=*/std::vector<std::string>());
}
void MockBidderWorklet::WaitForReportWin() {
DCHECK(!generate_bid_client_);
DCHECK(!report_win_run_loop_);
if (!report_win_callback_) {
report_win_run_loop_ = std::make_unique<base::RunLoop>();
report_win_run_loop_->Run();
report_win_run_loop_.reset();
DCHECK(report_win_callback_);
}
}
void MockBidderWorklet::InvokeReportWinCallback(
absl::optional<GURL> report_url,
base::flat_map<std::string, GURL> ad_beacon_map,
std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
pa_requests,
std::vector<std::string> errors) {
DCHECK(report_win_callback_);
std::move(report_win_callback_)
.Run(report_url, ad_beacon_map, std::move(pa_requests),
std::move(errors));
}
void MockBidderWorklet::Flush() {
receiver_.FlushForTesting();
}
bool MockBidderWorklet::PipeIsClosed() {
receiver_.FlushForTesting();
return pipe_closed_;
}
MockSellerWorklet::ScoreAdParams::ScoreAdParams() = default;
MockSellerWorklet::ScoreAdParams::ScoreAdParams(ScoreAdParams&&) = default;
MockSellerWorklet::ScoreAdParams::~ScoreAdParams() = default;
MockSellerWorklet::ScoreAdParams& MockSellerWorklet::ScoreAdParams::operator=(
ScoreAdParams&&) = default;
MockSellerWorklet::MockSellerWorklet(
mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
pending_receiver)
: receiver_(this, std::move(pending_receiver)) {}
MockSellerWorklet::~MockSellerWorklet() {
// Flush the receiver in case the message is pending on the pipe. This
// doesn't happen when the auction has run successfully, where the auction
// only completes when all messages have been received, but may happen in
// failure cases where the message is sent, but the AuctionRunner is torn
// down early.
if (receiver_.is_bound()) {
receiver_.FlushForTesting();
}
EXPECT_EQ(expect_send_pending_signals_requests_called_,
send_pending_signals_requests_called_);
// Every received ScoreAd() call should have been waited for.
EXPECT_TRUE(score_ad_params_.empty());
}
void MockSellerWorklet::ScoreAd(
const std::string& ad_metadata_json,
double bid,
const absl::optional<blink::AdCurrency>& bid_currency,
const blink::AuctionConfig::NonSharedParams&
auction_ad_config_non_shared_params,
const absl::optional<GURL>& direct_from_seller_seller_signals,
const absl::optional<GURL>& direct_from_seller_auction_signals,
auction_worklet::mojom::ComponentAuctionOtherSellerPtr
browser_signals_other_seller,
const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
const url::Origin& browser_signal_interest_group_owner,
const GURL& browser_signal_render_url,
const std::vector<GURL>& browser_signal_ad_components,
uint32_t browser_signal_bidding_duration_msecs,
const absl::optional<base::TimeDelta> seller_timeout,
uint64_t trace_id,
mojo::PendingRemote<auction_worklet::mojom::ScoreAdClient>
score_ad_client) {
// SendPendingSignalsRequests() should only be called once all ads are
// scored.
EXPECT_FALSE(send_pending_signals_requests_called_);
ASSERT_TRUE(seller_timeout.has_value());
// seller_timeout in auction_config higher than 500 ms should be clamped to
// 500 ms by the AuctionRunner before passed to ScoreAd(), and
// auction_config's seller_timeout is 1000 ms so it should be 500 ms here.
EXPECT_EQ(seller_timeout.value(), base::Milliseconds(500));
ScoreAdParams score_ad_params;
score_ad_params.score_ad_client = std::move(score_ad_client);
score_ad_params.bid = bid;
score_ad_params.interest_group_owner = browser_signal_interest_group_owner;
score_ad_params_.emplace_front(std::move(score_ad_params));
if (score_ad_run_loop_) {
score_ad_run_loop_->Quit();
}
}
void MockSellerWorklet::SendPendingSignalsRequests() {
// SendPendingSignalsRequests() should only be called once by a single
// AuctionRunner.
EXPECT_FALSE(send_pending_signals_requests_called_);
send_pending_signals_requests_called_ = true;
}
void MockSellerWorklet::ReportResult(
const blink::AuctionConfig::NonSharedParams&
auction_ad_config_non_shared_params,
const absl::optional<GURL>& direct_from_seller_seller_signals,
const absl::optional<GURL>& direct_from_seller_auction_signals,
auction_worklet::mojom::ComponentAuctionOtherSellerPtr
browser_signals_other_seller,
const url::Origin& browser_signal_interest_group_owner,
const absl::optional<std::string>&
browser_signal_buyer_and_seller_reporting_id,
const GURL& browser_signal_render_url,
double browser_signal_bid,
const absl::optional<blink::AdCurrency>& browser_signal_bid_currency,
double browser_signal_desirability,
double browser_signal_highest_scoring_other_bid,
const absl::optional<blink::AdCurrency>&
browser_signal_highest_scoring_other_bid_currency,
auction_worklet::mojom::ComponentAuctionReportResultParamsPtr
browser_signals_component_auction_report_result_params,
uint32_t browser_signal_data_version,
bool browser_signal_has_data_version,
uint64_t trace_id,
ReportResultCallback report_result_callback) {
report_result_callback_ = std::move(report_result_callback);
if (report_result_run_loop_) {
report_result_run_loop_->Quit();
}
}
void MockSellerWorklet::ConnectDevToolsAgent(
mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent) {
ADD_FAILURE()
<< "ConnectDevToolsAgent should not be called on MockSellerWorklet";
}
void MockSellerWorklet::ResetReceiverWithReason(const std::string& reason) {
receiver_.ResetWithReason(/*custom_reason_code=*/0, reason);
}
// Waits until ScoreAd() has been invoked, if it hasn't been already. It's up
// to the caller to invoke the returned ScoreAdParams::callback to continue
// the auction.
MockSellerWorklet::ScoreAdParams MockSellerWorklet::WaitForScoreAd() {
DCHECK(!score_ad_run_loop_);
if (score_ad_params_.empty()) {
score_ad_run_loop_ = std::make_unique<base::RunLoop>();
score_ad_run_loop_->Run();
score_ad_run_loop_.reset();
DCHECK(!score_ad_params_.empty());
}
ScoreAdParams out = std::move(score_ad_params_.front());
score_ad_params_.pop_front();
return out;
}
void MockSellerWorklet::WaitForReportResult() {
DCHECK(!report_result_run_loop_);
if (!report_result_callback_) {
report_result_run_loop_ = std::make_unique<base::RunLoop>();
report_result_run_loop_->Run();
report_result_run_loop_.reset();
DCHECK(report_result_callback_);
}
}
void MockSellerWorklet::InvokeReportResultCallback(
absl::optional<GURL> report_url,
base::flat_map<std::string, GURL> ad_beacon_map,
std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>
pa_requests,
std::vector<std::string> errors) {
DCHECK(report_result_callback_);
std::move(report_result_callback_)
.Run(/*signals_for_winner=*/absl::nullopt, std::move(report_url),
ad_beacon_map, std::move(pa_requests), errors);
}
void MockSellerWorklet::Flush() {
receiver_.FlushForTesting();
}
MockAuctionProcessManager::MockAuctionProcessManager() = default;
MockAuctionProcessManager::~MockAuctionProcessManager() = default;
RenderProcessHost* MockAuctionProcessManager::LaunchProcess(
mojo::PendingReceiver<auction_worklet::mojom::AuctionWorkletService>
auction_worklet_service_receiver,
const ProcessHandle* handle,
const std::string& display_name) {
mojo::ReceiverId receiver_id =
receiver_set_.Add(this, std::move(auction_worklet_service_receiver));
// Each receiver should get a unique display name. This check serves to help
// ensure that processes are correctly reused.
EXPECT_EQ(0u, receiver_display_name_map_.count(receiver_id));
for (auto receiver : receiver_display_name_map_) {
// Ignore closed receivers. ReportWin() will result in re-loading a
// worklet, after closing the original worklet, which may require
// re-creating the AuctionWorkletService.
if (receiver_set_.HasReceiver(receiver.first)) {
EXPECT_NE(receiver.second, display_name);
}
}
receiver_display_name_map_[receiver_id] = display_name;
return nullptr;
}
scoped_refptr<SiteInstance> MockAuctionProcessManager::MaybeComputeSiteInstance(
SiteInstance* frame_site_instance,
const url::Origin& worklet_origin) {
return nullptr;
}
bool MockAuctionProcessManager::TryUseSharedProcess(
ProcessHandle* process_handle) {
return false;
}
void MockAuctionProcessManager::LoadBidderWorklet(
mojo::PendingReceiver<auction_worklet::mojom::BidderWorklet>
bidder_worklet_receiver,
mojo::PendingRemote<auction_worklet::mojom::AuctionSharedStorageHost>
shared_storage_host_remote,
bool pause_for_debugger_on_start,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
pending_url_loader_factory,
const GURL& script_source_url,
const absl::optional<GURL>& bidding_wasm_helper_url,
const absl::optional<GURL>& trusted_bidding_signals_url,
const url::Origin& top_window_origin,
auction_worklet::mojom::AuctionWorkletPermissionsPolicyStatePtr
permissions_policy_state,
bool has_experiment_group_id,
uint16_t experiment_group_id) {
// Make sure this request came over the right pipe.
url::Origin owner = url::Origin::Create(script_source_url);
EXPECT_EQ(receiver_display_name_map_[receiver_set_.current_receiver()],
ComputeDisplayName(AuctionProcessManager::WorkletType::kBidder,
url::Origin::Create(script_source_url)));
EXPECT_EQ(0u, bidder_worklets_.count(script_source_url));
bidder_worklets_.emplace(
script_source_url,
std::make_unique<MockBidderWorklet>(std::move(bidder_worklet_receiver),
expected_per_buyer_timeouts_));
MaybeQuitWaitForWorkletsRunLoop();
}
void MockAuctionProcessManager::LoadSellerWorklet(
mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
seller_worklet_receiver,
mojo::PendingRemote<auction_worklet::mojom::AuctionSharedStorageHost>
shared_storage_host_remote,
bool should_pause_on_start,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
pending_url_loader_factory,
const GURL& script_source_url,
const absl::optional<GURL>& trusted_scoring_signals_url,
const url::Origin& top_window_origin,
auction_worklet::mojom::AuctionWorkletPermissionsPolicyStatePtr
permissions_policy_state,
bool has_experiment_group_id,
uint16_t experiment_group_id) {
EXPECT_EQ(0u, seller_worklets_.count(script_source_url));
// Make sure this request came over the right pipe.
EXPECT_EQ(receiver_display_name_map_[receiver_set_.current_receiver()],
ComputeDisplayName(AuctionProcessManager::WorkletType::kSeller,
url::Origin::Create(script_source_url)));
seller_worklets_.emplace(
script_source_url,
std::make_unique<MockSellerWorklet>(std::move(seller_worklet_receiver)));
MaybeQuitWaitForWorkletsRunLoop();
}
void MockAuctionProcessManager::SetExpectedBuyerBidTimeout(
const std::string& name,
base::TimeDelta value) {
expected_per_buyer_timeouts_[name] = value;
}
void MockAuctionProcessManager::WaitForWorklets(int num_bidders,
int num_sellers) {
DCHECK(!wait_for_worklets_run_loop_);
waiting_for_num_bidders_ = num_bidders;
waiting_for_num_sellers_ = num_sellers;
wait_for_worklets_run_loop_ = std::make_unique<base::RunLoop>();
MaybeQuitWaitForWorkletsRunLoop();
wait_for_worklets_run_loop_->Run();
wait_for_worklets_run_loop_.reset();
EXPECT_EQ(waiting_for_num_bidders_, bidder_worklets_.size());
EXPECT_EQ(waiting_for_num_sellers_, seller_worklets_.size());
waiting_for_num_bidders_ = 0;
waiting_for_num_sellers_ = 0;
}
void MockAuctionProcessManager::WaitForWinningBidderReload() {
WaitForWorklets(/*num_bidders=*/1, /*num_sellers=*/0);
}
void MockAuctionProcessManager::WaitForWinningSellerReload() {
WaitForWorklets(/*num_bidders=*/0, /*num_sellers=*/1);
}
std::unique_ptr<MockBidderWorklet> MockAuctionProcessManager::TakeBidderWorklet(
const GURL& script_source_url) {
auto it = bidder_worklets_.find(script_source_url);
if (it == bidder_worklets_.end()) {
return nullptr;
}
std::unique_ptr<MockBidderWorklet> out = std::move(it->second);
bidder_worklets_.erase(it);
return out;
}
std::unique_ptr<MockSellerWorklet> MockAuctionProcessManager::TakeSellerWorklet(
GURL script_source_url) {
if (seller_worklets_.empty()) {
return nullptr;
}
if (script_source_url.is_empty()) {
CHECK_EQ(1u, seller_worklets_.size());
script_source_url = seller_worklets_.begin()->first;
}
auto it = seller_worklets_.find(script_source_url);
if (it == seller_worklets_.end()) {
return nullptr;
}
std::unique_ptr<MockSellerWorklet> out = std::move(it->second);
seller_worklets_.erase(it);
return out;
}
void MockAuctionProcessManager::Flush() {
receiver_set_.FlushForTesting();
}
void MockAuctionProcessManager::MaybeQuitWaitForWorkletsRunLoop() {
if (wait_for_worklets_run_loop_ &&
bidder_worklets_.size() >= waiting_for_num_bidders_ &&
seller_worklets_.size() >= waiting_for_num_sellers_) {
wait_for_worklets_run_loop_->Quit();
}
}
} // namespace content