| // META: script=/resources/testdriver.js |
| // META: script=/resources/testdriver-vendor.js |
| // META: script=/common/utils.js |
| // META: script=resources/fledge-util.sub.js |
| // META: script=/common/subset-tests.js |
| // META: timeout=long |
| // META: variant=?1-4 |
| // META: variant=?5-8 |
| // META: variant=?9-12 |
| // META: variant=?13-16 |
| // META: variant=?17-20 |
| // META: variant=?21-24 |
| // META: variant=?25-28 |
| // META: variant=?29-32 |
| // META: variant=?33-36 |
| // META: variant=?37-last |
| |
| "use strict"; |
| |
| // These tests focus on the browserSignals argument passed to generateBid(). |
| // Note that "topLevelSeller" is covered by component auction tests, |
| // "dataVersion" by trusted signals tests, and cross-origin |
| // "topWindowHostname" and "seller" are covered by cross origin tests. |
| // |
| // Some of these tests use the "uuid" for interest group name, to avoid |
| // joins/bids from previous tests that failed to clean up after themselves |
| // from affecting results. |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| let expectedBrowserSignals = { |
| 'topWindowHostname': window.location.hostname, |
| 'seller': window.location.origin, |
| 'adComponentsLimit': 40, |
| 'joinCount': 1, |
| 'bidCount': 0, |
| 'multiBidLimit': 1, |
| 'prevWinsMs': [], |
| 'forDebuggingOnlySampling': false, |
| 'viewCounts': { |
| 'pastHour': 0, |
| 'pastDay': 0, |
| 'pastWeek': 0, |
| 'past30Days': 0, |
| 'past90Days': 0 |
| }, |
| 'clickCounts': { |
| 'pastHour': 0, |
| 'pastDay': 0, |
| 'pastWeek': 0, |
| 'past30Days': 0, |
| 'past90Days': 0 |
| } |
| }; |
| let biddingLogicURL = createBiddingScriptURL({ |
| generateBid: |
| `let expectedBrowserSignals = ${JSON.stringify(expectedBrowserSignals)}; |
| |
| // Can't check this value exactly. |
| expectedBrowserSignals.recency = browserSignals.recency; |
| |
| // This value may be affected by other recently run tests. |
| expectedBrowserSignals.forDebuggingOnlyInCooldownOrLockout = |
| browserSignals.forDebuggingOnlyInCooldownOrLockout; |
| |
| // Don't check exact values of view/click reports. |
| function zeroCounts(object) { |
| object.pastHour = 0; |
| object.pastDay = 0; |
| object.pastWeek = 0; |
| object.past30Days = 0; |
| object.past90Days = 0; |
| } |
| zeroCounts(browserSignals.viewCounts); |
| zeroCounts(browserSignals.clickCounts); |
| |
| // Remove deprecated field, if present. |
| delete browserSignals.prevWins; |
| |
| if (!deepEquals(browserSignals, expectedBrowserSignals)) |
| throw "Unexpected browserSignals: " + JSON.stringify(browserSignals);` |
| }); |
| |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: {name: uuid, |
| biddingLogicURL: biddingLogicURL}}); |
| }, 'Only expected fields present.'); |
| |
| // Creates a bidding script URL that expects the "joinCount" to be |
| // "expectedJoinCount". |
| function createJoinCountBiddingScriptURL(expectedJoinCount) { |
| return createBiddingScriptURL( |
| { generateBid: |
| `if (browserSignals.joinCount !== ${expectedJoinCount}) |
| throw "Unexpected joinCount: " + browserSignals.joinCount;` |
| }); |
| } |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: {name: uuid, |
| biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); |
| |
| // Joining again, even with a different script URL, should increase the join count. |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: {name: uuid, |
| biddingLogicURL: createJoinCountBiddingScriptURL(2)}}); |
| }, 'browserSignals.joinCount same joining page.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: {name: uuid, |
| biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); |
| |
| // Attempt to re-join the same interest group from a different top-level origin. |
| // The join count should still be persisted. |
| await joinCrossOriginInterestGroupInTopLevelWindow( |
| test, uuid, OTHER_ORIGIN1, window.location.origin, |
| { name: uuid, |
| biddingLogicURL: createJoinCountBiddingScriptURL(2)}); |
| |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.joinCount different top-level joining origin.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: {name: uuid, |
| biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); |
| |
| // Leaving interest group should clear join count. |
| await leaveInterestGroup({name: uuid}); |
| |
| // Check that join count was cleared. |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: {name: uuid, |
| biddingLogicURL: createJoinCountBiddingScriptURL(1)}}); |
| }, 'browserSignals.joinCount leave and rejoin.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| await runReportTest( |
| test, uuid, |
| { generateBid: |
| `if (browserSignals.recency === undefined) |
| throw new Error("Missing recency in browserSignals.") |
| |
| if (browserSignals.recency < 0) |
| throw new Error("Recency is a negative value.") |
| |
| if (browserSignals.recency > 30000) |
| throw new Error("Recency is over 30 seconds threshold.") |
| |
| if (browserSignals.recency % 100 !== 0) |
| throw new Error("Recency is not rounded to multiple of 100 milliseconds.") |
| |
| return {'bid': 9, |
| 'render': interestGroup.ads[0].renderURL};`, |
| reportWin: |
| `sendReportTo('${createBidderReportURL(uuid)}');` |
| }, |
| // expectedReportURLs |
| [createBidderReportURL(uuid)] |
| ); |
| }, 'Check recency in generateBid() is below a certain threshold and rounded ' + |
| 'to multiple of 100 milliseconds.'); |
| |
| // Creates a bidding script URL that expects the "bidCount" to be |
| // "expectedBidCount". |
| function createBidCountBiddingScriptURL(expectedBidCount) { |
| return createBiddingScriptURL( |
| { generateBid: |
| `if (browserSignals.bidCount !== ${expectedBidCount}) |
| throw "Unexpected bidCount: " + browserSignals.bidCount;` |
| }); |
| } |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Running an auction should not increment "bidCount". |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0)}); |
| |
| // These auctions would have no winner if the "bidCount" were incremented. |
| await runBasicFledgeAuction(test, uuid); |
| await runBasicFledgeAuction(test, uuid); |
| }, 'browserSignals.bidCount not incremented when ad not used.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0) }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| // Wait for the navigation to trigger reports. "bidCount" should be updated before |
| // any reports are sent. |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| // Wait for the navigation to trigger reports. "bidCount" should be updated before |
| // any reports are sent. |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(2) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount incremented when ad used.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Join an interest group and run an auction and navigate to the winning ad, |
| // increasing the bid count to 1. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0)}); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| // Wait for the navigation to trigger reports. "bidCount" should be updated before |
| // any reports are sent. |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| await joinCrossOriginInterestGroupInTopLevelWindow( |
| test, uuid, OTHER_ORIGIN1, window.location.origin, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount persists across re-join from other top-level origin.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Join an interest group and run an auction and navigate to the winning ad, |
| // increasing the bid count to 1. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0) }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| // Leaving interest group should clear "bidCount". |
| await leaveInterestGroup({name: uuid}); |
| |
| // Check that bid count was cleared. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0)}); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount leave and rejoin.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0)} ); |
| |
| // Run two auctions at once, without any navigations. |
| // "bidCount" should be 0 for both auctions. |
| let fencedFrameConfigs = |
| await Promise.all([runBasicFledgeTestExpectingWinner(test, uuid), |
| runBasicFledgeTestExpectingWinner(test, uuid)]); |
| |
| // Start navigating to both auction winners. |
| createAndNavigateFencedFrame(test, fencedFrameConfigs[0]); |
| createAndNavigateFencedFrame(test, fencedFrameConfigs[1]); |
| |
| // Wait for navigations to have sent reports (and thus to have updated |
| // bid counts). |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| // Check that "bidCount" has increased by 2. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(2) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount two auctions at once.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Use a tracker URL for the ad. It won't be successfully loaded, due to missing |
| // the fenced frame header, but it should be fetched twice. |
| let trackedRenderURL = |
| createTrackerURL(window.location.origin, uuid, 'track_get', /*id=*/'ad'); |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0), |
| ads: [{ renderURL: trackedRenderURL }] |
| }); |
| |
| let fencedFrameConfig = await runBasicFledgeTestExpectingWinner(test, uuid); |
| |
| // Start navigating two frames to the winning ad. |
| createAndNavigateFencedFrame(test, fencedFrameConfig); |
| createAndNavigateFencedFrame(test, fencedFrameConfig); |
| |
| // Wait for both navigations to have requested ads (and thus to have updated |
| // bid counts). |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| trackedRenderURL, |
| trackedRenderURL]); |
| |
| // Check that "bidCount" has increased by only 1. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount incremented once when winning ad used twice.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); |
| |
| // Join an interest group named "uuid", which will bid 0.1, losing the first auction. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { bid: 0.1, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) |
| }); |
| |
| // Join an interest group with the default name, which will bid 1 and win the first |
| // auction, sending a bidder report. |
| await joinInterestGroup( |
| test, uuid, |
| { biddingLogicURL: createBiddingScriptURL( |
| { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) |
| }); |
| |
| // Run an auction that both bidders participate in. Despite the first interest group |
| // losing, its "bidCount" should be incremented. |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| // Make sure the right bidder won. |
| await waitForObservedRequests(uuid, [bidderReportURL, createSellerReportURL(uuid)]); |
| |
| // Leave the second interest group (which has the default name). |
| await leaveInterestGroup(); |
| |
| // Re-join the first interest group, with a bidding script that checks its "bidCount". |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) |
| }); |
| |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount incremented when another interest group wins.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Use default interest group, other than using a unique name. It will make a bid. |
| await joinInterestGroup(test, uuid, { name: uuid }); |
| // Run auction with seller that rejects all bids. |
| await runBasicFledgeTestExpectingNoWinner( |
| test, uuid, |
| { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `return 0;`})}); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount incremented when seller rejects bid.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Use default interest group, other than using a unique name. It will make a bid. |
| await joinInterestGroup(test, uuid, { name: uuid }); |
| // Run auction with seller that always throws. |
| await runBasicFledgeTestExpectingNoWinner( |
| test, uuid, |
| { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `throw "a fit";`})}); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount incremented when seller throws.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Interest group that does not bid. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { generateBid: 'return;' }) |
| }); |
| await runBasicFledgeTestExpectingNoWinner(test, uuid); |
| |
| // Check that "bidCount" was not incremented. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount not incremented when no bid.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); |
| |
| // Interest group that does not bid. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { generateBid: 'return;' }) |
| }); |
| |
| // Join an interest group with the default name, which will bid 1 and win the first |
| // auction, sending a bidder report. |
| await joinInterestGroup( |
| test, uuid, |
| { biddingLogicURL: createBiddingScriptURL( |
| { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) |
| }); |
| |
| // Run an auction that both bidders participate in, and make sure the right bidder won. |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [bidderReportURL, createSellerReportURL(uuid)]); |
| |
| // Leave the second interest group (which has the default name). |
| await leaveInterestGroup(); |
| |
| // Re-join the first interest group, with a bidding script that checks its "bidCount". |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(0) |
| }); |
| |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount not incremented when no bid and another interest group wins.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { bid: 42, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) |
| }); |
| |
| // Join an interest group with the default name, which will bid 1 and win the first |
| // auction, sending a bidder report. |
| await joinInterestGroup( |
| test, uuid, |
| { biddingLogicURL: createBiddingScriptURL( |
| { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) |
| }); |
| |
| // Run an auction that both bidders participate in. The scoreAd script rejects the |
| // first interest group's bid. |
| await runBasicFledgeAuctionAndNavigate( |
| test, uuid, |
| { decisionLogicURL: createDecisionScriptURL( |
| uuid, |
| { scoreAd: `if (bid === 42) return -1;`})}); |
| // Make sure the second interest group won. |
| await waitForObservedRequests(uuid, [bidderReportURL]); |
| |
| // Leave the second interest group (which has the default name). |
| await leaveInterestGroup(); |
| |
| // Re-join the first interest group, with a bidding script that checks its "bidCount". |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBidCountBiddingScriptURL(1) |
| }); |
| |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.bidCount incremented when makes largest bid, but seller rejects the bid.'); |
| |
| // Creates a bidding script URL that expects "prevWinsMs" to be |
| // "expectedPrevWinsMs". All times in "expectedPrevWinsMs" must be 0. |
| // |
| // "adIndex" is the index of the ad to use in the bid. |
| function createPrevWinsMsBiddingScriptURL(expectedPrevWinsMs, adIndex = 0) { |
| return createBiddingScriptURL( |
| { generateBid: |
| `for (let i = 0; i < browserSignals.prevWinsMs.length; i++) { |
| // Check age is in a reasonable range. |
| if (browserSignals.prevWinsMs[i][0] < 0 || |
| browserSignals.prevWinsMs[i][0] > 30000) { |
| throw "Unexpected prevWinsMs time: " + JSON.stringify(browserSignals.prevWinsMs); |
| } |
| |
| // Set age to 0. |
| browserSignals.prevWinsMs[i][0] = 0; |
| |
| // Remove obsolete field, if present. |
| delete browserSignals.prevWinsMs[i][1].render_url; |
| } |
| if (!deepEquals(browserSignals.prevWinsMs, ${JSON.stringify(expectedPrevWinsMs)})) |
| throw "Unexpected prevWinsMs: " + JSON.stringify(browserSignals.prevWinsMs); |
| |
| return { |
| bid: 1, |
| render: interestGroup.ads[${adIndex}].renderURL |
| };` |
| }); |
| } |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Running an auction should not increment "prevWinsMs". |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); |
| |
| // These auctions would have no winner if the "prevWinsMs" were incremented. |
| await runBasicFledgeAuction(test, uuid); |
| await runBasicFledgeAuction(test, uuid); |
| }, 'browserSignals.prevWinsMs not affected when ad not used.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| // Wait for the navigation to trigger reports. "prevWinsMs" should be updated before |
| // any reports are sent. |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [[0, {renderURL: createRenderURL(uuid)}]]) }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| // Wait for the navigation to trigger reports. "prevWinsMs" should be updated before |
| // any reports are sent. |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [ [0, {renderURL: createRenderURL(uuid)}], |
| [0, {renderURL: createRenderURL(uuid)}]]) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs, no metadata.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const ads = [ {renderURL: createRenderURL(uuid, 0), metadata: null}, |
| {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}, |
| {renderURL: createRenderURL(uuid, 2)} ]; |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([], /*adIndex=*/0), |
| ads: ads }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [[0, {renderURL: createRenderURL(uuid, 0), metadata: null}]], |
| /*adIndex=*/1), |
| ads: ads }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], |
| [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}] ], |
| /*adIndex=*/2), |
| ads: ads }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], |
| [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}], |
| [0, {renderURL: createRenderURL(uuid, 2)}] ]), |
| ads: ads }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs, with metadata.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const ads = [ {renderURL: createRenderURL(uuid, 0), metadata: null}, |
| {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}, |
| {renderURL: createRenderURL(uuid, 2)} ]; |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]), |
| ads: [{renderURL: createRenderURL(uuid, 0), metadata: null}] }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [[0, {renderURL: createRenderURL(uuid, 0), metadata: null}]]), |
| ads: [{renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}] }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], |
| [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}] ]), |
| ads: [{renderURL: createRenderURL(uuid, 2)}] }); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [ [0, {renderURL: createRenderURL(uuid, 0), metadata: null}], |
| [0, {renderURL: createRenderURL(uuid, 1), metadata: ['1', 2, {3: 4}]}], |
| [0, {renderURL: createRenderURL(uuid, 2)}] ]) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs, different set of ads for each bid.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Join an interest group and run an auction and navigate to the winning ad, |
| // which should be logged in "prevWinsMs". |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| await joinCrossOriginInterestGroupInTopLevelWindow( |
| test, uuid, OTHER_ORIGIN1, window.location.origin, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [[0, {renderURL: createRenderURL(uuid)}]]) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs persists across re-join from other top-level origin.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Join an interest group and run an auction and navigate to the winning ad, |
| // which should be logged in "prevWinsMs". |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid)]); |
| |
| // Leaving interest group should clear "prevWinsMs". |
| await leaveInterestGroup({name: uuid}); |
| |
| // Check that bid count was cleared. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([])}); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs leave and rejoin.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) |
| }); |
| |
| // Run two auctions at once, without any navigations. |
| // "prevWinsMs" should be empty for both auctions. |
| let fencedFrameConfigs = |
| await Promise.all([runBasicFledgeTestExpectingWinner(test, uuid), |
| runBasicFledgeTestExpectingWinner(test, uuid)]); |
| |
| // Start navigating to both auction winners. |
| createAndNavigateFencedFrame(test, fencedFrameConfigs[0]); |
| createAndNavigateFencedFrame(test, fencedFrameConfigs[1]); |
| |
| // Wait for navigations to have sent reports (and thus to have updated |
| // "prevWinsMs"). |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| createSellerReportURL(uuid)]); |
| |
| // Check that "prevWinsMs" has two URLs. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [[0, {renderURL: createRenderURL(uuid)}], |
| [0, {renderURL: createRenderURL(uuid)}]]) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs two auctions at once.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Use a tracker URL for the ad. It won't be successfully loaded, due to missing |
| // the fenced frame header, but it should be fetched twice. |
| let trackedRenderURL = |
| createTrackerURL(window.location.origin, uuid, 'track_get', /*id=*/'ad'); |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]), |
| ads: [{ renderURL: trackedRenderURL }] |
| }); |
| |
| let fencedFrameConfig = await runBasicFledgeTestExpectingWinner(test, uuid); |
| |
| // Start navigating two frames to the winning ad. |
| createAndNavigateFencedFrame(test, fencedFrameConfig); |
| createAndNavigateFencedFrame(test, fencedFrameConfig); |
| |
| // Wait for both navigations to have requested ads (and thus to have updated |
| // "prevWinsMs"). |
| await waitForObservedRequests(uuid, [createSellerReportURL(uuid), |
| trackedRenderURL, |
| trackedRenderURL]); |
| |
| // Check that "prevWins" has only a single win. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL( |
| [[0, {renderURL: trackedRenderURL}]]) }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs has only one win when winning ad used twice.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); |
| |
| // Join an interest group named "uuid", which will bid 0.1, losing the first auction. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { bid: 0.1, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) |
| }); |
| |
| // Join an interest group with the default name, which will bid 1 and win the first |
| // auction, sending a bidder report. |
| await joinInterestGroup( |
| test, uuid, |
| { biddingLogicURL: createBiddingScriptURL( |
| { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) |
| }); |
| |
| // Run an auction that both bidders participate in, and make sure the right bidder won. |
| await runBasicFledgeAuctionAndNavigate(test, uuid); |
| await waitForObservedRequests(uuid, [bidderReportURL, createSellerReportURL(uuid)]); |
| |
| // Leave the second interest group (which has the default name). |
| await leaveInterestGroup(); |
| |
| // Re-join the first interest group, with a bidding script that expects prevWinsMs to |
| // be empty. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) |
| }); |
| |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs not updated when another interest group wins.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Use default interest group, other than using a unique name. It will make a bid. |
| await joinInterestGroup(test, uuid, { name: uuid }); |
| // Run auction with seller that rejects all bids. |
| await runBasicFledgeTestExpectingNoWinner( |
| test, uuid, |
| { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `return 0;`})}); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs not updated when seller rejects bid.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Use default interest group, other than using a unique name. It will make a bid. |
| await joinInterestGroup(test, uuid, { name: uuid }); |
| // Run auction with seller that always throws. |
| await runBasicFledgeTestExpectingNoWinner( |
| test, uuid, |
| { decisionLogicURL: createDecisionScriptURL(uuid, {scoreAd: `throw "a fit";`})}); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs not updated when seller throws.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Interest group that does not bid. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { generateBid: 'return;' }) |
| }); |
| await runBasicFledgeTestExpectingNoWinner(test, uuid); |
| |
| // Check that "prevWinsMs" was not modified. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) |
| }); |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs not updated when no bid.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| let bidderReportURL = createBidderReportURL(uuid, /*id=*/'winner'); |
| |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createBiddingScriptURL( |
| { bid: 42, reportWin: `sendReportTo('${createBidderReportURL(uuid, /*id=*/'loser')}')` }) |
| }); |
| |
| // Join an interest group with the default name, which will bid 1 and win the first |
| // auction, sending a bidder report. |
| await joinInterestGroup( |
| test, uuid, |
| { biddingLogicURL: createBiddingScriptURL( |
| { bid: 1, reportWin: `sendReportTo('${bidderReportURL}')` }) |
| }); |
| |
| // Run an auction that both bidders participate in. The scoreAd script returns a low |
| // score for the first interest group's bid. |
| await runBasicFledgeAuctionAndNavigate( |
| test, uuid, |
| { decisionLogicURL: createDecisionScriptURL( |
| uuid, |
| { scoreAd: `if (bid === 42) return 0.1;`})}); |
| // Make sure the second interest group won. |
| await waitForObservedRequests(uuid, [bidderReportURL]); |
| |
| // Leave the second interest group (which has the default name). |
| await leaveInterestGroup(); |
| |
| // Re-join the first interest group, with a bidding script that expects prevWinsMs to |
| // be empty. |
| await joinInterestGroup( |
| test, uuid, |
| { name: uuid, |
| biddingLogicURL: createPrevWinsMsBiddingScriptURL([]) |
| }); |
| |
| await runBasicFledgeTestExpectingWinner(test, uuid); |
| }, 'browserSignals.prevWinsMs not updated when makes largest bid, but another interest group wins.'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| |
| // Join an interest group with a WASM helper that exposes a single "increment" method, |
| // and make sure that method can be invoked and behaves as expected. |
| await joinGroupAndRunBasicFledgeTestExpectingWinner( |
| test, |
| { uuid: uuid, |
| interestGroupOverrides: { |
| biddingWasmHelperURL: `${RESOURCE_PATH}wasm-helper.py`, |
| biddingLogicURL: createBiddingScriptURL( |
| { generateBid: |
| `if (!browserSignals.wasmHelper) |
| throw "No WASM helper"; |
| |
| let instance = new WebAssembly.Instance(browserSignals.wasmHelper); |
| if (!instance) |
| throw "Couldn't create WASM Instance"; |
| |
| if (!deepEquals(Object.keys(instance.exports), ["increment"])) |
| throw "Unexpected exports: " + JSON.stringify(instance.exports); |
| |
| if (instance.exports.increment(1) !== 2) |
| throw "Unexpected increment result: " + instance.exports.increment(1);` }) |
| } |
| }); |
| }, 'browserSignals.wasmHelper.'); |
| |
| |
| // Generates 0 or 1 clicks, dependent on `produceAttributionSrc` & |
| // `produceUserAction`, and `numViews` views for `igOwner`, provided by |
| // `viewClickProvider`. |
| async function generateViewsAndClicks( |
| test, uuid, viewClickProvider, igOwner, numViews, produceAttributionSrc, |
| produceUserAction) { |
| let iframe = await createIframe(test, viewClickProvider); |
| let script = ` |
| // We use a wrapper iframe here so the original remains in communication. |
| let frame = document.createElement('iframe'); |
| document.body.appendChild(frame); |
| let frameDocument = frame.contentDocument; |
| let a = frameDocument.createElement('a'); |
| a.href = '${RESOURCE_PATH}/record-click.py?' + |
| 'eligible_origin=${igOwner}&num_views=${numViews}'; |
| if (${produceAttributionSrc}) { |
| a.attributionSrc = ''; |
| } |
| a.target = '_self'; |
| a.appendChild(frameDocument.createTextNode('Click me')); |
| frameDocument.body.appendChild(a); |
| |
| if (${produceUserAction}) { |
| // Note: test_driver.click() seems to not work well with Chrome's |
| // content_shell; while .bless() does... unreliably. |
| // headless_shell/chrome path seems to work reliably. User activation |
| // is used sparingly to work around content_shell flakiness. |
| await test_driver.bless('User-initiated click', () => { a.click() }); |
| } else { |
| a.click(); |
| } |
| `; |
| |
| await runInFrame(test, iframe, script); |
| } |
| |
| // Keep running a basic auction with an interest group in |
| // `interestGroupOverrides` until it succeeds; joining and leaving the |
| // IG every time to bypass caching which is permitted to provide stale |
| // view/click counts. |
| async function keepTryingAuctionUntilWinBypassCaching( |
| test, uuid, interestGroupOverrides) { |
| while (true) { |
| await joinInterestGroup(test, uuid, interestGroupOverrides); |
| let result = await runBasicFledgeAuction(test, uuid); |
| if (result !== null) { // Got a winner. |
| break; |
| } |
| await leaveInterestGroup(interestGroupOverrides); |
| } |
| } |
| |
| // Like keepTryingAuctionUntilWinBypassCaching but for auctions with |
| // cross-origin interest group, owned by `igOwner`. |
| async function crossOriginKeepTryingAuctionUntilWinBypassCaching( |
| test, uuid, igOwner, interestGroupOverrides) { |
| while (true) { |
| await joinCrossOriginInterestGroup( |
| test, uuid, igOwner, interestGroupOverrides); |
| const auctionConfigOverrides = {interestGroupBuyers: [igOwner]}; |
| let result = |
| await runBasicFledgeAuction(test, uuid, auctionConfigOverrides); |
| if (result !== null) { // Got a winner. |
| break; |
| } |
| await leaveCrossOriginInterestGroup( |
| test, uuid, igOwner, interestGroupOverrides); |
| } |
| } |
| |
| // Generates `numViews` views and 0 or 1 clicks based on `produceAttributionSrc` |
| // and `produceUserAction`, by `viewClickProvider` available to `igOwner`, then |
| // creates an interest group for `igOwner` with given |
| // `viewAndClickCountsProviders`, and runs an auction |
| // to make sure the events are eventually available. |
| async function testClickiness( |
| test, igOwner, viewClickProvider, numViews, produceAttributionSrc, |
| produceUserAction, viewAndClickCountsProviders = undefined) { |
| const uuid = generateUuid(test); |
| |
| await generateViewsAndClicks( |
| test, uuid, viewClickProvider, igOwner, numViews, produceAttributionSrc, |
| produceUserAction); |
| |
| // For clicks to be recorded, both attributionsrc attribution must exist |
| // and a user action must be used. If we don't expect clicks, we can expect |
| // that the number is exactly 0 since re-running the test won't break that. |
| // |
| // This is relying on all tests using Ad-Auction-Record-Event using distinct |
| // `viewClickProvider`s. |
| let clicksBadTest = |
| produceAttributionSrc && produceUserAction ? '< 1' : ' !== 0'; |
| |
| let viewsBadTest = (numViews > 0) ? `< ${numViews}` : ' !== 0'; |
| |
| // Join an IG to read view/click info back. We use a UUID for a name to make |
| // sure nothing old is cached, since view/clicks are permitted to be a bit |
| // stale. |
| let interestGroupOverrides = { |
| owner: igOwner, |
| name: uuid, |
| biddingLogicURL: createBiddingScriptURL({ |
| origin: igOwner, |
| generateBid: ` |
| // We should see at least one click and numViews views the test injects. |
| if (browserSignals.clickCounts.pastHour ${clicksBadTest} || |
| browserSignals.clickCounts.pastDay ${clicksBadTest} || |
| browserSignals.clickCounts.pastWeek ${clicksBadTest} || |
| browserSignals.clickCounts.past30Days ${clicksBadTest} || |
| browserSignals.clickCounts.past90Days ${clicksBadTest} || |
| browserSignals.viewCounts.pastHour ${viewsBadTest} || |
| browserSignals.viewCounts.pastDay ${viewsBadTest} || |
| browserSignals.viewCounts.pastWeek ${viewsBadTest} || |
| browserSignals.viewCounts.past30Days ${viewsBadTest} || |
| browserSignals.viewCounts.past90Days ${viewsBadTest}) { |
| return -1; |
| } |
| ` |
| }) |
| }; |
| |
| if (viewAndClickCountsProviders) { |
| interestGroupOverrides.viewAndClickCountsProviders = |
| viewAndClickCountsProviders; |
| } |
| |
| await crossOriginKeepTryingAuctionUntilWinBypassCaching( |
| test, uuid, igOwner, interestGroupOverrides); |
| } |
| |
| subsetTest(promise_test, async test => { |
| const IG_OWNER = OTHER_ORIGIN5; |
| const VIEW_CLICK_PROVIDER = OTHER_ORIGIN6; |
| await testClickiness( |
| test, IG_OWNER, VIEW_CLICK_PROVIDER, /*numViews=*/ 2, |
| /*produceAttributionSrc=*/ true, |
| /*produceUserAction=*/ true, [VIEW_CLICK_PROVIDER]); |
| }, 'browserSignals for clickiness.'); |
| |
| subsetTest(promise_test, async test => { |
| const IG_OWNER = OTHER_ORIGIN5; |
| const VIEW_CLICK_PROVIDER = OTHER_ORIGIN5; |
| |
| await testClickiness( |
| test, IG_OWNER, VIEW_CLICK_PROVIDER, /*numViews=*/ 4, |
| /*produceAttributionSrc=*/ false, |
| /*produceUserAction=*/ false); |
| }, 'IG owner is default clickiness provider if nothing is specified'); |
| |
| subsetTest(promise_test, async test => { |
| const IG_OWNER = OTHER_ORIGIN4; |
| const VIEW_CLICK_PROVIDER = OTHER_ORIGIN4; |
| |
| await testClickiness( |
| test, IG_OWNER, VIEW_CLICK_PROVIDER, /*numViews=*/ 6, |
| /*produceAttributionSrc=*/ true, |
| /*produceUserAction=*/ true, []); |
| }, 'IG owner is default clickiness provider if empty list provided'); |
| |
| subsetTest(promise_test, async test => { |
| const IG_OWNER = OTHER_ORIGIN3; |
| const VIEW_CLICK_PROVIDER = OTHER_ORIGIN3; |
| |
| await testClickiness( |
| test, IG_OWNER, VIEW_CLICK_PROVIDER, /*numViews=*/ 0, |
| /*produceAttributionSrc=*/ true, |
| /*produceUserAction=*/ true, []); |
| }, 'browserSignals for clickiness --- just a click'); |
| |
| subsetTest(promise_test, async test => { |
| const IG_OWNER = OTHER_ORIGIN2; |
| const VIEW_CLICK_PROVIDER = OTHER_ORIGIN2; |
| |
| await testClickiness( |
| test, IG_OWNER, VIEW_CLICK_PROVIDER, /*numViews=*/ 1, |
| /*produceAttributionSrc=*/ true, |
| /*produceUserAction=*/ false, [VIEW_CLICK_PROVIDER]); |
| }, 'browserSignals for clickiness --- no click report w/o user action'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const IG_OWNER = window.location.origin; |
| const VIEW_CLICK_PROVIDER1 = OTHER_ORIGIN1; |
| const VIEW_CLICK_PROVIDER2 = window.location.origin; |
| |
| // From provider 1 have click, no views. |
| // From provider 2 have views, no clicks; |
| await generateViewsAndClicks( |
| test, uuid, VIEW_CLICK_PROVIDER1, IG_OWNER, |
| /*numViews=*/ 0, /*produceAttributionSrc=*/ true, |
| /*produceUserAction=*/ true); |
| await generateViewsAndClicks( |
| test, uuid, VIEW_CLICK_PROVIDER2, IG_OWNER, |
| /*numViews=*/ 2, /*produceAttributionSrc=*/ false, |
| /*produceUserAction=*/ false); |
| |
| // Create an IG that subscribes only to provider 2 --- it should only see |
| // the views. |
| let interestGroupOverrides = { |
| name: uuid, |
| viewAndClickCountsProviders: [VIEW_CLICK_PROVIDER2], |
| biddingLogicURL: createBiddingScriptURL({ |
| generateBid: ` |
| if (browserSignals.clickCounts.pastHour !== 0 || |
| browserSignals.viewCounts.pastHour < 2) { |
| throw JSON.stringify(browserSignals); |
| } |
| ` |
| }) |
| }; |
| |
| await keepTryingAuctionUntilWinBypassCaching( |
| test, uuid, interestGroupOverrides); |
| |
| // Now see that subscribing only to 1 provides only the click. |
| interestGroupOverrides = { |
| name: uuid, |
| viewAndClickCountsProviders: [VIEW_CLICK_PROVIDER1], |
| biddingLogicURL: createBiddingScriptURL({ |
| generateBid: ` |
| if (browserSignals.clickCounts.pastHour < 1 || |
| browserSignals.viewCounts.pastHour !== 0) { |
| throw JSON.stringify(browserSignals); |
| } |
| ` |
| }) |
| }; |
| |
| await keepTryingAuctionUntilWinBypassCaching( |
| test, uuid, interestGroupOverrides); |
| |
| // Now subscribe to both. |
| interestGroupOverrides = { |
| name: uuid, |
| viewAndClickCountsProviders: [VIEW_CLICK_PROVIDER1, VIEW_CLICK_PROVIDER2], |
| biddingLogicURL: createBiddingScriptURL({ |
| generateBid: ` |
| if (browserSignals.clickCounts.pastHour < 1 || |
| browserSignals.viewCounts.pastHour < 2) { |
| throw JSON.stringify(browserSignals); |
| } |
| ` |
| }) |
| }; |
| |
| await keepTryingAuctionUntilWinBypassCaching( |
| test, uuid, interestGroupOverrides); |
| }, 'browserSignals for clickiness --- viewAndClickCountsProviders works.'); |