diff options
Diffstat (limited to '')
12 files changed, 1068 insertions, 23 deletions
diff --git a/testing/web-platform/tests/fledge/tentative/TODO b/testing/web-platform/tests/fledge/tentative/TODO index 6fd378c035..8760e59d21 100644 --- a/testing/web-platform/tests/fledge/tentative/TODO +++ b/testing/web-platform/tests/fledge/tentative/TODO @@ -79,7 +79,13 @@ Need tests for (likely not a complete list): origins, and between generateBid() and reportWin(). * Test Content-Type headers allowed in responess for script/wasm/JSON fetches. * Test WASM support, updating createBiddingWasmHelperURL(). - +* Remaining interest group updates. + * Check that an update with one valid field and one invalid one fails. + * Test that an update works if owner and/or name match those in the interest group. + * Test updating the update URL and bidding script URL so they are all the same origin (requires updating test fixture to handle multiple updates). + * Test when Ads is null. + * Test updating a cross origin interest group. + * Test fields that are updatable but do not make it to 'generateBid'. If possible: * Aggregate reporting. * Join/leave permission delegation via .well-known files diff --git a/testing/web-platform/tests/fledge/tentative/auction-config-passed-to-worklets.https.window.js b/testing/web-platform/tests/fledge/tentative/auction-config-passed-to-worklets.https.window.js index 9b12d077ba..7780957739 100644 --- a/testing/web-platform/tests/fledge/tentative/auction-config-passed-to-worklets.https.window.js +++ b/testing/web-platform/tests/fledge/tentative/auction-config-passed-to-worklets.https.window.js @@ -81,6 +81,18 @@ makeTest({ }); makeTest({ + name: 'AuctionConfig.deprecatedRenderURLReplacements with brackets.', + fieldName: 'deprecatedRenderURLReplacements', + fieldValue: {'${EXAMPLE_MACRO}': 'SSP'}, +}); + +makeTest({ + name: 'AuctionConfig.deprecatedRenderURLReplacements with percents.', + fieldName: 'deprecatedRenderURLReplacements', + fieldValue: {'%%EXAMPLE_MACRO%%': 'SSP'}, +}); + +makeTest({ name: 'AuctionConfig.seller is URL.', fieldName: 'seller', fieldValue: OTHER_ORIGIN1, diff --git a/testing/web-platform/tests/fledge/tentative/auction-config.https.window.js b/testing/web-platform/tests/fledge/tentative/auction-config.https.window.js index 5fa4fa252f..057b4d7f78 100644 --- a/testing/web-platform/tests/fledge/tentative/auction-config.https.window.js +++ b/testing/web-platform/tests/fledge/tentative/auction-config.https.window.js @@ -12,7 +12,10 @@ // META: variant=?31-35 // META: variant=?36-40 // META: variant=?40-45 -// META: variant=?46-last +// META: variant=?46-50 +// META: variant=?51-55 +// META: variant=?56-60 +// META: variant=?61-last "use strict;" @@ -110,6 +113,62 @@ const EXPECT_PROMISE_ERROR = auctionResult => { } makeTest({ + name: 'deprecatedRenderURLReplacements without end bracket is invalid.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'${No_End_Bracket': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements without percents and brackets.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'No_Wrapper': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements without dollar sign.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'{No_Dollar_Sign}': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements without start bracket is invalid.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'$No_Start_Bracket}': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements mix and match is invalid.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'${Bracket_And_Percent%%': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements missing start percent is invalid.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'%Missing_Start_Percents%%': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements single percents is invalid.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'%Single_Percents%': 'SSP'}} +}); + +makeTest({ + name: 'deprecatedRenderURLReplacements without end percents is invalid.', + expect: EXPECT_PROMISE_ERROR, + expectPromiseError: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {deprecatedRenderURLReplacements: {'%%No_End_Percents': 'SSP'}} +}); + +makeTest({ name: 'no buyers => no winners', expect: EXPECT_NO_WINNER, auctionConfigOverrides: {interestGroupBuyers: []}, @@ -445,6 +504,60 @@ makeTest({ {width: '200furlongs', height: '200'}]} }); +makeTest({ + name: 'sellerRealTimeReportingConfig has default local reporting type', + expect: EXPECT_WINNER, + auctionConfigOverrides: {sellerRealTimeReportingConfig: + {type: 'default-local-reporting'}} +}); + +makeTest({ + name: 'sellerRealTimeReportingConfig has no type', + expect: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {sellerRealTimeReportingConfig: + {notType: 'default-local-reporting'}} +}); + +makeTest({ + name: 'sellerRealTimeReportingConfig has unknown type', + expect: EXPECT_WINNER, + auctionConfigOverrides: {sellerRealTimeReportingConfig: {type: 'unknown type'}} +}); + +makeTest({ + name: 'perBuyerRealTimeReportingConfig', + expect: EXPECT_WINNER, + auctionConfigOverrides: {perBuyerRealTimeReportingConfig: + {"https://example.com": {type: 'default-local-reporting'}}} +}); + +makeTest({ + name: 'perBuyerRealTimeReportingConfig has no entry', + expect: EXPECT_WINNER, + auctionConfigOverrides: {perBuyerRealTimeReportingConfig: {}} +}); + +makeTest({ + name: 'perBuyerRealTimeReportingConfig has invalid buyer', + expect: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {perBuyerRealTimeReportingConfig: + {"http://example.com": {type: 'default-local-reporting'}}} +}); + +makeTest({ + name: 'perBuyerRealTimeReportingConfig has no type', + expect: EXPECT_EXCEPTION(TypeError), + auctionConfigOverrides: {perBuyerRealTimeReportingConfig: + {"https://example.com": {notType: 'default-local-reporting'}}} +}); + +makeTest({ + name: 'perBuyerRealTimeReportingConfig has unknown type', + expect: EXPECT_WINNER, + auctionConfigOverrides: {perBuyerRealTimeReportingConfig: + {"https://example.com": {type: 'unknown type'}}} +}); + subsetTest(promise_test, async test => { const uuid = generateUuid(test); diff --git a/testing/web-platform/tests/fledge/tentative/component-ads.https.window.js b/testing/web-platform/tests/fledge/tentative/component-ads.https.window.js index 6b22585d57..8493025429 100644 --- a/testing/web-platform/tests/fledge/tentative/component-ads.https.window.js +++ b/testing/web-platform/tests/fledge/tentative/component-ads.https.window.js @@ -44,13 +44,25 @@ function createComponentAdRenderURL(uuid, id) { // // If "adMetadata" is true, metadata is added to each component ad. Only integer metadata // is used, relying on renderURL tests to cover other types of renderURL metadata. +// +// If "deprecatedRenderURLReplacements" is passed, the matches and replacements will be +// used in the trackingURLs and the object will be passed into the auctionConfig, to +// replace matching macros within the renderURLs. async function runComponentAdLoadingTest(test, uuid, numComponentAdsInInterestGroup, - componentAdsInBid, componentAdsToLoad, - adMetadata = false) { + componentAdsInBid, componentAdsToLoad, + adMetadata = false, deprecatedRenderURLReplacements = null) { let interestGroupAdComponents = []; + // These are used within the URLs for deprecatedRenderURLReplacement tests. + const renderURLReplacementsStrings = createStringBeforeAndAfterReplacements(deprecatedRenderURLReplacements); + const beforeReplacementsString= renderURLReplacementsStrings.beforeReplacements; + const afterReplacementsString = renderURLReplacementsStrings.afterReplacements; + for (let i = 0; i < numComponentAdsInInterestGroup; ++i) { - const componentRenderURL = createComponentAdRenderURL(uuid, i); - let adComponent = {renderURL: componentRenderURL}; + let componentRenderURL = createComponentAdRenderURL(uuid, i); + if (deprecatedRenderURLReplacements !== null) { + componentRenderURL = createTrackerURL(window.location.origin, uuid, 'track_get', beforeReplacementsString); + } + let adComponent = { renderURL: componentRenderURL }; if (adMetadata) adComponent.metadata = i; interestGroupAdComponents.push(adComponent); @@ -74,7 +86,7 @@ async function runComponentAdLoadingTest(test, uuid, numComponentAdsInInterestGr eventData: status, destination: ["buyer"]});`); - let bid = {bid:1, render: renderURL}; + let bid = {bid:1, render:renderURL}; if (componentAdsInBid) { bid.adComponents = []; for (let index of componentAdsInBid) { @@ -89,8 +101,13 @@ async function runComponentAdLoadingTest(test, uuid, numComponentAdsInInterestGr // to "expectedTrackerURLs". if (componentAdsToLoad && bid.adComponents) { for (let index of componentAdsToLoad) { + let expectedURL = createComponentAdTrackerURL(uuid, componentAdsInBid[index]); + if (deprecatedRenderURLReplacements != null) { + expectedURL = createTrackerURL(window.location.origin, uuid, 'track_get', + afterReplacementsString); + } if (index < componentAdsInBid.length) - expectedTrackerURLs.push(createComponentAdTrackerURL(uuid, componentAdsInBid[index])); + expectedTrackerURLs.push(expectedURL); } } @@ -127,11 +144,13 @@ async function runComponentAdLoadingTest(test, uuid, numComponentAdsInInterestGr test, uuid, {decisionLogicURL: createDecisionScriptURL( uuid, - { scoreAd: + { scoreAd: `if (JSON.stringify(browserSignals.adComponents) !== '${JSON.stringify(bid.adComponents)}') { throw "Unexpected adComponents: " + JSON.stringify(browserSignals.adComponents); - }`})}); + }`}), + deprecatedRenderURLReplacements: deprecatedRenderURLReplacements + }); } await waitForObservedRequests(uuid, expectedTrackerURLs); @@ -447,3 +466,27 @@ subsetTest(promise_test, async test => { }, 'Reports not sent from component ad.'); + +subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + await runComponentAdLoadingTest(test, uuid, /*numComponentAdsInInterestGroup=*/1, + /*componentAdsInBid=*/[0], /*componentAdsToLoad=*/[0], false, { '%%EXAMPLE-MACRO%%': 'SSP' }); +}, 'component ad with render url replacements with percents.'); + +subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + await runComponentAdLoadingTest(test, uuid, /*numComponentAdsInInterestGroup=*/1, + /*componentAdsInBid=*/[0], /*componentAdsToLoad=*/[0], false, { '${EXAMPLE-MACRO}': 'SSP' }); +}, 'component ad with render url replacements with brackets.'); + +subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + await runComponentAdLoadingTest(test, uuid, /*numComponentAdsInInterestGroup=*/1, + /*componentAdsInBid=*/[0], /*componentAdsToLoad=*/[0], false, { '${EXAMPLE-MACRO-1}': 'SSP-1', '%%EXAMPLE-MACRO-2%%': 'SSP-2' }); +}, 'component ad with render url replacements with multiple replacements.'); + +subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + await runComponentAdLoadingTest(test, uuid, /*numComponentAdsInInterestGroup=*/3, + /*componentAdsInBid=*/[0,1,2], /*componentAdsToLoad=*/[0,1,2], false, { '${EXAMPLE-MACRO-1}': 'SSP-1', '%%EXAMPLE-MACRO-2%%': 'SSP-2' }); +}, 'component ad with render url replacements with multiple replacements, and multiple component ads.'); diff --git a/testing/web-platform/tests/fledge/tentative/component-auction.https.window.js b/testing/web-platform/tests/fledge/tentative/component-auction.https.window.js index 015c20a5c2..bf804e6857 100644 --- a/testing/web-platform/tests/fledge/tentative/component-auction.https.window.js +++ b/testing/web-platform/tests/fledge/tentative/component-auction.https.window.js @@ -11,18 +11,21 @@ "use strict"; // Creates an AuctionConfig with a single component auction. -function createComponentAuctionConfig(uuid) { +function createComponentAuctionConfig(uuid, auctionConfigOverrides = {}, + deprecatedRenderURLReplacements = {}) { let componentAuctionConfig = { seller: window.location.origin, decisionLogicURL: createDecisionScriptURL(uuid), - interestGroupBuyers: [window.location.origin] + interestGroupBuyers: [window.location.origin], + deprecatedRenderURLReplacements: deprecatedRenderURLReplacements }; return { seller: window.location.origin, decisionLogicURL: createDecisionScriptURL(uuid), interestGroupBuyers: [], - componentAuctions: [componentAuctionConfig] + componentAuctions: [componentAuctionConfig], + ...auctionConfigOverrides }; } @@ -717,3 +720,118 @@ subsetTest(promise_test, async test => { uuid, [bidderReportURL1, seller1ReportURL, bidderReportURL2, seller2ReportURL]); }, `Component auction prevWinsMs and numBids updating in one component seller's auction, read in another's.`); + + +const makeDeprecatedRenderURLReplacementTest = ({ + name, + deprecatedRenderURLReplacements, +}) => { + subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + + let bidderReportURL = createBidderReportURL(uuid); + let componentSellerReportURL = createSellerReportURL(uuid, /*id=*/"component"); + let topLevelSellerReportURL = createSellerReportURL(uuid, /*id=*/"top"); + + // These are used within the URLs for deprecatedRenderURLReplacement tests. + const renderURLReplacementsStrings = createStringBeforeAndAfterReplacements(deprecatedRenderURLReplacements); + const beforeReplacementsString = renderURLReplacementsStrings.beforeReplacements; + const afterReplacementsString = renderURLReplacementsStrings.afterReplacements; + const renderURLBeforeReplacements = createTrackerURL(window.location.origin, uuid, 'track_get', beforeReplacementsString); + const renderURLAfterReplacements = createTrackerURL(window.location.origin, uuid, 'track_get', afterReplacementsString); + + await joinInterestGroup( + test, uuid, + { + ads: [{ renderURL: renderURLBeforeReplacements }], + biddingLogicURL: createBiddingScriptURL( + { + allowComponentAuction: true, + bid: 5, + reportWin: + `if (browserSignals.bid !== 5) + throw "Unexpected bid: " + browserSignals.bid; + sendReportTo("${bidderReportURL}");` + }) + }); + + let auctionConfig = createComponentAuctionConfig(uuid, {}, deprecatedRenderURLReplacements); + + auctionConfig.componentAuctions[0].decisionLogicURL = + createDecisionScriptURL( + uuid, + { + scoreAd: + `if (bid !== 5) + throw "Unexpected component bid: " + bid`, + reportResult: + `if (browserSignals.bid !== 5) + throw "Unexpected component bid: " + browserSignals.bid; + if (browserSignals.modifiedBid !== undefined) + throw "Unexpected component modifiedBid: " + browserSignals.modifiedBid; + sendReportTo("${componentSellerReportURL}");` + }); + + auctionConfig.decisionLogicURL = + createDecisionScriptURL( + uuid, + { + scoreAd: + `if (bid !== 5) + throw "Unexpected top-level bid: " + bid`, + reportResult: + `if (browserSignals.bid !== 5) + throw "Unexpected top-level bid: " + browserSignals.bid; + if (browserSignals.modifiedBid !== undefined) + throw "Unexpected top-level modifiedBid: " + browserSignals.modifiedBid; + sendReportTo("${topLevelSellerReportURL}");` + }); + + await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfig); + await waitForObservedRequests( + uuid, + [bidderReportURL, componentSellerReportURL, topLevelSellerReportURL, renderURLAfterReplacements]); + }, name); +}; + +makeDeprecatedRenderURLReplacementTest({ + name: 'Replacements with brackets.', + deprecatedRenderURLReplacements: { '${EXAMPLE-MACRO}': 'SSP' } +}); + +makeDeprecatedRenderURLReplacementTest({ + name: 'Replacements with percents.', + deprecatedRenderURLReplacements: { '%%EXAMPLE-MACRO%%': 'SSP' } +}); + +makeDeprecatedRenderURLReplacementTest({ + name: 'Replacements with multiple replacements.', + deprecatedRenderURLReplacements: { '${EXAMPLE-MACRO1}': 'SSP1', '%%EXAMPLE-MACRO2%%': 'SSP2' } +}); + +subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + let deprecatedRenderURLReplacements = { '${EXAMPLE-MACRO1}': 'SSP1', '%%EXAMPLE-MACRO2%%': 'SSP2' }; + const renderURLReplacementsStrings = createStringBeforeAndAfterReplacements(deprecatedRenderURLReplacements); + let beforeReplacementsString = renderURLReplacementsStrings.beforeReplacements; + + await joinInterestGroup( + test, uuid, + { + ads: [{ renderURL: createTrackerURL(window.location.origin, uuid, 'track_get', beforeReplacementsString) }], + biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) + }); + let auctionConfigOverride = {deprecatedRenderURLReplacements: deprecatedRenderURLReplacements } + let auctionConfig = createComponentAuctionConfig(uuid,/*auctionConfigOverride=*/auctionConfigOverride, + /*deprecatedRenderURLReplacements=*/deprecatedRenderURLReplacements); + + auctionConfig.componentAuctions[0].decisionLogicURL = createDecisionScriptURL(uuid); + + try { + await runBasicFledgeAuction(test, uuid, auctionConfig); + } catch (exception) { + assert_true(exception instanceof TypeError, "did not get expected error: " + exception); + return; + } + throw 'Exception unexpectedly not thrown.' +}, "deprecatedRenderURLReplacements cause error if passed in top level auction and component auction."); diff --git a/testing/web-platform/tests/fledge/tentative/deprecated-render-url-replacements.https.window.js b/testing/web-platform/tests/fledge/tentative/deprecated-render-url-replacements.https.window.js new file mode 100644 index 0000000000..4f8bc1cc7f --- /dev/null +++ b/testing/web-platform/tests/fledge/tentative/deprecated-render-url-replacements.https.window.js @@ -0,0 +1,196 @@ +// META: script=/resources/testdriver.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-5 +// META: variant=?6-10 +// META: variant=?11-15 +// META: variant=?16-last + + +"use strict;" + +// This test ensures proper handling of deprecatedRenderURLReplacements within auctionConfigOverrides. +// It validates that these replacements are correctly applied to the winning bid's renderURL by +// injecting a URL with matching macros into an interest group and ensuring that a new url with +// the replacements in it, is tracked and observed. +const makeTest = ({ + // Test name + name, + // Overrides to the interest group. + interestGroupOverrides = {}, + // Overrides to the auction config. + auctionConfigOverrides = {}, + // This is what goes into the renderURL and is expected to be replaced. + beforeReplacements, + // This is what's expected when 'beforeReplacements' is replaced. + afterReplacements, +}) => { + subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + let urlBeforeReplacements = createTrackerURL(window.location.origin, uuid, 'track_get', beforeReplacements); + let urlAfterReplacements = createTrackerURL(window.location.origin, uuid, 'track_get', afterReplacements); + interestGroupOverrides.ads = [{ renderURL: urlBeforeReplacements }]; + await joinInterestGroup(test, uuid, interestGroupOverrides); + + await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfigOverrides); + await waitForObservedRequests( + uuid, + [urlAfterReplacements, createSellerReportURL(uuid), createBidderReportURL(uuid)]); + }, name); +}; + +makeTest({ + name: 'Replacements with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${EXAMPLE-MACRO}': 'SSP' } + }, + beforeReplacements: "${EXAMPLE-MACRO}", + afterReplacements: 'SSP', + +}); + +makeTest({ + name: 'Replacements with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%EXAMPLE-MACRO%%': 'SSP' } + }, + beforeReplacements: "%%EXAMPLE-MACRO%%", + afterReplacements: 'SSP', +}); + +makeTest({ + name: 'Multiple replacements within a URL.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${EXAMPLE-MACRO1}': 'SSP1', '%%EXAMPLE-MACRO2%%': 'SSP2' } + }, + beforeReplacements: "${EXAMPLE-MACRO1}/%%EXAMPLE-MACRO2%%", + afterReplacements: 'SSP1/SSP2', +}); + +makeTest({ + name: 'Recursive and reduce size with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${1}': '1' } + }, + beforeReplacements: "${${${1}}}", + afterReplacements: "${${1}}" +}); + +makeTest({ + name: 'Recursive and increase size with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${1}': '${${1}}' } + }, + beforeReplacements: "${1}", + afterReplacements: "${${1}}" +}); + +makeTest({ + name: 'Replacements use a single pass with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${1}': '${2}', '${2}': '${1}' } + }, + beforeReplacements: "${1}${2}", + afterReplacements: "${2}${1}" +}); + +makeTest({ + name: 'Multiple instances of same substitution string with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${1}': '${2}' } + }, + beforeReplacements: "{${1}${1}}", + afterReplacements: "{${2}${2}}" +}); + +makeTest({ + name: 'Mismatched replacement with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${2}': '${1}' } + }, + beforeReplacements: "${1}", + afterReplacements: "${1}" +}); + +makeTest({ + name: 'Recursive and reduce size with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%1%%': '1' } + }, + beforeReplacements: "%%%%1%%%%", + afterReplacements: "%%1%%" +}); + +makeTest({ + name: 'Recursive and increase size with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%1%%': '%%%%1%%%%' } + }, + beforeReplacements: "%%1%%", + afterReplacements: "%%%%1%%%%" +}); + +makeTest({ + name: 'Replacements use a single pass with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%1%%': '%%2%%', '%%2%%': '%%1%%' } + }, + beforeReplacements: "%%1%%%%2%%", + afterReplacements: "%%2%%%%1%%" +}); + +makeTest({ + name: 'Multiple instances of same substitution string with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%1%%': '%%2%%' } + }, + beforeReplacements: "%%1%%%%1%%", + afterReplacements: "%%2%%%%2%%" +}); + +makeTest({ + name: 'Mismatched replacement with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%2%%': '%%1%%' } + }, + beforeReplacements: "%%1%%", + afterReplacements: "%%1%%" +}); + +makeTest({ + name: 'Case sensativity.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%foo%%': '%%bar%%' } + }, + beforeReplacements: "%%FOO%%%%foo%%", + afterReplacements: "%%FOO%%%%bar%%" +}); + +makeTest({ + name: 'Super macro, a macro with a macro inside it basically, with percents.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '%%%%foo%%%%': 'foo' } + }, + beforeReplacements: "%%%%foo%%%%", + afterReplacements: "foo" +}); + +makeTest({ + name: 'Super macro, with brackets.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${${foo}}': 'foo' } + }, + beforeReplacements: "${${foo}}", + afterReplacements: "foo" +}); + +makeTest({ + name: 'Super macro, with both.', + auctionConfigOverrides: { + deprecatedRenderURLReplacements: { '${%%foo%%}': 'foo', '%%${bar}%%':'bar' } + }, + beforeReplacements: "${%%foo%%}%%${bar}%%", + afterReplacements: "foobar" +}); diff --git a/testing/web-platform/tests/fledge/tentative/interest-group-update.https.window.js b/testing/web-platform/tests/fledge/tentative/interest-group-update.https.window.js new file mode 100644 index 0000000000..59b3736b09 --- /dev/null +++ b/testing/web-platform/tests/fledge/tentative/interest-group-update.https.window.js @@ -0,0 +1,406 @@ +// META: script=/resources/testdriver.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-9 +// META: variant=?10-14 +// META: variant=?15-19 +// META: variant=?20-last + +"use strict;" + +// This test repeatedly runs auctions to verify an update. A modified bidding script +// continuously throws errors until it detects the expected change in the interest group +// field. This update then stops the auction cycle. +const makeTestForUpdate = ({ + // Test name + name, + // fieldname that is getting updated + interestGroupFieldName, + // This is used to check if update has happened. + expectedValue, + // This is used to create the update response, by default it will always send + // back the `expectedValue`. Extra steps to make a deep copy. + responseOverride = expectedValue, + // Overrides to the interest group. + interestGroupOverrides = {}, + // Overrides to the auction config. + auctionConfigOverrides = {}, +}) => { + subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + extraBiddingLogic = ``; + + let replacePlaceholders = (ads) => ads.forEach(element => { + element.renderURL = element.renderURL.replace(`UUID-PLACEHOLDER`, uuid); + }); + + // Testing 'ads' requires some additional setup due to it's reliance + // on createRenderURL, specifically the bidding script used checks to make + // sure the `uuid` is the correct one for the test. We use a renderURL + // with a placeholder 'UUID-PLACEHOLDER' and make sure to replace it + // before moving on to the test. + if (interestGroupFieldName === `ads`) { + if (interestGroupFieldName in interestGroupOverrides) { + replacePlaceholders(interestGroupOverrides[interestGroupFieldName]); + } + replacePlaceholders(responseOverride); + replacePlaceholders(expectedValue); + } + // When checking the render URL, both the deprecated 'renderUrl' and the updated 'renderURL' might exist + // in the interest group simultaneously, so this test deletes the 'renderUrl' to ensure a + // clean comparison with deepEquals. + if (interestGroupFieldName === `ads` || interestGroupFieldName === `adComponents`) { + extraBiddingLogic = ` + interestGroup.${interestGroupFieldName}.forEach(element => { + delete element.renderUrl; + });` + } + + let expectedValueJSON = JSON.stringify(expectedValue); + // When the update has not yet been seen, throw an error which will cause the + // auction not to have a result. + interestGroupOverrides.biddingLogicURL = createBiddingScriptURL({ + generateBid: ` + ${extraBiddingLogic} + if (!deepEquals(interestGroup.${interestGroupFieldName}, ${expectedValueJSON})) { + throw '${interestGroupFieldName} is ' + + JSON.stringify(interestGroup.${interestGroupFieldName}) + + ' instead of ' + '${expectedValueJSON}'; + }` + }); + + let responseBody = {}; + responseBody[interestGroupFieldName] = responseOverride; + let updateParams = { + body: JSON.stringify(responseBody), + uuid: uuid + }; + interestGroupOverrides.updateURL = createUpdateURL(updateParams); + await joinInterestGroup(test, uuid, interestGroupOverrides); + + // Run an auction until there's a winner, which means update occurred. + let auctionResult = await runBasicFledgeAuction(test, uuid, auctionConfigOverrides); + expectNoWinner(auctionResult); + while (!auctionResult) { + auctionResult = await runBasicFledgeAuction(test, uuid, auctionConfigOverrides); + } + }, name); +}; + +// In order to test the update process does not update certain fields, this test uses two interest groups: + +// * `failedUpdateGroup`: Receives an invalid update, and will continue to throw errors until the update +// occurs (which shouldn't happen). This group will have a high bid to ensure if +// there was ever a tie, it would win. +// * `successUpdateGroup`: A hard-coded interest group that receives a update and will signal the change +// by throwing an error. + +// By tracking render URLs, this test guarantees that only the URL associated with the correct update +// (`goodUpdateRenderURL`) is used, and the incorrect URL (`badUpdateRenderURL`) isn't. The test runs +// auctions repeatedly until the update in `successUpdateGroup` stops an auction from producing a winner. +// It then will run one final auction. If there's still no winner, it can infer that `failedUpdateGroup` +// would have received the update if it were propagating correctly. + +// If there was a bug in the implementation, a possible case can occur and manifest as a flaky test. +// In this scenerio with the current structure of the Protected Audience API, the `successUpdateGroup` +// updates, and so does the `failedUpdateGroup`, but the `failedUpdateGroup` update happens significantly +// after the `successUpdateGroup`'s update. In an effort to combat this, after the while loop we run +// another auction to ensure there is no winner (both cases should throw), but depending how slow the +// update takes, this flaky issue still can **possibly** occur. +const makeTestForNoUpdate = ({ + // Test name + name, + // fieldname that is should not be getting updated + interestGroupFieldName, + // this is used to create the update response and check if it did not happen. + responseOverride, + // Overrides to the auction config. + auctionConfigOverrides = {}, + // Overrides to the interest group. + failedUpdateGroup = {}, +}) => { + subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + // successUpdateGroup + + // These are used in `successUpdateGroup` in order to get a proper update. + let successUpdateGroup = {}; + let successUpdateField = `userBiddingSignals`; + let successUpdateFieldExpectedValue = { 'test': 20 }; + + const goodUpdateRenderURL = createTrackerURL(window.location.origin, uuid, 'track_get', 'good_update'); + successUpdateGroup.ads = [{ 'renderURL': goodUpdateRenderURL }]; + successUpdateGroup.biddingLogicURL = createBiddingScriptURL({ + generateBid: ` + if (deepEquals(interestGroup.${successUpdateField}, ${JSON.stringify(successUpdateFieldExpectedValue)})){ + throw '${successUpdateField} has updated and is ' + + '${JSON.stringify(successUpdateFieldExpectedValue)}.' + }`, + bid: 5 + }); + + let successResponseBody = {}; + successResponseBody[successUpdateField] = successUpdateFieldExpectedValue; + let successUpdateParams = { + body: JSON.stringify(successResponseBody), + uuid: uuid + }; + successUpdateGroup.updateURL = createUpdateURL(successUpdateParams); + await joinInterestGroup(test, uuid, successUpdateGroup); + ///////////////////////// successUpdateGroup + + // failedUpdateGroup + const badUpdateRenderURL = createTrackerURL(window.location.origin, uuid, `track_get`, `bad_update`); + // Name needed so we don't have two IGs with same name. + failedUpdateGroup.name = failedUpdateGroup.name ? failedUpdateGroup.name : `IG name` + failedUpdateGroup.ads = [{ 'renderURL': badUpdateRenderURL }]; + failedUpdateGroup.biddingLogicURL = createBiddingScriptURL({ + generateBid: ` + if (!deepEquals(interestGroup.${interestGroupFieldName}, ${JSON.stringify(responseOverride)})){ + throw '${interestGroupFieldName} is as expected: '+ + JSON.stringify(interestGroup.${interestGroupFieldName}); + }`, + bid: 1000 + }); + let failedResponseBody = {}; + failedResponseBody[interestGroupFieldName] = responseOverride; + + let failedUpdateParams = { + body: JSON.stringify(failedResponseBody), + uuid: uuid + }; + + failedUpdateGroup.updateURL = createUpdateURL(failedUpdateParams); + await joinInterestGroup(test, uuid, failedUpdateGroup); + ///////////////////////// failedUpdateGroup + + // First result should be not be null, `successUpdateGroup` throws when update is detected so until then, + // run and observe the requests to ensure only `goodUpdateRenderURL` is fetched. + let auctionResult = await runBasicFledgeTestExpectingWinner(test, uuid, auctionConfigOverrides); + while (auctionResult) { + createAndNavigateFencedFrame(test, auctionResult); + await waitForObservedRequests( + uuid, + [goodUpdateRenderURL, createSellerReportURL(uuid)]); + await fetch(createCleanupURL(uuid)); + auctionResult = await runBasicFledgeAuction(test, uuid, auctionConfigOverrides); + } + // Re-run to ensure null because: + // `successUpdateGroup` should be throwing since update occurred. + // `failedUpdateGroup` should be throwing since update did not occur. + await runBasicFledgeTestExpectingNoWinner(test, uuid, auctionConfigOverrides); + }, name); +}; + +// Helper to eliminate rewriting a long call to createRenderURL(). +// Only thing to change would be signalParams to differentiate between URLs. +const createTempRenderURL = (signalsParams = null) => { + return createRenderURL(/*uuid=*/`UUID-PLACEHOLDER`,/*script=*/ null,/*signalParams=*/ signalsParams,/*origin=*/ null); +}; + +makeTestForUpdate({ + name: 'userBiddingSignals update overwrites everything in the field.', + interestGroupFieldName: 'userBiddingSignals', + expectedValue: { 'test': 20 }, + interestGroupOverrides: { + userBiddingSignals: { 'test': 10, 'extra_value': true }, + } +}); + +makeTestForUpdate({ + name: 'userBiddingSignals updated multi-type', + interestGroupFieldName: 'userBiddingSignals', + expectedValue: { 'test': 20, 5: [1, [false, false, true], 3, 'Hello'] }, + interestGroupOverrides: { + userBiddingSignals: { 'test': 10 }, + } +}); + +makeTestForUpdate({ + name: 'userBiddingSignals updated to non object', + interestGroupFieldName: 'userBiddingSignals', + expectedValue: 5, + interestGroupOverrides: { + userBiddingSignals: { 'test': 10 }, + } +}); + +makeTestForUpdate({ + name: 'userBiddingSignals updated to null', + interestGroupFieldName: 'userBiddingSignals', + expectedValue: null, + interestGroupOverrides: { + userBiddingSignals: { 'test': 10 }, + } +}); + +makeTestForUpdate({ + name: 'trustedBiddingSignalsKeys updated correctly', + interestGroupFieldName: 'trustedBiddingSignalsKeys', + expectedValue: ['new_key', 'old_key'], + interestGroupOverrides: { + trustedBiddingSignalsKeys: ['old_key'], + } +}); + +makeTestForUpdate({ + name: 'trustedBiddingSignalsKeys updated to empty array.', + interestGroupFieldName: 'trustedBiddingSignalsKeys', + expectedValue: [], + interestGroupOverrides: { + trustedBiddingSignalsKeys: ['old_key'], + } +}); + + +makeTestForUpdate({ + name: 'trustedBiddingSignalsSlotSizeMode updated to slot-size', + interestGroupFieldName: 'trustedBiddingSignalsSlotSizeMode', + expectedValue: 'slot-size', + interestGroupOverrides: { + trustedBiddingSignalsKeys: ['key'], + trustedBiddingSignalsSlotSizeMode: 'none', + } +}); + +makeTestForUpdate({ + name: 'trustedBiddingSignalsSlotSizeMode updated to all-slots-requested-sizes', + interestGroupFieldName: 'trustedBiddingSignalsSlotSizeMode', + expectedValue: 'all-slots-requested-sizes', + interestGroupOverrides: { + trustedBiddingSignalsKeys: ['key'], + trustedBiddingSignalsSlotSizeMode: 'slot-size', + } +}); + +makeTestForUpdate({ + name: 'trustedBiddingSignalsSlotSizeMode updated to none', + interestGroupFieldName: 'trustedBiddingSignalsSlotSizeMode', + expectedValue: 'none', + interestGroupOverrides: { + trustedBiddingSignalsKeys: ['key'], + trustedBiddingSignalsSlotSizeMode: 'slot-size', + } +}); + +makeTestForUpdate({ + name: 'trustedBiddingSignalsSlotSizeMode updated to unknown, defaults to none', + interestGroupFieldName: 'trustedBiddingSignalsSlotSizeMode', + expectedValue: 'none', + responseOverride: 'unknown-type', + interestGroupOverrides: { + trustedBiddingSignalsKeys: ['key'], + trustedBiddingSignalsSlotSizeMode: 'slot-size', + } +}); + +makeTestForUpdate({ + name: 'ads updated from 2 ads to 1.', + interestGroupFieldName: 'ads', + expectedValue: [ + { renderURL: createTempRenderURL('new_url1'), metadata: 'test1-new' }, + ], + interestGroupOverrides: { + ads: [{ renderURL: createTempRenderURL() }, + { renderURL: createTempRenderURL() }] + } +}); + +makeTestForUpdate({ + name: 'ads updated from 1 ad to 2.', + interestGroupFieldName: 'ads', + expectedValue: [{ renderURL: createTempRenderURL('new_url1'), metadata: 'test1-new' }, + { renderURL: createTempRenderURL('new_url2'), metadata: 'test2-new' }], + interestGroupOverrides: { + ads: [{ renderURL: createTempRenderURL() }] + } +}); + +makeTestForUpdate({ + name: 'adComponents updated from 1 adComponent to 2.', + interestGroupFieldName: 'adComponents', + expectedValue: [{ renderURL: createTempRenderURL('new_url1'), metadata: 'test1-new' }, + { renderURL: createTempRenderURL('new_url2'), metadata: 'test2' }], + interestGroupOverrides: { + adComponents: [{ renderURL: createTempRenderURL(), metadata: 'test1' }] + }, +}); + +makeTestForUpdate({ + name: 'adComponents updated from 2 adComponents to 1.', + interestGroupFieldName: 'adComponents', + expectedValue: [{ renderURL: createTempRenderURL('new_url1'), metadata: 'test1-new' }], + interestGroupOverrides: { + adComponents: [{ renderURL: createTempRenderURL() }, + { renderURL: createTempRenderURL() }] + }, +}); + +makeTestForUpdate({ + name: 'executionMode updated to frozen context', + interestGroupFieldName: 'executionMode', + expectedValue: 'frozen-context', + interestGroupOverrides: { + executionMode: 'compatibility', + } +}); + +makeTestForUpdate({ + name: 'executionMode updated to compatibility', + interestGroupFieldName: 'executionMode', + expectedValue: 'compatibility', + interestGroupOverrides: { + executionMode: 'frozen-context', + } +}); + +makeTestForUpdate({ + name: 'executionMode updated to group by origin', + interestGroupFieldName: 'executionMode', + expectedValue: 'group-by-origin', + interestGroupOverrides: { + executionMode: 'compatibility', + } +}); + +makeTestForNoUpdate({ + name: 'executionMode updated with invalid input', + interestGroupFieldName: 'executionMode', + responseOverride: 'unknown-type', +}); + +makeTestForNoUpdate({ + name: 'owner cannot be updated.', + interestGroupFieldName: 'owner', + responseOverride: OTHER_ORIGIN1, + auctionConfigOverrides: { + interestGroupBuyers: [OTHER_ORIGIN1, window.location.origin] + } +}); + +makeTestForNoUpdate({ + name: 'name cannot be updated.', + interestGroupFieldName: 'name', + responseOverride: 'new_name', + failedUpdateGroup: { name: 'name2' }, +}); + +makeTestForNoUpdate({ + name: 'executionMode not updated when unknown type.', + interestGroupFieldName: 'executionMode', + responseOverride: 'unknown-type', + failedUpdateGroup: { executionMode: 'compatibility' }, +}); + +makeTestForNoUpdate({ + name: 'trustedBiddingSignalsKeys not updated when bad value.', + interestGroupFieldName: 'trustedBiddingSignalsKeys', + responseOverride: 5, + failedUpdateGroup: { + trustedBiddingSignalsKeys: ['key'], + }, +}); + diff --git a/testing/web-platform/tests/fledge/tentative/resources/fledge-util.sub.js b/testing/web-platform/tests/fledge/tentative/resources/fledge-util.sub.js index 7be02e34ff..a7d0f63830 100644 --- a/testing/web-platform/tests/fledge/tentative/resources/fledge-util.sub.js +++ b/testing/web-platform/tests/fledge/tentative/resources/fledge-util.sub.js @@ -77,6 +77,15 @@ function createDirectFromSellerSignalsURL(origin = window.location.origin) { return url.toString(); } +function createUpdateURL(params = {}) { + let origin = window.location.origin; + let url = new URL(`${origin}${RESOURCE_PATH}update-url.py`); + url.searchParams.append('body', params.body); + url.searchParams.append('uuid', params.uuid); + + return url.toString(); +} + // Generates a UUID and registers a cleanup method with the test fixture to // request a URL from the request tracking script that clears all data // associated with the generated uuid when requested. @@ -142,19 +151,21 @@ async function waitForObservedRequests(uuid, expectedRequests, filter) { trackedRequests = trackedRequests.filter(filter); } - // If expected number of requests have been observed, compare with list of - // all expected requests and exit. - if (trackedRequests.length >= expectedRequests.length) { - assert_array_equals(trackedRequests, expectedRequests); - break; - } - // If fewer than total number of expected requests have been observed, // compare what's been received so far, to have a greater chance to fail // rather than hang on error. for (const trackedRequest of trackedRequests) { assert_in_array(trackedRequest, expectedRequests); } + + // If expected number of requests have been observed, compare with list of + // all expected requests and exit. This check was previously before the for loop, + // but was swapped in order to avoid flakiness with failing tests and their + // respective *-expected.txt. + if (trackedRequests.length >= expectedRequests.length) { + assert_array_equals(trackedRequests, expectedRequests); + break; + } } } @@ -830,3 +841,21 @@ let additionalBidHelper = function() { fetchAdditionalBids: fetchAdditionalBids }; }(); + + +// DeprecatedRenderURLReplacements helper function. +// Returns an object containing sample strings both before and after the +// replacements in 'replacements' have been applied by +// deprecatedRenderURLReplacements. All substitution strings will appear +// only once in the output strings. +function createStringBeforeAndAfterReplacements(deprecatedRenderURLReplacements) { + let beforeReplacements = ''; + let afterReplacements = ''; + if(deprecatedRenderURLReplacements){ + for (const [match, replacement] of Object.entries(deprecatedRenderURLReplacements)) { + beforeReplacements += match + "/"; + afterReplacements += replacement + "/"; + } + } + return { beforeReplacements, afterReplacements }; +} diff --git a/testing/web-platform/tests/fledge/tentative/resources/trusted-bidding-signals.py b/testing/web-platform/tests/fledge/tentative/resources/trusted-bidding-signals.py index f9ca9031f1..955a7c0bdf 100644 --- a/testing/web-platform/tests/fledge/tentative/resources/trusted-bidding-signals.py +++ b/testing/web-platform/tests/fledge/tentative/resources/trusted-bidding-signals.py @@ -1,3 +1,4 @@ +import collections import json from urllib.parse import unquote_plus @@ -47,7 +48,8 @@ def main(request, response): response.status = (200, b"OK") # The JSON representation of this is used as the response body. This does - # not currently include a "perInterestGroupData" object. + # not currently include a "perInterestGroupData" object except for + # updateIfOlderThanMs. responseBody = {"keys": {}} # Set when certain special keys are observed, used in place of the JSON @@ -117,6 +119,22 @@ def main(request, response): if "data-version" in interestGroupNames: dataVersion = "4" + per_interest_group_data = collections.defaultdict(dict) + for name in interestGroupNames: + if name == "use-update-if-older-than-ms": + # One hour in milliseconds. + per_interest_group_data[name]["updateIfOlderThanMs"] = 3_600_000 + elif name == "use-update-if-older-than-ms-small": + # A value less than the minimum of 10 minutes. + per_interest_group_data[name]["updateIfOlderThanMs"] = 1 + elif name == "use-update-if-older-than-ms-zero": + per_interest_group_data[name]["updateIfOlderThanMs"] = 0 + elif name == "use-update-if-older-than-ms-negative": + per_interest_group_data[name]["updateIfOlderThanMs"] = -1 + + if per_interest_group_data: + responseBody["perInterestGroupData"] = dict(per_interest_group_data) + if contentType: response.headers.set("Content-Type", contentType) if adAuctionAllowed: diff --git a/testing/web-platform/tests/fledge/tentative/resources/update-url.py b/testing/web-platform/tests/fledge/tentative/resources/update-url.py new file mode 100644 index 0000000000..7de89e0f8f --- /dev/null +++ b/testing/web-platform/tests/fledge/tentative/resources/update-url.py @@ -0,0 +1,6 @@ +def main(request, response): + response.status = (200, b"OK") + response.headers.set(b"Ad-Auction-Allowed", b"true") + response.headers.set(b"Content-Type", b"application/json") + body = request.GET.first(b"body", None) + return body
\ No newline at end of file diff --git a/testing/web-platform/tests/fledge/tentative/score-ad-browser-signals.https.window.js b/testing/web-platform/tests/fledge/tentative/score-ad-browser-signals.https.window.js new file mode 100644 index 0000000000..f20412cfc7 --- /dev/null +++ b/testing/web-platform/tests/fledge/tentative/score-ad-browser-signals.https.window.js @@ -0,0 +1,57 @@ +// META: script=/resources/testdriver.js +// META: script=/common/utils.js +// META: script=resources/fledge-util.sub.js +// META: script=/common/subset-tests.js +// META: timeout=long + +"use strict;" + +// These tests focus on the browserSignals argument passed to scoreAd(). + +subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + + let biddingLogicURL = createBiddingScriptURL( + { + generateBid: + ` + return { + bid: 1, + render: { url: interestGroup.ads[0].renderURL, + width: '100sw', + height: '50px' } + }; + ` + }); + + let decisionLogicURL = createDecisionScriptURL(uuid, + { + scoreAd: + ` + if (!browserSignals.hasOwnProperty('renderSize')) { + throw 'Missing renderSize member in browserSignals.'; + } + if (browserSignals.renderSize.width !== '100sw' || + browserSignals.renderSize.height !== '50px') { + throw 'Incorrect renderSize width or height.'; + } + ` + } + ); + + await joinGroupAndRunBasicFledgeTestExpectingWinner( + test, + { + uuid: uuid, + interestGroupOverrides: { + name: uuid, + biddingLogicURL: biddingLogicURL, + ads: [{ renderURL: createRenderURL(uuid), sizeGroup: 'group1' }], + adSizes: { 'size1': { width: '100sw', height: '50px' } }, + sizeGroups: { 'group1': ['size1'] } + }, + auctionConfigOverrides: { + decisionLogicURL: decisionLogicURL + } + }); +}, 'ScoreAd browserSignals renderSize test.'); diff --git a/testing/web-platform/tests/fledge/tentative/trusted-bidding-signals.https.window.js b/testing/web-platform/tests/fledge/tentative/trusted-bidding-signals.https.window.js index d0b9a82086..905abf8381 100644 --- a/testing/web-platform/tests/fledge/tentative/trusted-bidding-signals.https.window.js +++ b/testing/web-platform/tests/fledge/tentative/trusted-bidding-signals.https.window.js @@ -17,7 +17,8 @@ // META: variant=?56-60 // META: variant=?61-65 // META: variant=?66-70 -// META: variant=?71-last +// META: variant=?71-75 +// META: variant=?76-last "use strict"; @@ -938,4 +939,44 @@ subsetTest(promise_test, async test => { ] ); runBasicFledgeTestExpectingWinner(test, uuid); -}, 'Trusted bidding signals splits the request if the combined URL length exceeds the limit of small value.');
\ No newline at end of file +}, 'Trusted bidding signals splits the request if the combined URL length exceeds the limit of small value.'); + +///////////////////////////////////////////////////////////////////////////// +// updateIfOlderThanMs tests +// +// NOTE: Due to the lack of mock time in wpt, these test just exercise the code +// paths and ensure that no crash occurs -- they don't otherwise verify +// behavior. +///////////////////////////////////////////////////////////////////////////// + +subsetTest(promise_test, async test => { + await runTrustedBiddingSignalsTest( + test, + 'true', + { name: 'use-update-if-older-than-ms', + trustedBiddingSignalsURL: TRUSTED_BIDDING_SIGNALS_URL }); +}, 'Trusted bidding signals response has updateIfOlderThanMs > 10 min.'); + +subsetTest(promise_test, async test => { + await runTrustedBiddingSignalsTest( + test, + 'true', + { name: 'use-update-if-older-than-ms-small', + trustedBiddingSignalsURL: TRUSTED_BIDDING_SIGNALS_URL }); +}, 'Trusted bidding signals response has updateIfOlderThanMs == 1 ms.'); + +subsetTest(promise_test, async test => { + await runTrustedBiddingSignalsTest( + test, + 'true', + { name: 'use-update-if-older-than-ms-zero', + trustedBiddingSignalsURL: TRUSTED_BIDDING_SIGNALS_URL }); +}, 'Trusted bidding signals response has updateIfOlderThanMs == 0 ms.'); + +subsetTest(promise_test, async test => { + await runTrustedBiddingSignalsTest( + test, + 'true', + { name: 'use-update-if-older-than-ms-negative', + trustedBiddingSignalsURL: TRUSTED_BIDDING_SIGNALS_URL }); +}, 'Trusted bidding signals response has updateIfOlderThanMs == -1 ms.'); |