tie.https.window.js (5070B)
1 // META: script=/resources/testdriver.js 2 // META: script=/resources/testdriver-vendor.js 3 // META: script=/common/utils.js 4 // META: script=resources/fledge-util.sub.js 5 // META: timeout=long 6 7 "use strict"; 8 9 // Runs one auction at a time using `auctionConfigOverrides` until the auction 10 // has a winner. 11 async function runAuctionsUntilWinner(test, uuid, auctionConfigOverrides) { 12 let fencedFrameConfig = null; 13 while (!fencedFrameConfig) { 14 fencedFrameConfig = 15 await runBasicFledgeAuction(test, uuid, auctionConfigOverrides); 16 } 17 return fencedFrameConfig; 18 } 19 20 // This tests the case of ties. The winner of an auction is normally checked 21 // by these tests by checking a report sent when the winner is loaded in a fenced 22 // frame. Unfortunately, that requires a lot of navigations, which can be slow. 23 // 24 // So instead, run a multi-seller auction. The inner auction has two bidders, 25 // which both bid, and the seller gives them the same score. For the first 26 // auction, the top-level seller just accepts the only bid it sees, and then 27 // as usual, we navigate a fenced frame, to learn which bidder won. 28 // 29 // The for subsequent auctions, the nested component auction is identical, 30 // but the top-level auction rejects bids from the bidder that won the 31 // first auction. So if we have a winner, we know that the other bidder 32 // won the tie. Auctions are run in parallel until this happens. 33 // 34 // The interest groups use "group-by-origin" execution mode, to potentially 35 // allow the auctions run in parallel to complete faster. 36 promise_test(async test => { 37 const uuid = generateUuid(test); 38 39 // Use different report URLs for each interest group, to identify 40 // which interest group has won an auction. 41 let reportURLs = [createBidderReportURL(uuid, /*id=*/'1'), 42 createBidderReportURL(uuid, /*id=*/'2')]; 43 44 // Use different ad URLs for each auction. These need to be distinct 45 // so that the top-level seller can check the URL to check if the 46 // winning bid from the component auction has already won an 47 // auction. 48 let adURLs = [createRenderURL(uuid), 49 createRenderURL(uuid, /*script=*/';')]; 50 51 await Promise.all( 52 [ joinInterestGroup( 53 test, uuid, 54 { name: 'group 1', 55 ads: [{ renderURL: adURLs[0] }], 56 executionMode: 'group-by-origin', 57 biddingLogicURL: createBiddingScriptURL( 58 { allowComponentAuction: true, 59 reportWin: `sendReportTo("${reportURLs[0]}");`})}), 60 joinInterestGroup( 61 test, uuid, 62 { name: 'group 2', 63 ads: [{ renderURL: adURLs[1] }], 64 executionMode: 'group-by-origin', 65 biddingLogicURL: createBiddingScriptURL( 66 { allowComponentAuction: true, 67 reportWin: `sendReportTo("${reportURLs[1]}");`})}) 68 ] 69 ); 70 71 let componentAuctionConfig = { 72 seller: window.location.origin, 73 decisionLogicURL: createDecisionScriptURL(uuid), 74 interestGroupBuyers: [window.location.origin] 75 }; 76 77 let auctionConfigOverrides = { 78 decisionLogicURL: createDecisionScriptURL(uuid), 79 interestGroupBuyers: [], 80 componentAuctions: [componentAuctionConfig] 81 }; 82 83 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfigOverrides); 84 85 // Waiting for the report URL of the winner should succeed, while waiting for 86 // the one of the loser should throw. Wait for both, see which succeeds, and 87 // set "winningAdURL" to the ad URL of the winner. 88 let winningAdURL = ''; 89 try { 90 await waitForObservedRequests(uuid, [reportURLs[0]]); 91 winningAdURL = adURLs[0]; 92 } catch (e) { 93 await waitForObservedRequests(uuid, [reportURLs[1]]); 94 winningAdURL = adURLs[1]; 95 } 96 97 // Modify `auctionConfigOverrides` to only accept the ad from the interest 98 // group that didn't win the first auction. 99 auctionConfigOverrides.decisionLogicURL = 100 createDecisionScriptURL( 101 uuid, 102 {scoreAd: `if (browserSignals.renderURL === "${winningAdURL}") 103 return 0;`}); 104 105 // Add an abort controller, so can cancel extra auctions. 106 let abortController = new AbortController(); 107 auctionConfigOverrides.signal = abortController.signal; 108 109 // Run a bunch of auctions in parallel, until one has a winner. 110 let fencedFrameConfig = await Promise.any( 111 [ runAuctionsUntilWinner(test, uuid, auctionConfigOverrides), 112 runAuctionsUntilWinner(test, uuid, auctionConfigOverrides), 113 runAuctionsUntilWinner(test, uuid, auctionConfigOverrides), 114 runAuctionsUntilWinner(test, uuid, auctionConfigOverrides), 115 runAuctionsUntilWinner(test, uuid, auctionConfigOverrides), 116 runAuctionsUntilWinner(test, uuid, auctionConfigOverrides) 117 ] 118 ); 119 // Abort the other auctions. 120 abortController.abort('reason'); 121 122 // Load the fencedFrameConfig in a fenced frame, and double-check that each 123 // interest group has won once. 124 createAndNavigateFencedFrame(test, fencedFrameConfig); 125 await waitForObservedRequests(uuid, [reportURLs[0], reportURLs[1]]); 126 }, 'runAdAuction tie.');