generate-bid-browser-signals.https.window.js (37444B)
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: script=/common/subset-tests.js 6 // META: timeout=long 7 // META: variant=?1-4 8 // META: variant=?5-8 9 // META: variant=?9-12 10 // META: variant=?13-16 11 // META: variant=?17-20 12 // META: variant=?21-24 13 // META: variant=?25-28 14 // META: variant=?29-last 15 16 "use strict"; 17 18 // These tests focus on the browserSignals argument passed to generateBid(). 19 // Note that "topLevelSeller" is covered by component auction tests, 20 // "dataVersion" by trusted signals tests, and cross-origin 21 // "topWindowHostname" and "seller" are covered by cross origin tests. 22 // 23 // Some of these tests use the "uuid" for interest group name, to avoid 24 // joins/bids from previous tests that failed to clean up after themselves 25 // from affecting results. 26 27 subsetTest(promise_test, async test => { 28 const uuid = generateUuid(test); 29 30 let expectedBrowserSignals = { 31 'topWindowHostname': window.location.hostname, 32 'seller': window.location.origin, 33 'adComponentsLimit': 40, 34 'joinCount': 1, 35 'bidCount': 0, 36 'multiBidLimit': 1, 37 'prevWinsMs': [], 38 }; 39 let biddingLogicURL = createBiddingScriptURL({ 40 generateBid: 41 `let expectedBrowserSignals = ${JSON.stringify(expectedBrowserSignals)}; 42 43 // Can't check this value exactly. 44 expectedBrowserSignals.recency = browserSignals.recency; 45 46 // This value may be affected by other recently run tests. 47 expectedBrowserSignals.forDebuggingOnlyInCooldownOrLockout = 48 browserSignals.forDebuggingOnlyInCooldownOrLockout; 49 50 51 // Remove deprecated field, if present. 52 delete browserSignals.prevWins; 53 54 if (!deepEquals(browserSignals, expectedBrowserSignals)) 55 throw "Unexpected browserSignals: " + JSON.stringify(browserSignals) + " - " + JSON.stringify(expectedBrowserSignals)` 56 }); 57 58 await joinGroupAndRunBasicFledgeTestExpectingWinner( 59 test, 60 { uuid: uuid, 61 interestGroupOverrides: {name: uuid, 62 biddingLogicURL: biddingLogicURL}}); 63 }, 'Only expected fields present.'); 64 65 // Creates a bidding script URL that expects the "joinCount" to be 66 // "expectedJoinCount". 67 function createJoinCountBiddingScriptURL(expectedJoinCount) { 68 return createBiddingScriptURL( 69 { generateBid: 70 `if (browserSignals.joinCount !== ${expectedJoinCount}) 71 throw "Unexpected joinCount: " + browserSignals.joinCount;` 72 }); 73 } 74 75 subsetTest(promise_test, async test => { 76 const uuid = generateUuid(test); 77 78 await joinGroupAndRunBasicFledgeTestExpectingWinner( 79 test, 80 { uuid: uuid, 81 interestGroupOverrides: {name: uuid, 82 biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); 83 84 // Joining again, even with a different script URL, should increase the join count. 85 await joinGroupAndRunBasicFledgeTestExpectingWinner( 86 test, 87 { uuid: uuid, 88 interestGroupOverrides: {name: uuid, 89 biddingLogicURL: createJoinCountBiddingScriptURL(2)}}); 90 }, 'browserSignals.joinCount same joining page.'); 91 92 subsetTest(promise_test, async test => { 93 const uuid = generateUuid(test); 94 95 await joinGroupAndRunBasicFledgeTestExpectingWinner( 96 test, 97 { uuid: uuid, 98 interestGroupOverrides: {name: uuid, 99 biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); 100 101 // Attempt to re-join the same interest group from a different top-level origin. 102 // The join count should still be persisted. 103 await joinCrossOriginInterestGroupInTopLevelWindow( 104 test, uuid, OTHER_ORIGIN1, window.location.origin, 105 { name: uuid, 106 biddingLogicURL: createJoinCountBiddingScriptURL(2)}); 107 108 await runBasicFledgeTestExpectingWinner(test, uuid); 109 }, 'browserSignals.joinCount different top-level joining origin.'); 110 111 subsetTest(promise_test, async test => { 112 const uuid = generateUuid(test); 113 114 await joinGroupAndRunBasicFledgeTestExpectingWinner( 115 test, 116 { uuid: uuid, 117 interestGroupOverrides: {name: uuid, 118 biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); 119 120 // Leaving interest group should clear join count. 121 await leaveInterestGroup({name: uuid}); 122 123 // Check that join count was cleared. 124 await joinGroupAndRunBasicFledgeTestExpectingWinner( 125 test, 126 { uuid: uuid, 127 interestGroupOverrides: {name: uuid, 128 biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); 129 }, 'browserSignals.joinCount leave and rejoin.'); 130 131 subsetTest(promise_test, async test => { 132 const uuid = generateUuid(test); 133 await runReportTest( 134 test, uuid, 135 { generateBid: 136 `if (browserSignals.recency === undefined) 137 throw new Error("Missing recency in browserSignals.") 138 139 if (browserSignals.recency < 0) 140 throw new Error("Recency is a negative value.") 141 142 if (browserSignals.recency > 30000) 143 throw new Error("Recency is over 30 seconds threshold.") 144 145 if (browserSignals.recency % 100 !== 0) 146 throw new Error("Recency is not rounded to multiple of 100 milliseconds.") 147 148 return {'bid': 9, 149 'render': interestGroup.ads[0].renderURL};`, 150 reportWin: 151 `sendReportTo('${createBidderReportURL(uuid)}');` 152 }, 153 // expectedReportURLs 154 [createBidderReportURL(uuid)] 155 ); 156 }, 'Check recency in generateBid() is below a certain threshold and rounded ' + 157 'to multiple of 100 milliseconds.'); 158 159 // Creates a bidding script URL that expects the "bidCount" to be 160 // "expectedBidCount". 161 function createBidCountBiddingScriptURL(expectedBidCount) { 162 return createBiddingScriptURL( 163 { generateBid: 164 `if (browserSignals.bidCount !== ${expectedBidCount}) 165 throw "Unexpected bidCount: " + browserSignals.bidCount;` 166 }); 167 } 168 169 subsetTest(promise_test, async test => { 170 const uuid = generateUuid(test); 171 172 // Running an auction should not increment "bidCount". 173 await joinGroupAndRunBasicFledgeTestExpectingWinner( 174 test, uuid, 175 { name: uuid, 176 biddingLogicURL: createBidCountBiddingScriptURL(0)}); 177 178 // These auctions would have no winner if the "bidCount" were incremented. 179 await runBasicFledgeAuction(test, uuid); 180 await runBasicFledgeAuction(test, uuid); 181 }, 'browserSignals.bidCount not incremented when ad not used.'); 182 183 subsetTest(promise_test, async test => { 184 const uuid = generateUuid(test); 185 186 await joinInterestGroup( 187 test, uuid, 188 { name: uuid, 189 biddingLogicURL: createBidCountBiddingScriptURL(0) }); 190 await runBasicFledgeAuctionAndNavigate(test, uuid); 191 // Wait for the navigation to trigger reports. "bidCount" should be updated before 192 // any reports are sent. 193 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 194 195 await joinInterestGroup( 196 test, uuid, 197 { name: uuid, 198 biddingLogicURL: createBidCountBiddingScriptURL(1) }); 199 await runBasicFledgeAuctionAndNavigate(test, uuid); 200 // Wait for the navigation to trigger reports. "bidCount" should be updated before 201 // any reports are sent. 202 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 203 createSellerReportURL(uuid)]); 204 205 await joinInterestGroup( 206 test, uuid, 207 { name: uuid, 208 biddingLogicURL: createBidCountBiddingScriptURL(2) }); 209 await runBasicFledgeTestExpectingWinner(test, uuid); 210 }, 'browserSignals.bidCount incremented when ad used.'); 211 212 subsetTest(promise_test, async test => { 213 const uuid = generateUuid(test); 214 215 // Join an interest group and run an auction and navigate to the winning ad, 216 // increasing the bid count to 1. 217 await joinInterestGroup( 218 test, uuid, 219 { name: uuid, 220 biddingLogicURL: createBidCountBiddingScriptURL(0)}); 221 await runBasicFledgeAuctionAndNavigate(test, uuid); 222 // Wait for the navigation to trigger reports. "bidCount" should be updated before 223 // any reports are sent. 224 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 225 226 await joinCrossOriginInterestGroupInTopLevelWindow( 227 test, uuid, OTHER_ORIGIN1, window.location.origin, 228 { name: uuid, 229 biddingLogicURL: createBidCountBiddingScriptURL(1) }); 230 await runBasicFledgeTestExpectingWinner(test, uuid); 231 }, 'browserSignals.bidCount persists across re-join from other top-level origin.'); 232 233 subsetTest(promise_test, async test => { 234 const uuid = generateUuid(test); 235 236 // Join an interest group and run an auction and navigate to the winning ad, 237 // increasing the bid count to 1. 238 await joinInterestGroup( 239 test, uuid, 240 { name: uuid, 241 biddingLogicURL: createBidCountBiddingScriptURL(0) }); 242 await runBasicFledgeAuctionAndNavigate(test, uuid); 243 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 244 245 // Leaving interest group should clear "bidCount". 246 await leaveInterestGroup({name: uuid}); 247 248 // Check that bid count was cleared. 249 await joinInterestGroup( 250 test, uuid, 251 { name: uuid, 252 biddingLogicURL: createBidCountBiddingScriptURL(0)}); 253 await runBasicFledgeTestExpectingWinner(test, uuid); 254 }, 'browserSignals.bidCount leave and rejoin.'); 255 256 subsetTest(promise_test, async test => { 257 const uuid = generateUuid(test); 258 259 await joinInterestGroup( 260 test, uuid, 261 { name: uuid, 262 biddingLogicURL: createBidCountBiddingScriptURL(0)} ); 263 264 // Run two auctions at once, without any navigations. 265 // "bidCount" should be 0 for both auctions. 266 let fencedFrameConfigs = 267 await Promise.all([runBasicFledgeTestExpectingWinner(test, uuid), 268 runBasicFledgeTestExpectingWinner(test, uuid)]); 269 270 // Start navigating to both auction winners. 271 createAndNavigateFencedFrame(test, fencedFrameConfigs[0]); 272 createAndNavigateFencedFrame(test, fencedFrameConfigs[1]); 273 274 // Wait for navigations to have sent reports (and thus to have updated 275 // bid counts). 276 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 277 createSellerReportURL(uuid)]); 278 279 // Check that "bidCount" has increased by 2. 280 await joinInterestGroup( 281 test, uuid, 282 { name: uuid, 283 biddingLogicURL: createBidCountBiddingScriptURL(2) }); 284 await runBasicFledgeTestExpectingWinner(test, uuid); 285 }, 'browserSignals.bidCount two auctions at once.'); 286 287 subsetTest(promise_test, async test => { 288 const uuid = generateUuid(test); 289 290 // Use a tracker URL for the ad. It won't be successfully loaded, due to missing 291 // the fenced frame header, but it should be fetched twice. 292 let trackedRenderURL = 293 createTrackerURL(window.location.origin, uuid, 'track_get', /*id=*/'ad'); 294 await joinInterestGroup( 295 test, uuid, 296 { name: uuid, 297 biddingLogicURL: createBidCountBiddingScriptURL(0), 298 ads: [{ renderURL: trackedRenderURL }] 299 }); 300 301 let fencedFrameConfig = await runBasicFledgeTestExpectingWinner(test, uuid); 302 303 // Start navigating two frames to the winning ad. 304 createAndNavigateFencedFrame(test, fencedFrameConfig); 305 createAndNavigateFencedFrame(test, fencedFrameConfig); 306 307 // Wait for both navigations to have requested ads (and thus to have updated 308 // bid counts). 309 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 310 trackedRenderURL, 311 trackedRenderURL]); 312 313 // Check that "bidCount" has increased by only 1. 314 await joinInterestGroup( 315 test, uuid, 316 { name: uuid, 317 biddingLogicURL: createBidCountBiddingScriptURL(1) }); 318 await runBasicFledgeTestExpectingWinner(test, uuid); 319 }, 'browserSignals.bidCount incremented once when winning ad used twice.'); 320 321 subsetTest(promise_test, async test => { 322 const uuid = generateUuid(test); 323 324 let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); 325 326 // Join an interest group named "uuid", which will bid 0.1, losing the first auction. 327 await joinInterestGroup( 328 test, uuid, 329 { name: uuid, 330 biddingLogicURL: createBiddingScriptURL( 331 { bid: 0.1, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) 332 }); 333 334 // Join an interest group with the default name, which will bid 1 and win the first 335 // auction, sending a bidder report. 336 await joinInterestGroup( 337 test, uuid, 338 { biddingLogicURL: createBiddingScriptURL( 339 { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) 340 }); 341 342 // Run an auction that both bidders participate in. Despite the first interest group 343 // losing, its "bidCount" should be incremented. 344 await runBasicFledgeAuctionAndNavigate(test, uuid); 345 // Make sure the right bidder won. 346 await waitForObservedRequests(uuid, [bidderReportURL, createSellerReportURL(uuid)]); 347 348 // Leave the second interest group (which has the default name). 349 await leaveInterestGroup(); 350 351 // Re-join the first interest group, with a bidding script that checks its "bidCount". 352 await joinInterestGroup( 353 test, uuid, 354 { name: uuid, 355 biddingLogicURL: createBidCountBiddingScriptURL(1) 356 }); 357 358 await runBasicFledgeTestExpectingWinner(test, uuid); 359 }, 'browserSignals.bidCount incremented when another interest group wins.'); 360 361 subsetTest(promise_test, async test => { 362 const uuid = generateUuid(test); 363 364 // Use default interest group, other than using a unique name. It will make a bid. 365 await joinInterestGroup(test, uuid, { name: uuid }); 366 // Run auction with seller that rejects all bids. 367 await runBasicFledgeTestExpectingNoWinner( 368 test, uuid, 369 { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `return 0;`})}); 370 371 await joinInterestGroup( 372 test, uuid, 373 { name: uuid, 374 biddingLogicURL: createBidCountBiddingScriptURL(1) 375 }); 376 await runBasicFledgeTestExpectingWinner(test, uuid); 377 }, 'browserSignals.bidCount incremented when seller rejects bid.'); 378 379 subsetTest(promise_test, async test => { 380 const uuid = generateUuid(test); 381 382 // Use default interest group, other than using a unique name. It will make a bid. 383 await joinInterestGroup(test, uuid, { name: uuid }); 384 // Run auction with seller that always throws. 385 await runBasicFledgeTestExpectingNoWinner( 386 test, uuid, 387 { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `throw "a fit";`})}); 388 389 await joinInterestGroup( 390 test, uuid, 391 { name: uuid, 392 biddingLogicURL: createBidCountBiddingScriptURL(1) 393 }); 394 await runBasicFledgeTestExpectingWinner(test, uuid); 395 }, 'browserSignals.bidCount incremented when seller throws.'); 396 397 subsetTest(promise_test, async test => { 398 const uuid = generateUuid(test); 399 400 // Interest group that does not bid. 401 await joinInterestGroup( 402 test, uuid, 403 { name: uuid, 404 biddingLogicURL: createBiddingScriptURL( 405 { generateBid: 'return;' }) 406 }); 407 await runBasicFledgeTestExpectingNoWinner(test, uuid); 408 409 // Check that "bidCount" was not incremented. 410 await joinInterestGroup( 411 test, uuid, 412 { name: uuid, 413 biddingLogicURL: createBidCountBiddingScriptURL(0) 414 }); 415 await runBasicFledgeTestExpectingWinner(test, uuid); 416 }, 'browserSignals.bidCount not incremented when no bid.'); 417 418 subsetTest(promise_test, async test => { 419 const uuid = generateUuid(test); 420 421 let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); 422 423 // Interest group that does not bid. 424 await joinInterestGroup( 425 test, uuid, 426 { name: uuid, 427 biddingLogicURL: createBiddingScriptURL( 428 { generateBid: 'return;' }) 429 }); 430 431 // Join an interest group with the default name, which will bid 1 and win the first 432 // auction, sending a bidder report. 433 await joinInterestGroup( 434 test, uuid, 435 { biddingLogicURL: createBiddingScriptURL( 436 { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) 437 }); 438 439 // Run an auction that both bidders participate in, and make sure the right bidder won. 440 await runBasicFledgeAuctionAndNavigate(test, uuid); 441 await waitForObservedRequests(uuid, [bidderReportURL, createSellerReportURL(uuid)]); 442 443 // Leave the second interest group (which has the default name). 444 await leaveInterestGroup(); 445 446 // Re-join the first interest group, with a bidding script that checks its "bidCount". 447 await joinInterestGroup( 448 test, uuid, 449 { name: uuid, 450 biddingLogicURL: createBidCountBiddingScriptURL(0) 451 }); 452 453 await runBasicFledgeTestExpectingWinner(test, uuid); 454 }, 'browserSignals.bidCount not incremented when no bid and another interest group wins.'); 455 456 subsetTest(promise_test, async test => { 457 const uuid = generateUuid(test); 458 459 let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); 460 461 await joinInterestGroup( 462 test, uuid, 463 { name: uuid, 464 biddingLogicURL: createBiddingScriptURL( 465 { bid: 42, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) 466 }); 467 468 // Join an interest group with the default name, which will bid 1 and win the first 469 // auction, sending a bidder report. 470 await joinInterestGroup( 471 test, uuid, 472 { biddingLogicURL: createBiddingScriptURL( 473 { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) 474 }); 475 476 // Run an auction that both bidders participate in. The scoreAd script rejects the 477 // first interest group's bid. 478 await runBasicFledgeAuctionAndNavigate( 479 test, uuid, 480 { decisionLogicURL: createDecisionScriptURL( 481 uuid, 482 { scoreAd: `if (bid === 42) return -1;`})}); 483 // Make sure the second interest group won. 484 await waitForObservedRequests(uuid, [bidderReportURL]); 485 486 // Leave the second interest group (which has the default name). 487 await leaveInterestGroup(); 488 489 // Re-join the first interest group, with a bidding script that checks its "bidCount". 490 await joinInterestGroup( 491 test, uuid, 492 { name: uuid, 493 biddingLogicURL: createBidCountBiddingScriptURL(1) 494 }); 495 496 await runBasicFledgeTestExpectingWinner(test, uuid); 497 }, 'browserSignals.bidCount incremented when makes largest bid, but seller rejects the bid.'); 498 499 // Creates a bidding script URL that expects "prevWinsMs" to be 500 // "expectedPrevWinsMs". All times in "expectedPrevWinsMs" must be 0. 501 // 502 // "adIndex" is the index of the ad to use in the bid. 503 function createPrevWinsMsBiddingScriptURL(expectedPrevWinsMs, adIndex = 0) { 504 return createBiddingScriptURL( 505 { generateBid: 506 `for (let i = 0; i < browserSignals.prevWinsMs.length; i++) { 507 // Check age is in a reasonable range. 508 if (browserSignals.prevWinsMs[i][0] < 0 || 509 browserSignals.prevWinsMs[i][0] > 30000) { 510 throw "Unexpected prevWinsMs time: " + JSON.stringify(browserSignals.prevWinsMs); 511 } 512 513 // Set age to 0. 514 browserSignals.prevWinsMs[i][0] = 0; 515 516 // Remove obsolete field, if present. 517 delete browserSignals.prevWinsMs[i][1].render_url; 518 } 519 if (!deepEquals(browserSignals.prevWinsMs, ${JSON.stringify(expectedPrevWinsMs)})) 520 throw "Unexpected prevWinsMs: " + JSON.stringify(browserSignals.prevWinsMs); 521 522 return { 523 bid: 1, 524 render: interestGroup.ads[${adIndex}].renderURL 525 };` 526 }); 527 } 528 529 subsetTest(promise_test, async test => { 530 const uuid = generateUuid(test); 531 532 // Running an auction should not increment "prevWinsMs". 533 await joinGroupAndRunBasicFledgeTestExpectingWinner( 534 test, uuid, 535 { name: uuid, 536 biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); 537 538 // These auctions would have no winner if the "prevWinsMs" were incremented. 539 await runBasicFledgeAuction(test, uuid); 540 await runBasicFledgeAuction(test, uuid); 541 }, 'browserSignals.prevWinsMs not affected when ad not used.'); 542 543 subsetTest(promise_test, async test => { 544 const uuid = generateUuid(test); 545 546 await joinInterestGroup( 547 test, uuid, 548 { name: uuid, 549 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) }); 550 await runBasicFledgeAuctionAndNavigate(test, uuid); 551 // Wait for the navigation to trigger reports. "prevWinsMs" should be updated before 552 // any reports are sent. 553 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 554 555 await joinInterestGroup( 556 test, uuid, 557 { name: uuid, 558 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 559 [[0, {renderURL: createRenderURL(uuid)}]]) }); 560 await runBasicFledgeAuctionAndNavigate(test, uuid); 561 // Wait for the navigation to trigger reports. "prevWinsMs" should be updated before 562 // any reports are sent. 563 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 564 createSellerReportURL(uuid)]); 565 566 await joinInterestGroup( 567 test, uuid, 568 { name: uuid, 569 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 570 [ [0, {renderURL: createRenderURL(uuid)}], 571 [0, {renderURL: createRenderURL(uuid)}]]) }); 572 await runBasicFledgeTestExpectingWinner(test, uuid); 573 }, 'browserSignals.prevWinsMs, no metadata.'); 574 575 subsetTest(promise_test, async test => { 576 const uuid = generateUuid(test); 577 const ads = [ {renderURL: createRenderURL(uuid, 0), metadata: null}, 578 {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}, 579 {renderURL: createRenderURL(uuid, 2)} ]; 580 581 await joinInterestGroup( 582 test, uuid, 583 { name: uuid, 584 biddingLogicURL: createPrevWinsMsBiddingScriptURL([], /*adIndex=*/0), 585 ads: ads }); 586 await runBasicFledgeAuctionAndNavigate(test, uuid); 587 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 588 589 await joinInterestGroup( 590 test, uuid, 591 { name: uuid, 592 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 593 [[0, {renderURL: createRenderURL(uuid, 0), metadata: null}]], 594 /*adIndex=*/1), 595 ads: ads }); 596 await runBasicFledgeAuctionAndNavigate(test, uuid); 597 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 598 createSellerReportURL(uuid)]); 599 600 await joinInterestGroup( 601 test, uuid, 602 { name: uuid, 603 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 604 [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], 605 [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}] ], 606 /*adIndex=*/2), 607 ads: ads }); 608 await runBasicFledgeAuctionAndNavigate(test, uuid); 609 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 610 createSellerReportURL(uuid), 611 createSellerReportURL(uuid)]); 612 613 await joinInterestGroup( 614 test, uuid, 615 { name: uuid, 616 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 617 [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], 618 [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}], 619 [0, {renderURL: createRenderURL(uuid, 2)}] ]), 620 ads: ads }); 621 await runBasicFledgeTestExpectingWinner(test, uuid); 622 }, 'browserSignals.prevWinsMs, with metadata.'); 623 624 subsetTest(promise_test, async test => { 625 const uuid = generateUuid(test); 626 const ads = [ {renderURL: createRenderURL(uuid, 0), metadata: null}, 627 {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}, 628 {renderURL: createRenderURL(uuid, 2)} ]; 629 630 await joinInterestGroup( 631 test, uuid, 632 { name: uuid, 633 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]), 634 ads: [{renderURL: createRenderURL(uuid, 0), metadata: null}] }); 635 await runBasicFledgeAuctionAndNavigate(test, uuid); 636 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 637 638 await joinInterestGroup( 639 test, uuid, 640 { name: uuid, 641 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 642 [[0, {renderURL: createRenderURL(uuid, 0), metadata: null}]]), 643 ads: [{renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}] }); 644 await runBasicFledgeAuctionAndNavigate(test, uuid); 645 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 646 createSellerReportURL(uuid)]); 647 648 await joinInterestGroup( 649 test, uuid, 650 { name: uuid, 651 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 652 [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], 653 [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}] ]), 654 ads: [{renderURL: createRenderURL(uuid, 2)}] }); 655 await runBasicFledgeAuctionAndNavigate(test, uuid); 656 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 657 createSellerReportURL(uuid), 658 createSellerReportURL(uuid)]); 659 660 await joinInterestGroup( 661 test, uuid, 662 { name: uuid, 663 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 664 [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], 665 [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}], 666 [0, {renderURL: createRenderURL(uuid, 2)}] ]) }); 667 await runBasicFledgeTestExpectingWinner(test, uuid); 668 }, 'browserSignals.prevWinsMs, different set of ads for each bid.'); 669 670 subsetTest(promise_test, async test => { 671 const uuid = generateUuid(test); 672 673 // Join an interest group and run an auction and navigate to the winning ad, 674 // which should be logged in "prevWinsMs". 675 await joinInterestGroup( 676 test, uuid, 677 { name: uuid, 678 biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); 679 await runBasicFledgeAuctionAndNavigate(test, uuid); 680 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 681 682 await joinCrossOriginInterestGroupInTopLevelWindow( 683 test, uuid, OTHER_ORIGIN1, window.location.origin, 684 { name: uuid, 685 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 686 [[0, {renderURL: createRenderURL(uuid)}]]) }); 687 await runBasicFledgeTestExpectingWinner(test, uuid); 688 }, 'browserSignals.prevWinsMs persists across re-join from other top-level origin.'); 689 690 subsetTest(promise_test, async test => { 691 const uuid = generateUuid(test); 692 693 // Join an interest group and run an auction and navigate to the winning ad, 694 // which should be logged in "prevWinsMs". 695 await joinInterestGroup( 696 test, uuid, 697 { name: uuid, 698 biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); 699 await runBasicFledgeAuctionAndNavigate(test, uuid); 700 await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); 701 702 // Leaving interest group should clear "prevWinsMs". 703 await leaveInterestGroup({name: uuid}); 704 705 // Check that bid count was cleared. 706 await joinInterestGroup( 707 test, uuid, 708 { name: uuid, 709 biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); 710 await runBasicFledgeTestExpectingWinner(test, uuid); 711 }, 'browserSignals.prevWinsMs leave and rejoin.'); 712 713 subsetTest(promise_test, async test => { 714 const uuid = generateUuid(test); 715 716 await joinInterestGroup( 717 test, uuid, 718 { name: uuid, 719 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) 720 }); 721 722 // Run two auctions at once, without any navigations. 723 // "prevWinsMs" should be empty for both auctions. 724 let fencedFrameConfigs = 725 await Promise.all([runBasicFledgeTestExpectingWinner(test, uuid), 726 runBasicFledgeTestExpectingWinner(test, uuid)]); 727 728 // Start navigating to both auction winners. 729 createAndNavigateFencedFrame(test, fencedFrameConfigs[0]); 730 createAndNavigateFencedFrame(test, fencedFrameConfigs[1]); 731 732 // Wait for navigations to have sent reports (and thus to have updated 733 // "prevWinsMs"). 734 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 735 createSellerReportURL(uuid)]); 736 737 // Check that "prevWinsMs" has two URLs. 738 await joinInterestGroup( 739 test, uuid, 740 { name: uuid, 741 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 742 [[0, {renderURL: createRenderURL(uuid)}], 743 [0, {renderURL: createRenderURL(uuid)}]]) 744 }); 745 await runBasicFledgeTestExpectingWinner(test, uuid); 746 }, 'browserSignals.prevWinsMs two auctions at once.'); 747 748 subsetTest(promise_test, async test => { 749 const uuid = generateUuid(test); 750 751 // Use a tracker URL for the ad. It won't be successfully loaded, due to missing 752 // the fenced frame header, but it should be fetched twice. 753 let trackedRenderURL = 754 createTrackerURL(window.location.origin, uuid, 'track_get', /*id=*/'ad'); 755 await joinInterestGroup( 756 test, uuid, 757 { name: uuid, 758 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]), 759 ads: [{ renderURL: trackedRenderURL }] 760 }); 761 762 let fencedFrameConfig = await runBasicFledgeTestExpectingWinner(test, uuid); 763 764 // Start navigating two frames to the winning ad. 765 createAndNavigateFencedFrame(test, fencedFrameConfig); 766 createAndNavigateFencedFrame(test, fencedFrameConfig); 767 768 // Wait for both navigations to have requested ads (and thus to have updated 769 // "prevWinsMs"). 770 await waitForObservedRequests(uuid, [createSellerReportURL(uuid), 771 trackedRenderURL, 772 trackedRenderURL]); 773 774 // Check that "prevWins" has only a single win. 775 await joinInterestGroup( 776 test, uuid, 777 { name: uuid, 778 biddingLogicURL: createPrevWinsMsBiddingScriptURL( 779 [[0, {renderURL: trackedRenderURL}]]) }); 780 await runBasicFledgeTestExpectingWinner(test, uuid); 781 }, 'browserSignals.prevWinsMs has only one win when winning ad used twice.'); 782 783 subsetTest(promise_test, async test => { 784 const uuid = generateUuid(test); 785 786 let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); 787 788 // Join an interest group named "uuid", which will bid 0.1, losing the first auction. 789 await joinInterestGroup( 790 test, uuid, 791 { name: uuid, 792 biddingLogicURL: createBiddingScriptURL( 793 { bid: 0.1, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) 794 }); 795 796 // Join an interest group with the default name, which will bid 1 and win the first 797 // auction, sending a bidder report. 798 await joinInterestGroup( 799 test, uuid, 800 { biddingLogicURL: createBiddingScriptURL( 801 { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) 802 }); 803 804 // Run an auction that both bidders participate in, and make sure the right bidder won. 805 await runBasicFledgeAuctionAndNavigate(test, uuid); 806 await waitForObservedRequests(uuid, [bidderReportURL, createSellerReportURL(uuid)]); 807 808 // Leave the second interest group (which has the default name). 809 await leaveInterestGroup(); 810 811 // Re-join the first interest group, with a bidding script that expects prevWinsMs to 812 // be empty. 813 await joinInterestGroup( 814 test, uuid, 815 { name: uuid, 816 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) 817 }); 818 819 await runBasicFledgeTestExpectingWinner(test, uuid); 820 }, 'browserSignals.prevWinsMs not updated when another interest group wins.'); 821 822 subsetTest(promise_test, async test => { 823 const uuid = generateUuid(test); 824 825 // Use default interest group, other than using a unique name. It will make a bid. 826 await joinInterestGroup(test, uuid, { name: uuid }); 827 // Run auction with seller that rejects all bids. 828 await runBasicFledgeTestExpectingNoWinner( 829 test, uuid, 830 { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `return 0;`})}); 831 832 await joinInterestGroup( 833 test, uuid, 834 { name: uuid, 835 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) 836 }); 837 await runBasicFledgeTestExpectingWinner(test, uuid); 838 }, 'browserSignals.prevWinsMs not updated when seller rejects bid.'); 839 840 subsetTest(promise_test, async test => { 841 const uuid = generateUuid(test); 842 843 // Use default interest group, other than using a unique name. It will make a bid. 844 await joinInterestGroup(test, uuid, { name: uuid }); 845 // Run auction with seller that always throws. 846 await runBasicFledgeTestExpectingNoWinner( 847 test, uuid, 848 { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `throw "a fit";`})}); 849 850 await joinInterestGroup( 851 test, uuid, 852 { name: uuid, 853 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) 854 }); 855 await runBasicFledgeTestExpectingWinner(test, uuid); 856 }, 'browserSignals.prevWinsMs not updated when seller throws.'); 857 858 subsetTest(promise_test, async test => { 859 const uuid = generateUuid(test); 860 861 // Interest group that does not bid. 862 await joinInterestGroup( 863 test, uuid, 864 { name: uuid, 865 biddingLogicURL: createBiddingScriptURL( 866 { generateBid: 'return;' }) 867 }); 868 await runBasicFledgeTestExpectingNoWinner(test, uuid); 869 870 // Check that "prevWinsMs" was not modified. 871 await joinInterestGroup( 872 test, uuid, 873 { name: uuid, 874 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) 875 }); 876 await runBasicFledgeTestExpectingWinner(test, uuid); 877 }, 'browserSignals.prevWinsMs not updated when no bid.'); 878 879 subsetTest(promise_test, async test => { 880 const uuid = generateUuid(test); 881 882 let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); 883 884 await joinInterestGroup( 885 test, uuid, 886 { name: uuid, 887 biddingLogicURL: createBiddingScriptURL( 888 { bid: 42, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) 889 }); 890 891 // Join an interest group with the default name, which will bid 1 and win the first 892 // auction, sending a bidder report. 893 await joinInterestGroup( 894 test, uuid, 895 { biddingLogicURL: createBiddingScriptURL( 896 { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) 897 }); 898 899 // Run an auction that both bidders participate in. The scoreAd script returns a low 900 // score for the first interest group's bid. 901 await runBasicFledgeAuctionAndNavigate( 902 test, uuid, 903 { decisionLogicURL: createDecisionScriptURL( 904 uuid, 905 { scoreAd: `if (bid === 42) return 0.1;`})}); 906 // Make sure the second interest group won. 907 await waitForObservedRequests(uuid, [bidderReportURL]); 908 909 // Leave the second interest group (which has the default name). 910 await leaveInterestGroup(); 911 912 // Re-join the first interest group, with a bidding script that expects prevWinsMs to 913 // be empty. 914 await joinInterestGroup( 915 test, uuid, 916 { name: uuid, 917 biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) 918 }); 919 920 await runBasicFledgeTestExpectingWinner(test, uuid); 921 }, 'browserSignals.prevWinsMs not updated when makes largest bid, but another interest group wins.'); 922 923 subsetTest(promise_test, async test => { 924 const uuid = generateUuid(test); 925 926 // Join an interest group with a WASM helper that exposes a single "increment" method, 927 // and make sure that method can be invoked and behaves as expected. 928 await joinGroupAndRunBasicFledgeTestExpectingWinner( 929 test, 930 { uuid: uuid, 931 interestGroupOverrides: { 932 biddingWasmHelperURL: `${RESOURCE_PATH}wasm-helper.py`, 933 biddingLogicURL: createBiddingScriptURL( 934 { generateBid: 935 `if (!browserSignals.wasmHelper) 936 throw "No WASM helper"; 937 938 let instance = new WebAssembly.Instance(browserSignals.wasmHelper); 939 if (!instance) 940 throw "Couldn't create WASM Instance"; 941 942 if (!deepEquals(Object.keys(instance.exports), ["increment"])) 943 throw "Unexpected exports: " + JSON.stringify(instance.exports); 944 945 if (instance.exports.increment(1) !== 2) 946 throw "Unexpected increment result: " + instance.exports.increment(1);` }) 947 } 948 }); 949 }, 'browserSignals.wasmHelper.'); 950 951 952 // Generates 0 or 1 clicks, dependent on `produceAttributionSrc` & 953 // `produceUserAction`, and `numViews` views for `igOwner`, provided by 954 // `viewClickProvider`. 955 async function generateViewsAndClicks( 956 test, uuid, viewClickProvider, igOwner, numViews, produceAttributionSrc, 957 produceUserAction) { 958 let iframe = await createIframe(test, viewClickProvider); 959 let script = ` 960 // We use a wrapper iframe here so the original remains in communication. 961 let frame = document.createElement('iframe'); 962 document.body.appendChild(frame); 963 let frameDocument = frame.contentDocument; 964 let a = frameDocument.createElement('a'); 965 a.href = '${RESOURCE_PATH}/record-click.py?' + 966 'eligible_origin=${igOwner}&num_views=${numViews}'; 967 if (${produceAttributionSrc}) { 968 a.attributionSrc = ''; 969 } 970 a.target = '_self'; 971 a.appendChild(frameDocument.createTextNode('Click me')); 972 frameDocument.body.appendChild(a); 973 974 if (${produceUserAction}) { 975 // Note: test_driver.click() seems to not work well with Chrome's 976 // content_shell; while .bless() does... unreliably. 977 // headless_shell/chrome path seems to work reliably. User activation 978 // is used sparingly to work around content_shell flakiness. 979 await test_driver.bless('User-initiated click', () => { a.click() }); 980 } else { 981 a.click(); 982 } 983 `; 984 985 await runInFrame(test, iframe, script); 986 }