@@ -211,6 +211,24 @@ std::string MakeBidScript(const url::Origin& seller,
211
211
throw new Error("wrong renderUrl");
212
212
if (sellerSignals.bid !== bid)
213
213
throw new Error("wrong bid");
214
+ // `sellerSignals` is the `browserSignals` for the seller that's
215
+ // associated with the bid. If it's the top-level seller, the seller's
216
+ // `browserSignals` should have no `componentSeller`, since the bid
217
+ // was made directly to the top-level seller. If it's the component
218
+ // seller, the seller's `browserSignals` should have a `topLevelSeller`
219
+ // instead of a `componentSeller`, so `componentSeller` should never
220
+ // be present in `sellerSignals` here.
221
+ if ("componentSeller" in sellerSignals)
222
+ throw new Error("wrong componentSeller in sellerSignals");
223
+ if (browserSignals.seller === topLevelSeller) {
224
+ if ("topLevelSeller" in sellerSignals)
225
+ throw new Error("wrong topLevelSeller in sellerSignals");
226
+ } else {
227
+ // If the seller is a component seller, then then the seller's
228
+ // `browserSignals` should have the top-level seller.
229
+ if (sellerSignals.topLevelSeller !== topLevelSeller)
230
+ throw new Error("wrong topLevelSeller in browserSignals");
231
+ }
214
232
215
233
if (browserSignals.topWindowHostname !== 'publisher1.com')
216
234
throw new Error("wrong browserSignals.topWindowHostname");
@@ -393,25 +411,39 @@ std::string MakeDecisionScript(
393
411
if (decisionLogicUrl.startsWith(topLevelSeller)) {
394
412
// Top-level sellers should receive component sellers, but only for
395
413
// bids received from component auctions.
396
- if ("topLevelSeller" in browserSignals)
397
- throw new Error("Expected no topLevelSeller in browserSignals.");
414
+ if ("topLevelSeller" in browserSignals)
415
+ throw new Error("Expected no topLevelSeller in browserSignals.");
398
416
if (bidFromComponentAuctionWins) {
399
417
if (!browserSignals.componentSeller.includes("component"))
400
418
throw new Error("Incorrect componentSeller in browserSignals.");
401
419
} else {
402
420
if ("componentSeller" in browserSignals)
403
421
throw new Error("Expected no componentSeller in browserSignals.");
404
422
}
423
+
424
+ if ("topLevelSellerSignals" in browserSignals)
425
+ throw new Error("Unexpected browserSignals.topLevelSellerSignals");
405
426
} else {
406
427
// Component sellers should receive only the top-level seller.
407
428
if (browserSignals.topLevelSeller !== topLevelSeller)
408
429
throw new Error("Incorrect topLevelSeller in browserSignals.");
409
430
if ("componentSeller" in browserSignals)
410
431
throw new Error("Expected no componentSeller in browserSignals.");
432
+
433
+ // Component sellers should get the return value of the top-level
434
+ // seller's `reportResult()` call, which is, in this case, the
435
+ // `browserSignals` of the top-level seller.
436
+ if (browserSignals.topLevelSellerSignals.componentSeller !=
437
+ auctionConfig.seller) {
438
+ throw new Error("Unexpected browserSignals.topLevelSellerSignals");
439
+ }
411
440
}
412
441
413
442
if (browserSignals.desirability != computeScore(browserSignals.bid))
414
443
throw new Error("wrong bid or desirability in browserSignals");
444
+ // The default scoreAd() script does not modify bids.
445
+ if ("modifiedBid" in browserSignals)
446
+ throw new Error("modifiedBid unexpectedly in browserSignals");
415
447
if (browserSignals.dataVersion !== undefined)
416
448
throw new Error(`wrong dataVersion (${browserSignals.dataVersion})`);
417
449
if (sendReportUrl)
@@ -766,17 +798,20 @@ class MockSellerWorklet : public auction_worklet::mojom::SellerWorklet {
766
798
send_pending_signals_requests_called_ = true ;
767
799
}
768
800
769
- void ReportResult (blink::mojom::AuctionAdConfigNonSharedParamsPtr
770
- auction_ad_config_non_shared_params,
771
- auction_worklet::mojom::ComponentAuctionOtherSellerPtr
772
- browser_signals_other_seller,
773
- const url::Origin& browser_signal_interest_group_owner,
774
- const GURL& browser_signal_render_url,
775
- double browser_signal_bid,
776
- double browser_signal_desirability,
777
- uint32_t browser_signal_data_version,
778
- bool browser_signal_has_data_version,
779
- ReportResultCallback report_result_callback) override {
801
+ void ReportResult (
802
+ blink::mojom::AuctionAdConfigNonSharedParamsPtr
803
+ auction_ad_config_non_shared_params,
804
+ auction_worklet::mojom::ComponentAuctionOtherSellerPtr
805
+ browser_signals_other_seller,
806
+ const url::Origin& browser_signal_interest_group_owner,
807
+ const GURL& browser_signal_render_url,
808
+ double browser_signal_bid,
809
+ double browser_signal_desirability,
810
+ auction_worklet::mojom::ComponentAuctionReportResultParamsPtr
811
+ browser_signals_component_auction_report_result_params,
812
+ uint32_t browser_signal_data_version,
813
+ bool browser_signal_has_data_version,
814
+ ReportResultCallback report_result_callback) override {
780
815
report_result_callback_ = std::move (report_result_callback);
781
816
if (report_result_run_loop_)
782
817
report_result_run_loop_->Quit ();
@@ -2495,6 +2530,80 @@ TEST_F(AuctionRunnerTest, ComponentAuctionOneComponentTwoBidders) {
2495
2530
/* expected_interest_groups=*/ 2 , /* expected_owners=*/ 2 );
2496
2531
}
2497
2532
2533
+ // Test the case a top-level seller returns no signals in its reportResult
2534
+ // method. The default scripts return signals, so only need to individually test
2535
+ // the no-value case.
2536
+ TEST_F (AuctionRunnerTest, ComponentAuctionNoTopLevelReportResultSignals) {
2537
+ // Basic bid script.
2538
+ const char kBidScript [] = R"(
2539
+ function generateBid(interestGroup, auctionSignals, perBuyerSignals,
2540
+ trustedBiddingSignals, browserSignals) {
2541
+ return {ad: [], bid: 2, render: interestGroup.ads[0].renderUrl,
2542
+ allowComponentAuction: true};
2543
+ }
2544
+
2545
+ function reportWin(auctionSignals, perBuyerSignals, sellerSignals,
2546
+ browserSignals) {
2547
+ sendReportTo("https://buyer-reporting.example.com/" + browserSignals.bid);
2548
+ }
2549
+ )" ;
2550
+
2551
+ // Component seller script that makes a report to a URL based on whether the
2552
+ // top-level seller signals are null.
2553
+ const std::string kComponentSellerScript = R"(
2554
+ function scoreAd(adMetadata, bid, auctionConfig, browserSignals) {
2555
+ return {desirability: 10, allowComponentAuction: true};
2556
+ }
2557
+
2558
+ function reportResult(auctionConfig, browserSignals) {
2559
+ sendReportTo(auctionConfig.seller + "/" +
2560
+ (browserSignals.topLevelSellerSignals === null));
2561
+ }
2562
+ )" ;
2563
+
2564
+ // Top-level seller script with a reportResult method that has no return
2565
+ // value.
2566
+ const std::string kTopLevelSellerScript = R"(
2567
+ function scoreAd(adMetadata, bid, auctionConfig, browserSignals) {
2568
+ return {desirability: 10, allowComponentAuction: true};
2569
+ }
2570
+
2571
+ function reportResult(auctionConfig, browserSignals) {
2572
+ sendReportTo(auctionConfig.seller + "/" + browserSignals.bid);
2573
+ // Note that there's no return value here.
2574
+ }
2575
+ )" ;
2576
+
2577
+ auction_worklet::AddJavascriptResponse (&url_loader_factory_, kBidder1Url ,
2578
+ kBidScript );
2579
+ auction_worklet::AddJavascriptResponse (&url_loader_factory_, kSellerUrl ,
2580
+ kTopLevelSellerScript );
2581
+ auction_worklet::AddJavascriptResponse (
2582
+ &url_loader_factory_, kComponentSeller1Url , kComponentSellerScript );
2583
+
2584
+ interest_group_buyers_.reset ();
2585
+ component_auctions_.emplace_back (
2586
+ CreateAuctionConfig (kComponentSeller1Url , {{kBidder1 }}));
2587
+
2588
+ std::vector<StorageInterestGroup> bidders;
2589
+ bidders.emplace_back (MakeInterestGroup (
2590
+ kBidder1 , kBidder1Name , kBidder1Url ,
2591
+ /* trusted_bidding_signals_url=*/ absl::nullopt,
2592
+ /* trusted_bidding_signals_keys=*/ {}, GURL (" https://ad1.com" )));
2593
+
2594
+ StartAuction (kSellerUrl , std::move (bidders));
2595
+ auction_run_loop_->Run ();
2596
+ EXPECT_EQ (GURL (" https://ad1.com" ), result_.ad_url );
2597
+ EXPECT_THAT (result_.errors , testing::ElementsAre ());
2598
+ EXPECT_THAT (result_.report_urls ,
2599
+ testing::UnorderedElementsAre (
2600
+ GURL (" https://buyer-reporting.example.com/2" ),
2601
+ GURL (" https://component.seller1.test/true" ),
2602
+ GURL (" https://adstuff.publisher1.com/2" )));
2603
+ CheckHistograms (AuctionRunner::AuctionResult::kSuccess ,
2604
+ /* expected_interest_groups=*/ 1 , /* expected_owners=*/ 1 );
2605
+ }
2606
+
2498
2607
TEST_F (AuctionRunnerTest, ComponentAuctionModifiesBid) {
2499
2608
// Basic bid script.
2500
2609
const char kBidScript [] = R"(
@@ -2517,7 +2626,8 @@ TEST_F(AuctionRunnerTest, ComponentAuctionModifiesBid) {
2517
2626
}
2518
2627
2519
2628
function reportResult(auctionConfig, browserSignals) {
2520
- sendReportTo(auctionConfig.seller + "/" + browserSignals.bid);
2629
+ sendReportTo(auctionConfig.seller + "/" + browserSignals.bid +
2630
+ "_" + browserSignals.modifiedBid);
2521
2631
}
2522
2632
)" ;
2523
2633
@@ -2558,13 +2668,10 @@ TEST_F(AuctionRunnerTest, ComponentAuctionModifiesBid) {
2558
2668
EXPECT_THAT (result_.errors , testing::ElementsAre ());
2559
2669
// The reporting URLs contain the bids - the top-level seller report should
2560
2670
// see the modified bid, the other worklets see the original bid.
2561
- //
2562
- // TODO(https://crbug.com/1288865): The component seller worklet should also
2563
- // get the modified bid, in another field.
2564
2671
EXPECT_THAT (result_.report_urls ,
2565
2672
testing::UnorderedElementsAre (
2566
2673
GURL (" https://buyer-reporting.example.com/2" ),
2567
- GURL (" https://component.seller1.test/2 " ),
2674
+ GURL (" https://component.seller1.test/2_3 " ),
2568
2675
GURL (" https://adstuff.publisher1.com/3" )));
2569
2676
CheckHistograms (AuctionRunner::AuctionResult::kSuccess ,
2570
2677
/* expected_interest_groups=*/ 1 , /* expected_owners=*/ 1 );
0 commit comments