component-auction.https.window.js (35094B)
1 // META: script=/resources/testdriver.js 2 // META: script=/resources/testdriver-vendor.js 3 // META: script=/common/utils.js 4 // META: script=/common/subset-tests.js 5 // META: script=resources/fledge-util.sub.js 6 // META: timeout=long 7 // META: variant=?1-5 8 // META: variant=?6-10 9 // META: variant=?11-15 10 // META: variant=?16-last 11 12 "use strict"; 13 14 // Creates an AuctionConfig with a single component auction. 15 function createComponentAuctionConfig(uuid, auctionConfigOverrides = {}, 16 deprecatedRenderURLReplacements = {}) { 17 let componentAuctionConfig = { 18 seller: window.location.origin, 19 decisionLogicURL: createDecisionScriptURL(uuid), 20 interestGroupBuyers: [window.location.origin], 21 deprecatedRenderURLReplacements: deprecatedRenderURLReplacements 22 }; 23 24 return { 25 seller: window.location.origin, 26 decisionLogicURL: createDecisionScriptURL(uuid), 27 interestGroupBuyers: [], 28 componentAuctions: [componentAuctionConfig], 29 ...auctionConfigOverrides 30 }; 31 } 32 33 subsetTest(promise_test, async test => { 34 const uuid = generateUuid(test); 35 36 await joinInterestGroup( 37 test, uuid, 38 { biddingLogicURL: createBiddingScriptURL()}); 39 40 await runBasicFledgeTestExpectingNoWinner(test, uuid, createComponentAuctionConfig(uuid)); 41 }, 'Component auction allowed not specified by bidder.'); 42 43 subsetTest(promise_test, async test => { 44 const uuid = generateUuid(test); 45 46 await joinInterestGroup( 47 test, uuid, 48 { biddingLogicURL: createBiddingScriptURL( 49 { allowComponentAuction: false })}); 50 51 await runBasicFledgeTestExpectingNoWinner(test, uuid, createComponentAuctionConfig(uuid)); 52 }, 'Component auction not allowed by bidder.'); 53 54 subsetTest(promise_test, async test => { 55 const uuid = generateUuid(test); 56 57 await joinInterestGroup( 58 test, uuid, 59 { biddingLogicURL: createBiddingScriptURL( 60 { allowComponentAuction: true })}); 61 62 let auctionConfig = createComponentAuctionConfig(uuid); 63 auctionConfig.componentAuctions[0].decisionLogicURL = createDecisionScriptURL( 64 uuid, 65 { scoreAd: "return 5;" }); 66 67 await runBasicFledgeTestExpectingNoWinner(test, uuid, auctionConfig); 68 }, 'Component auction allowed not specified by component seller.'); 69 70 subsetTest(promise_test, async test => { 71 const uuid = generateUuid(test); 72 73 await joinInterestGroup( 74 test, uuid, 75 { biddingLogicURL: createBiddingScriptURL( 76 { allowComponentAuction: true })}); 77 78 let auctionConfig = createComponentAuctionConfig(uuid); 79 auctionConfig.componentAuctions[0].decisionLogicURL = createDecisionScriptURL( 80 uuid, 81 { scoreAd: "return {desirability: 5, allowComponentAuction: false};" }); 82 83 await runBasicFledgeTestExpectingNoWinner(test, uuid, auctionConfig); 84 }, 'Component auction not allowed by component seller.'); 85 86 subsetTest(promise_test, async test => { 87 const uuid = generateUuid(test); 88 89 await joinInterestGroup( 90 test, uuid, 91 { biddingLogicURL: createBiddingScriptURL( 92 { allowComponentAuction: true })}); 93 94 let auctionConfig = createComponentAuctionConfig(uuid); 95 auctionConfig.decisionLogicURL = createDecisionScriptURL( 96 uuid, 97 { scoreAd: "return 5;" }); 98 99 await runBasicFledgeTestExpectingNoWinner(test, uuid, auctionConfig); 100 }, 'Component auction allowed not specified by top-level seller.'); 101 102 subsetTest(promise_test, async test => { 103 const uuid = generateUuid(test); 104 105 await joinInterestGroup( 106 test, uuid, 107 { biddingLogicURL: createBiddingScriptURL( 108 { allowComponentAuction: true })}); 109 110 let auctionConfig = createComponentAuctionConfig(uuid); 111 auctionConfig.interestGroupBuyers = [window.location.origin]; 112 113 try { 114 await runBasicFledgeAuction(test, uuid, auctionConfig); 115 } catch (exception) { 116 assert_true(exception instanceof TypeError, "did not get expected error: " + exception); 117 return; 118 } 119 throw 'Exception unexpectedly not thrown.' 120 }, 'Component auction top-level auction cannot have buyers.'); 121 122 subsetTest(promise_test, async test => { 123 const uuid = generateUuid(test); 124 125 await joinInterestGroup( 126 test, uuid, 127 { biddingLogicURL: createBiddingScriptURL( 128 { allowComponentAuction: true })}); 129 130 let auctionConfig = createComponentAuctionConfig(uuid); 131 auctionConfig.decisionLogicURL = createDecisionScriptURL( 132 uuid, 133 { scoreAd: "return {desirability: 5, allowComponentAuction: false};" }); 134 135 await runBasicFledgeTestExpectingNoWinner(test, uuid, auctionConfig); 136 }, 'Component auction not allowed by top-level seller.'); 137 138 subsetTest(promise_test, async test => { 139 const uuid = generateUuid(test); 140 141 // Use distinct origins so can validate all origin parameters passed to worklets. 142 let bidder = OTHER_ORIGIN1; 143 let componentSeller = OTHER_ORIGIN2; 144 let topLevelSeller = OTHER_ORIGIN3; 145 146 let bidderReportURL = createBidderReportURL(uuid); 147 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 148 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 149 150 // Note that generateBid() and reportWin() receive slightly different 151 // "browserSignals" fields - only reportWin() gets "interestGroupOwner", so 152 // need different sets of checks for them. 153 await joinCrossOriginInterestGroup( 154 test, uuid, bidder, 155 { biddingLogicURL: createBiddingScriptURL( 156 { origin: bidder, 157 allowComponentAuction: true, 158 generateBid: 159 `if (browserSignals.seller !== "${componentSeller}") 160 throw "Unexpected seller: " + browserSignals.seller; 161 if (browserSignals.componentSeller !== undefined) 162 throw "Unexpected componentSeller: " + browserSignals.componentSeller; 163 if (browserSignals.topLevelSeller !== "${topLevelSeller}") 164 throw "Unexpected topLevelSeller: " + browserSignals.topLevelSeller; 165 if (browserSignals.interestGroupOwner !== undefined) 166 throw "Unexpected interestGroupOwner: " + browserSignals.interestGroupOwner; 167 if (browserSignals.topWindowHostname !== "${window.location.hostname}") 168 throw "Unexpected topWindowHostname: " + browserSignals.topWindowHostname;`, 169 reportWin: 170 `if (browserSignals.seller !== "${componentSeller}") 171 throw "Unexpected seller: " + browserSignals.seller; 172 if (browserSignals.componentSeller !== undefined) 173 throw "Unexpected componentSeller: " + browserSignals.componentSeller; 174 if (browserSignals.topLevelSeller !== "${topLevelSeller}") 175 throw "Unexpected topLevelSeller: " + browserSignals.topLevelSeller; 176 if (browserSignals.interestGroupOwner !== "${bidder}") 177 throw "Unexpected interestGroupOwner: " + browserSignals.interestGroupOwner; 178 if (browserSignals.topWindowHostname !== "${window.location.hostname}") 179 throw "Unexpected topWindowHostname: " + browserSignals.topWindowHostname; 180 sendReportTo("${bidderReportURL}");`})}); 181 182 // Checks for scoreAd() and reportResult() for the component seller. 183 let componentSellerChecks = 184 `if (browserSignals.seller !== undefined) 185 throw "Unexpected seller: " + browserSignals.seller; 186 if (browserSignals.componentSeller !== undefined) 187 throw "Unexpected componentSeller: " + browserSignals.componentSeller; 188 if (browserSignals.topLevelSeller !== "${topLevelSeller}") 189 throw "Unexpected topLevelSeller: " + browserSignals.topLevelSeller; 190 if (browserSignals.interestGroupOwner !== "${bidder}") 191 throw "Unexpected interestGroupOwner: " + browserSignals.interestGroupOwner; 192 if (browserSignals.topWindowHostname !== "${window.location.hostname}") 193 throw "Unexpected topWindowHostname: " + browserSignals.topWindowHostname;`; 194 195 let componentAuctionConfig = { 196 seller: componentSeller, 197 decisionLogicURL: createDecisionScriptURL( 198 uuid, 199 { origin: componentSeller, 200 scoreAd: componentSellerChecks, 201 reportResult: `${componentSellerChecks} 202 sendReportTo("${componentSellerReportURL}");` }), 203 interestGroupBuyers: [bidder] 204 }; 205 206 // Checks for scoreAd() and reportResult() for the top-level seller. 207 let topLevelSellerChecks = 208 `if (browserSignals.seller !== undefined) 209 throw "Unexpected seller: " + browserSignals.seller; 210 if (browserSignals.componentSeller !== "${componentSeller}") 211 throw "Unexpected componentSeller: " + browserSignals.componentSeller; 212 if (browserSignals.topLevelSeller !== undefined) 213 throw "Unexpected topLevelSeller: " + browserSignals.topLevelSeller; 214 if (browserSignals.interestGroupOwner !== "${bidder}") 215 throw "Unexpected interestGroupOwner: " + browserSignals.interestGroupOwner; 216 if (browserSignals.topWindowHostname !== "${window.location.hostname}") 217 throw "Unexpected topWindowHostname: " + browserSignals.topWindowHostname;`; 218 219 let auctionConfigOverrides = { 220 seller: topLevelSeller, 221 decisionLogicURL: createDecisionScriptURL( 222 uuid, 223 { origin: topLevelSeller, 224 scoreAd: topLevelSellerChecks, 225 reportResult: `${topLevelSellerChecks} 226 sendReportTo("${topLevelSellerReportURL}");` }), 227 interestGroupBuyers: [], 228 componentAuctions: [componentAuctionConfig] 229 }; 230 231 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfigOverrides); 232 await waitForObservedRequests( 233 uuid, 234 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL]); 235 }, 'Component auction browserSignals origins.'); 236 237 subsetTest(promise_test, async test => { 238 const uuid = generateUuid(test); 239 240 let bidderReportURL = createBidderReportURL(uuid); 241 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 242 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 243 244 await joinInterestGroup( 245 test, uuid, 246 { biddingLogicURL: createBiddingScriptURL( 247 { allowComponentAuction: true, 248 bid: 5, 249 reportWin: 250 `if (browserSignals.bid !== 5) 251 throw "Unexpected bid: " + browserSignals.bid; 252 sendReportTo("${bidderReportURL}");`})}); 253 254 let auctionConfig = createComponentAuctionConfig(uuid); 255 256 auctionConfig.componentAuctions[0].decisionLogicURL = 257 createDecisionScriptURL( 258 uuid, 259 { scoreAd: 260 `if (bid !== 5) 261 throw "Unexpected component bid: " + bid`, 262 reportResult: 263 `if (browserSignals.bid !== 5) 264 throw "Unexpected component bid: " + browserSignals.bid; 265 if (browserSignals.modifiedBid !== undefined) 266 throw "Unexpected component modifiedBid: " + browserSignals.modifiedBid; 267 sendReportTo("${componentSellerReportURL}");` }); 268 269 auctionConfig.decisionLogicURL = 270 createDecisionScriptURL( 271 uuid, 272 { scoreAd: 273 `if (bid !== 5) 274 throw "Unexpected top-level bid: " + bid`, 275 reportResult: 276 `if (browserSignals.bid !== 5) 277 throw "Unexpected top-level bid: " + browserSignals.bid; 278 if (browserSignals.modifiedBid !== undefined) 279 throw "Unexpected top-level modifiedBid: " + browserSignals.modifiedBid; 280 sendReportTo("${topLevelSellerReportURL}");` }); 281 282 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 283 await waitForObservedRequests( 284 uuid, 285 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL]); 286 }, 'Component auction unmodified bid.'); 287 288 subsetTest(promise_test, async test => { 289 const uuid = generateUuid(test); 290 291 let bidderReportURL = createBidderReportURL(uuid); 292 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 293 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 294 295 await joinInterestGroup( 296 test, uuid, 297 { biddingLogicURL: createBiddingScriptURL( 298 { allowComponentAuction: true, 299 bid: 5, 300 reportWin: 301 `if (browserSignals.bid !== 5) 302 throw "Unexpected bid: " + browserSignals.bid; 303 sendReportTo("${bidderReportURL}");`})}); 304 305 let auctionConfig = createComponentAuctionConfig(uuid); 306 307 auctionConfig.componentAuctions[0].decisionLogicURL = 308 createDecisionScriptURL( 309 uuid, 310 { scoreAd: 311 `if (bid !== 5) 312 throw "Unexpected component bid: " + bid 313 return {desirability: 5, allowComponentAuction: true, bid: 4};`, 314 reportResult: 315 `if (browserSignals.bid !== 5) 316 throw "Unexpected component bid: " + browserSignals.bid; 317 if (browserSignals.modifiedBid !== 4) 318 throw "Unexpected component modifiedBid: " + browserSignals.modifiedBid; 319 sendReportTo("${componentSellerReportURL}");` }); 320 321 auctionConfig.decisionLogicURL = 322 createDecisionScriptURL( 323 uuid, 324 { scoreAd: 325 `if (bid !== 4) 326 throw "Unexpected top-level bid: " + bid`, 327 reportResult: 328 `if (browserSignals.bid !== 4) 329 throw "Unexpected top-level bid: " + browserSignals.bid; 330 if (browserSignals.modifiedBid !== undefined) 331 throw "Unexpected top-level modifiedBid: " + browserSignals.modifiedBid; 332 sendReportTo("${topLevelSellerReportURL}");` }); 333 334 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 335 await waitForObservedRequests( 336 uuid, 337 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL]); 338 }, 'Component auction modified bid.'); 339 340 subsetTest(promise_test, async test => { 341 const uuid = generateUuid(test); 342 343 let bidderReportURL = createBidderReportURL(uuid); 344 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 345 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 346 347 await joinInterestGroup( 348 test, uuid, 349 { biddingLogicURL: createBiddingScriptURL( 350 { allowComponentAuction: true, 351 bid: 5, 352 reportWin: 353 `if (browserSignals.bid !== 5) 354 throw "Unexpected bid: " + browserSignals.bid; 355 sendReportTo("${bidderReportURL}");`})}); 356 357 let auctionConfig = createComponentAuctionConfig(uuid); 358 359 auctionConfig.componentAuctions[0].decisionLogicURL = 360 createDecisionScriptURL( 361 uuid, 362 { scoreAd: 363 `if (bid !== 5) 364 throw "Unexpected component bid: " + bid 365 return {desirability: 5, allowComponentAuction: true, bid: 5};`, 366 reportResult: 367 `if (browserSignals.bid !== 5) 368 throw "Unexpected component bid: " + browserSignals.bid; 369 if (browserSignals.modifiedBid !== 5) 370 throw "Unexpected component modifiedBid: " + browserSignals.modifiedBid; 371 sendReportTo("${componentSellerReportURL}");` }); 372 373 auctionConfig.decisionLogicURL = 374 createDecisionScriptURL( 375 uuid, 376 { scoreAd: 377 `if (bid !== 5) 378 throw "Unexpected top-level bid: " + bid`, 379 reportResult: 380 `if (browserSignals.bid !== 5) 381 throw "Unexpected top-level bid: " + browserSignals.bid; 382 if (browserSignals.modifiedBid !== undefined) 383 throw "Unexpected top-level modifiedBid: " + browserSignals.modifiedBid; 384 sendReportTo("${topLevelSellerReportURL}");` }); 385 386 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 387 await waitForObservedRequests( 388 uuid, 389 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL]); 390 }, 'Component auction modified bid to same value.'); 391 392 subsetTest(promise_test, async test => { 393 const uuid = generateUuid(test); 394 395 let bidderReportURL = createBidderReportURL(uuid); 396 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 397 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 398 399 await joinInterestGroup( 400 test, uuid, 401 { biddingLogicURL: createBiddingScriptURL( 402 { allowComponentAuction: true, 403 bid: 5, 404 reportWin: 405 `if (browserSignals.bid !== 5) 406 throw "Unexpected bid: " + browserSignals.bid; 407 sendReportTo("${bidderReportURL}");`})}); 408 409 let auctionConfig = createComponentAuctionConfig(uuid); 410 411 auctionConfig.componentAuctions[0].decisionLogicURL = 412 createDecisionScriptURL( 413 uuid, 414 { scoreAd: 415 `if (bid !== 5) 416 throw "Unexpected component bid: " + bid`, 417 reportResult: 418 `if (browserSignals.bid !== 5) 419 throw "Unexpected component bid: " + browserSignals.bid; 420 if (browserSignals.modifiedBid !== undefined) 421 throw "Unexpected component modifiedBid: " + browserSignals.modifiedBid; 422 sendReportTo("${componentSellerReportURL}");` }); 423 424 auctionConfig.decisionLogicURL = 425 createDecisionScriptURL( 426 uuid, 427 { scoreAd: 428 `if (bid !== 5) 429 throw "Unexpected top-level bid: " + bid 430 return {desirability: 5, allowComponentAuction: true, bid: 4};`, 431 reportResult: 432 `if (browserSignals.bid !== 5) 433 throw "Unexpected top-level bid: " + browserSignals.bid; 434 if (browserSignals.modifiedBid !== undefined) 435 throw "Unexpected top-level modifiedBid: " + browserSignals.modifiedBid; 436 sendReportTo("${topLevelSellerReportURL}");` }); 437 438 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 439 await waitForObservedRequests( 440 uuid, 441 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL]); 442 }, 'Top-level auction cannot modify bid.'); 443 444 subsetTest(promise_test, async test => { 445 const uuid = generateUuid(test); 446 447 let bidderReportURL = createBidderReportURL(uuid); 448 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 449 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 450 451 await joinInterestGroup( 452 test, uuid, 453 { biddingLogicURL: createBiddingScriptURL( 454 { allowComponentAuction: true, 455 reportWin: 456 `if (browserSignals.desirability !== undefined) 457 throw "Unexpected desirability: " + browserSignals.desirability; 458 sendReportTo("${bidderReportURL}");`})}); 459 460 let auctionConfig = createComponentAuctionConfig(uuid); 461 462 auctionConfig.componentAuctions[0].decisionLogicURL = 463 createDecisionScriptURL( 464 uuid, 465 { scoreAd: 466 `return {desirability: 3, allowComponentAuction: true};`, 467 reportResult: 468 `if (browserSignals.desirability !== 3) 469 throw "Unexpected component desirability: " + browserSignals.desirability; 470 sendReportTo("${componentSellerReportURL}");` }); 471 472 auctionConfig.decisionLogicURL = 473 createDecisionScriptURL( 474 uuid, 475 { scoreAd: 476 `return {desirability: 4, allowComponentAuction: true};`, 477 reportResult: 478 `if (browserSignals.desirability !== 4) 479 throw "Unexpected component desirability: " + browserSignals.desirability; 480 sendReportTo("${topLevelSellerReportURL}");` }); 481 482 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 483 await waitForObservedRequests( 484 uuid, 485 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL]); 486 }, 'Component auction desirability.'); 487 488 subsetTest(promise_test, async test => { 489 const uuid = generateUuid(test); 490 491 // An auction with two components, each of which has a distinct bidder origin, 492 // so the bidder in the second component is OTHER_ORIGIN1). The bidder in the 493 // first component auction bids more and is given the highest of all 494 // desirability scores in the auction by its component seller, but the 495 // top-level seller prefers bidder 2. 496 let bidder1ReportURL = createBidderReportURL(uuid, /*id=*/1); 497 let bidder2ReportURL = createBidderReportURL(uuid, /*id=*/2); 498 let componentSeller1ReportURL = createSellerReportURL(uuid, /*id=*/"component1"); 499 let componentSeller2ReportURL = createSellerReportURL(uuid, /*id=*/"component2"); 500 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 501 502 await Promise.all([ 503 joinInterestGroup( 504 test, uuid, 505 { biddingLogicURL: createBiddingScriptURL( 506 { bid: 10, 507 allowComponentAuction: true, 508 reportWin: 509 `sendReportTo("${bidder1ReportURL}");`})}), 510 joinCrossOriginInterestGroup(test, uuid, OTHER_ORIGIN1, 511 { biddingLogicURL: createBiddingScriptURL( 512 { origin: OTHER_ORIGIN1, 513 bid: 2, 514 allowComponentAuction: true, 515 reportWin: 516 `if (browserSignals.bid !== 2) 517 throw "Unexpected bid: " + browserSignals.bid; 518 sendReportTo("${bidder2ReportURL}");`})}) 519 ]); 520 521 let auctionConfig = createComponentAuctionConfig(uuid); 522 523 auctionConfig.componentAuctions[0].decisionLogicURL = 524 createDecisionScriptURL( 525 uuid, 526 { scoreAd: 527 `return {desirability: 10, allowComponentAuction: true};`, 528 reportResult: 529 `sendReportTo("${componentSeller1ReportURL}");` }); 530 531 auctionConfig.componentAuctions[1] = { 532 ...auctionConfig.componentAuctions[0], 533 interestGroupBuyers: [OTHER_ORIGIN1], 534 decisionLogicURL: createDecisionScriptURL( 535 uuid, 536 { scoreAd: 537 `return {desirability: 1, allowComponentAuction: true};`, 538 reportResult: 539 `if (browserSignals.desirability !== 1) 540 throw "Unexpected component desirability: " + browserSignals.desirability; 541 sendReportTo("${componentSeller2ReportURL}");` }) 542 } 543 544 auctionConfig.decisionLogicURL = 545 createDecisionScriptURL( 546 uuid, 547 { scoreAd: 548 `return {desirability: 11 - bid, allowComponentAuction: true};`, 549 reportResult: 550 `if (browserSignals.desirability !== 9) 551 throw "Unexpected component desirability: " + browserSignals.desirability; 552 sendReportTo("${topLevelSellerReportURL}");` }); 553 554 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 555 await waitForObservedRequests( 556 uuid, 557 [bidder2ReportURL, componentSeller2ReportURL, topLevelSellerReportURL]); 558 }, 'Component auction desirability two sellers, two bidders.'); 559 560 subsetTest(promise_test, async test => { 561 const uuid = generateUuid(test); 562 563 let renderURL1 = createRenderURL(uuid); 564 let renderURL2 = createRenderURL(uuid, /*script=*/';'); 565 566 // The same bidder uses different ads, bids, and reporting URLs for different 567 // component sellers. 568 let bidderReportURL1 = createBidderReportURL(uuid, /*id=*/1); 569 let bidderReportURL2 = createBidderReportURL(uuid, /*id=*/2); 570 let componentSeller1ReportURL = createSellerReportURL(uuid, /*id=*/"component1"); 571 let componentSeller2ReportURL = createSellerReportURL(uuid, /*id=*/"component2"); 572 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 573 574 await joinInterestGroup( 575 test, uuid, 576 { ads: [{ renderURL: renderURL1 }, { renderURL: renderURL2 }], 577 biddingLogicURL: createBiddingScriptURL( 578 { allowComponentAuction: true, 579 generateBid: 580 // "auctionSignals" contains the bid and the report URL, to 581 // make the same bidder behave differently in the two 582 // auctions. 583 'return auctionSignals;', 584 reportWin: 585 `if (browserSignals.renderURL !== "${renderURL2}") 586 throw "Wrong winner: " + browserSignals.renderURL; 587 sendReportTo(auctionSignals.reportURL);`})}); 588 589 let auctionConfig = createComponentAuctionConfig(uuid); 590 591 auctionConfig.componentAuctions[0].decisionLogicURL = 592 createDecisionScriptURL( 593 uuid, 594 { scoreAd: 595 `return {desirability: 10, allowComponentAuction: true};`, 596 reportResult: 597 `sendReportTo("${componentSeller1ReportURL}");` }); 598 // "auctionSignals" contains the bid and the report URL, to 599 // make the same bidder behave differently in the two 600 // auctions. 601 auctionConfig.componentAuctions[0].auctionSignals = { 602 bid: 10, 603 allowComponentAuction: true, 604 render: renderURL1, 605 reportURL: bidderReportURL1 606 }; 607 608 auctionConfig.componentAuctions[1] = { 609 ...auctionConfig.componentAuctions[0], 610 auctionSignals: { 611 bid: 2, 612 allowComponentAuction: true, 613 render: renderURL2, 614 reportURL: bidderReportURL2 615 }, 616 decisionLogicURL: createDecisionScriptURL( 617 uuid, 618 { scoreAd: 619 `return {desirability: 1, allowComponentAuction: true};`, 620 reportResult: 621 `if (browserSignals.desirability !== 1) 622 throw "Unexpected component desirability: " + browserSignals.desirability; 623 if (browserSignals.renderURL !== "${renderURL2}") 624 throw "Wrong winner: " + browserSignals.renderURL; 625 sendReportTo("${componentSeller2ReportURL}");` }) 626 } 627 628 auctionConfig.decisionLogicURL = 629 createDecisionScriptURL( 630 uuid, 631 { scoreAd: 632 `return {desirability: 11 - bid, allowComponentAuction: true};`, 633 reportResult: 634 `if (browserSignals.desirability !== 9) 635 throw "Unexpected component desirability: " + browserSignals.desirability; 636 if (browserSignals.renderURL !== "${renderURL2}") 637 throw "Wrong winner: " + browserSignals.renderURL; 638 sendReportTo("${topLevelSellerReportURL}");` }); 639 640 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 641 await waitForObservedRequests( 642 uuid, 643 [bidderReportURL2, componentSeller2ReportURL, topLevelSellerReportURL]); 644 }, 'Component auction desirability and renderURL two sellers, one bidder.'); 645 646 subsetTest(promise_test, async test => { 647 const uuid = generateUuid(test); 648 649 // The renderURLs / report URLs for the first/second iterations of the auction. 650 let renderURL1 = createRenderURL(uuid); 651 let renderURL2 = createRenderURL(uuid, /*script=*/';'); 652 let bidderReportURL1 = createBidderReportURL(uuid, /*id=*/1); 653 let bidderReportURL2 = createBidderReportURL(uuid, /*id=*/2); 654 let seller1ReportURL = createSellerReportURL(uuid, /*id=*/1); 655 let seller2ReportURL = createSellerReportURL(uuid, /*id=*/2); 656 657 await joinInterestGroup( 658 test, uuid, 659 { ads: [{ renderURL: renderURL1 }, { renderURL: renderURL2 }], 660 biddingLogicURL: createBiddingScriptURL( 661 { allowComponentAuction: true, 662 generateBid: 663 `// If this is the first recorded win, use "renderURL1" 664 if (browserSignals.bidCount === 0 && 665 browserSignals.prevWinsMs.length === 0) { 666 return {bid: 2, allowComponentAuction: true, render: "${renderURL1}"}; 667 } 668 669 // Otherwise, check that a single bid and win were reported, despite the 670 // bidder bidding twice in the first auction, once for each component 671 // auction. 672 if (browserSignals.bidCount === 1 && 673 browserSignals.prevWinsMs.length === 1 && 674 typeof browserSignals.prevWinsMs[0][0] === "number" && 675 browserSignals.prevWinsMs[0][1].renderURL === "${renderURL1}") { 676 return {bid: 1, allowComponentAuction: true, render: "${renderURL2}"}; 677 } 678 throw "Unexpected browserSignals: " + JSON.stringify(browserSignals);`, 679 reportWin: 680 `if (browserSignals.renderURL === "${renderURL1}") 681 sendReportTo("${bidderReportURL1}"); 682 if (browserSignals.renderURL === "${renderURL2}") 683 sendReportTo("${bidderReportURL2}");`})}); 684 685 // Auction has two component auctions with different sellers but the same 686 // single bidder. The first component auction only accepts bids with 687 // "renderURL1", the second only accepts bids with "renderURL2". 688 let auctionConfig = createComponentAuctionConfig(uuid); 689 auctionConfig.componentAuctions[0].decisionLogicURL = 690 createDecisionScriptURL( 691 uuid, 692 { scoreAd: `if (browserSignals.renderURL !== '${renderURL1}') 693 throw 'Wrong ad';`, 694 reportResult: `sendReportTo('${seller1ReportURL}');`} 695 ); 696 697 auctionConfig.componentAuctions[1] = { 698 seller: OTHER_ORIGIN1, 699 interestGroupBuyers: [window.location.origin], 700 decisionLogicURL: createDecisionScriptURL( 701 uuid, 702 { origin: OTHER_ORIGIN1, 703 scoreAd: `if (browserSignals.renderURL !== '${renderURL2}') 704 throw 'Wrong ad';`, 705 reportResult: `sendReportTo('${seller2ReportURL}');`} 706 ) 707 }; 708 709 // In the first auction, the bidder should use "renderURL1", which the first 710 // component auction allows. `prevWinsMs` and `numBids` should be updated. 711 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 712 await waitForObservedRequests( 713 uuid, 714 [bidderReportURL1, seller1ReportURL]); 715 716 // In the second auction, the bidder should use "renderURL2", which the second 717 // component auction allows. `prevWinsMs` and `numBids` should reflect the updated 718 // value. 719 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 720 await waitForObservedRequests( 721 uuid, 722 [bidderReportURL1, seller1ReportURL, bidderReportURL2, seller2ReportURL]); 723 }, `Component auction prevWinsMs and numBids updating in one component seller's auction, read in another's.`); 724 725 726 const makeDeprecatedRenderURLReplacementTest = ({ 727 name, 728 deprecatedRenderURLReplacements, 729 }) => { 730 subsetTest(promise_test, async test => { 731 const uuid = generateUuid(test); 732 733 let bidderReportURL = createBidderReportURL(uuid); 734 let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); 735 let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); 736 737 // These are used within the URLs for deprecatedRenderURLReplacement tests. 738 const renderURLReplacementsStrings = createStringBeforeAndAfterReplacements(deprecatedRenderURLReplacements); 739 const beforeReplacementsString = renderURLReplacementsStrings.beforeReplacements; 740 const afterReplacementsString = renderURLReplacementsStrings.afterReplacements; 741 const renderURLBeforeReplacements = createTrackerURL(window.location.origin, uuid, 'track_get', beforeReplacementsString); 742 const renderURLAfterReplacements = createTrackerURL(window.location.origin, uuid, 'track_get', afterReplacementsString); 743 744 await joinInterestGroup( 745 test, uuid, 746 { 747 ads: [{ renderURL: renderURLBeforeReplacements }], 748 biddingLogicURL: createBiddingScriptURL( 749 { 750 allowComponentAuction: true, 751 bid: 5, 752 reportWin: 753 `if (browserSignals.bid !== 5) 754 throw "Unexpected bid: " + browserSignals.bid; 755 sendReportTo("${bidderReportURL}");` 756 }) 757 }); 758 759 let auctionConfig = createComponentAuctionConfig(uuid, {}, deprecatedRenderURLReplacements); 760 761 auctionConfig.componentAuctions[0].decisionLogicURL = 762 createDecisionScriptURL( 763 uuid, 764 { 765 scoreAd: 766 `if (bid !== 5) 767 throw "Unexpected component bid: " + bid`, 768 reportResult: 769 `if (browserSignals.bid !== 5) 770 throw "Unexpected component bid: " + browserSignals.bid; 771 if (browserSignals.modifiedBid !== undefined) 772 throw "Unexpected component modifiedBid: " + browserSignals.modifiedBid; 773 sendReportTo("${componentSellerReportURL}");` 774 }); 775 776 auctionConfig.decisionLogicURL = 777 createDecisionScriptURL( 778 uuid, 779 { 780 scoreAd: 781 `if (bid !== 5) 782 throw "Unexpected top-level bid: " + bid`, 783 reportResult: 784 `if (browserSignals.bid !== 5) 785 throw "Unexpected top-level bid: " + browserSignals.bid; 786 if (browserSignals.modifiedBid !== undefined) 787 throw "Unexpected top-level modifiedBid: " + browserSignals.modifiedBid; 788 sendReportTo("${topLevelSellerReportURL}");` 789 }); 790 791 await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); 792 await waitForObservedRequests( 793 uuid, 794 [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL, renderURLAfterReplacements]); 795 }, name); 796 }; 797 798 makeDeprecatedRenderURLReplacementTest({ 799 name: 'Replacements with brackets.', 800 deprecatedRenderURLReplacements: { '${EXAMPLE-MACRO}': 'SSP' } 801 }); 802 803 makeDeprecatedRenderURLReplacementTest({ 804 name: 'Replacements with percents.', 805 deprecatedRenderURLReplacements: { '%%EXAMPLE-MACRO%%': 'SSP' } 806 }); 807 808 makeDeprecatedRenderURLReplacementTest({ 809 name: 'Replacements with multiple replacements.', 810 deprecatedRenderURLReplacements: { '${EXAMPLE-MACRO1}': 'SSP1', '%%EXAMPLE-MACRO2%%': 'SSP2' } 811 }); 812 813 subsetTest(promise_test, async test => { 814 const uuid = generateUuid(test); 815 let deprecatedRenderURLReplacements = { '${EXAMPLE-MACRO1}': 'SSP1', '%%EXAMPLE-MACRO2%%': 'SSP2' }; 816 const renderURLReplacementsStrings = createStringBeforeAndAfterReplacements(deprecatedRenderURLReplacements); 817 let beforeReplacementsString = renderURLReplacementsStrings.beforeReplacements; 818 819 await joinInterestGroup( 820 test, uuid, 821 { 822 ads: [{ renderURL: createTrackerURL(window.location.origin, uuid, 'track_get', beforeReplacementsString) }], 823 biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) 824 }); 825 let auctionConfigOverride = {deprecatedRenderURLReplacements: deprecatedRenderURLReplacements } 826 let auctionConfig = createComponentAuctionConfig(uuid,/*auctionConfigOverride=*/auctionConfigOverride, 827 /*deprecatedRenderURLReplacements=*/deprecatedRenderURLReplacements); 828 829 auctionConfig.componentAuctions[0].decisionLogicURL = createDecisionScriptURL(uuid); 830 831 try { 832 await runBasicFledgeAuction(test, uuid, auctionConfig); 833 } catch (exception) { 834 assert_true(exception instanceof TypeError, "did not get expected error: " + exception); 835 return; 836 } 837 throw 'Exception unexpectedly not thrown.' 838 }, "deprecatedRenderURLReplacements cause error if passed in top level auction and component auction.");