diff --git a/testing/web-platform/tests/fledge/tentative/register-ad-beacon.https.sub.window.js b/testing/web-platform/tests/fledge/tentative/register-ad-beacon.https.sub.window.js new file mode 100644 index 000000000000..3df6b408a570 --- /dev/null +++ b/testing/web-platform/tests/fledge/tentative/register-ad-beacon.https.sub.window.js @@ -0,0 +1,321 @@ +// META: script=/resources/testdriver.js +// META: script=/common/utils.js +// META: script=resources/fledge-util.js +// META: timeout=long + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + null, + '', + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid)}, body: `], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "", + destination: ["seller"] + });`) + ); +}, 'Seller calls registerAdBeacon().'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + '', + // reportWin: + null, + `registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createBidderBeaconUrl(uuid)}, body: `], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "", + destination: ["buyer"] + });`) + ); +}, 'Buyer calls registerAdBeacon().'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + null, + '', + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid)}, body: body`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body", + destination: ["seller"] + });`) + ); +}, 'Seller calls registerAdBeacon(), beacon sent with body.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + '', + // reportWin: + null, + `registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createBidderBeaconUrl(uuid)}, body: body`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body", + destination: ["buyer"] + });`) + ); +}, 'Buyer calls registerAdBeacon(), beacon sent with body.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + null, + '', + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid)}, body: body1`, + `${createSellerBeaconUrl(uuid)}, body: body2`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body1", + destination: ["seller"] + }); + window.fence.reportEvent({ + eventType: "beacon", + eventData: "body2", + destination: ["seller"] + });`) + ); +}, 'Seller calls registerAdBeacon(). reportEvent() called twice.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + '', + // reportWin: + null, + `registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createBidderBeaconUrl(uuid)}, body: body1`, + `${createBidderBeaconUrl(uuid)}, body: body2`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body1", + destination: ["buyer"] + }); + window.fence.reportEvent({ + eventType: "beacon", + eventData: "body2", + destination: ["buyer"] + });`) + ); +}, 'Buyer calls registerAdBeacon(). reportEvent() called twice.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon1: '${createSellerBeaconUrl(uuid, '1')}', + beacon2: '${createSellerBeaconUrl(uuid, '2')}'});`, + // reportWin: + null, + '', + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid, '1')}, body: body1`, + `${createSellerBeaconUrl(uuid, '2')}, body: body2`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon1", + eventData: "body1", + destination: ["seller"] + }); + window.fence.reportEvent({ + eventType: "beacon2", + eventData: "body2", + destination: ["seller"] + });`) + ); +}, 'Seller calls registerAdBeacon() with multiple beacons.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + '', + // reportWin: + null, + `registerAdBeacon({beacon1: '${createBidderBeaconUrl(uuid, '1')}', + beacon2: '${createBidderBeaconUrl(uuid, '2')}'});`, + // expectedReportUrls: + [`${createBidderBeaconUrl(uuid, '1')}, body: body1`, + `${createBidderBeaconUrl(uuid, '2')}, body: body2`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon1", + eventData: "body1", + destination: ["buyer"] + }); + window.fence.reportEvent({ + eventType: "beacon2", + eventData: "body2", + destination: ["buyer"] + });`) + ); +}, 'Buyer calls registerAdBeacon() with multiple beacons.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + null, + `registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid)}, body: body`, + `${createBidderBeaconUrl(uuid)}, body: body`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body", + destination: ["seller","buyer"] + });`) + ); +}, 'Seller and buyer call registerAdBeacon() with shared reportEvent() call.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + null, + `registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid)}, body: body1`, + `${createBidderBeaconUrl(uuid)}, body: body2`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body1", + destination: ["seller"] + }); + window.fence.reportEvent({ + eventType: "beacon", + eventData: "body2", + destination: ["buyer"] + });`) + ); +}, 'Seller and buyer call registerAdBeacon() with separate reportEvent() calls.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + // Multiple registerAdBeacon() call should result in an exception, + // throwing away all beacons and other types of reports. + `sendReportTo('${createSellerReportUrl(uuid)}'); + registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'}); + registerAdBeacon({beacon1: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + 'sellerSignals === null', + `registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createBidderBeaconUrl(uuid)}, body: body`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body", + destination: ["seller","buyer"] + });`) + ); +}, 'Seller calls registerAdBeacon() multiple times.'); + +promise_test(async test => { + const uuid = generateUuid(test); + await runReportTest( + test, uuid, + // reportResult: + null, + `registerAdBeacon({beacon: '${createSellerBeaconUrl(uuid)}'});`, + // reportWin: + null, + // Multiple registerAdBeacon() call should result in an exception, + // throwing away all beacons and other types of reports. + `sendReportTo('${createBidderReportUrl(uuid)}'); + registerAdBeacon({beacon: '${createBidderBeaconUrl(uuid)}'}); + registerAdBeacon({beacon1: '${createBidderBeaconUrl(uuid)}'});`, + // expectedReportUrls: + [`${createSellerBeaconUrl(uuid)}, body: body`], + // renderUrlOverride: + createRenderUrl( + uuid, + `window.fence.reportEvent({ + eventType: "beacon", + eventData: "body", + destination: ["seller","buyer"] + });`) + ); +}, 'Buyer calls registerAdBeacon() multiple times.'); diff --git a/testing/web-platform/tests/fledge/tentative/resources/fenced-frame.sub.py b/testing/web-platform/tests/fledge/tentative/resources/fenced-frame.sub.py new file mode 100644 index 000000000000..c29bb6fecccf --- /dev/null +++ b/testing/web-platform/tests/fledge/tentative/resources/fenced-frame.sub.py @@ -0,0 +1,19 @@ +# Fenced frame HTML body. Generated by a Python file to avoid having quotes in +# the injected script escaped, which the test server does to *.html files. +def main(request, response): + response.status = (200, b"OK") + response.headers.set(b"Content-Type", b"text/html") + response.headers.set(b"Supports-Loading-Mode", b"fenced-frame") + + return """ + + + + + + + """ + + diff --git a/testing/web-platform/tests/fledge/tentative/resources/fenced_frame.sub.html b/testing/web-platform/tests/fledge/tentative/resources/fenced_frame.sub.html deleted file mode 100644 index eaca3f49fd15..000000000000 --- a/testing/web-platform/tests/fledge/tentative/resources/fenced_frame.sub.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/testing/web-platform/tests/fledge/tentative/resources/fenced_frame.sub.html.headers b/testing/web-platform/tests/fledge/tentative/resources/fenced_frame.sub.html.headers deleted file mode 100644 index bc74b5851b6c..000000000000 --- a/testing/web-platform/tests/fledge/tentative/resources/fenced_frame.sub.html.headers +++ /dev/null @@ -1,2 +0,0 @@ -Content-Type: text/html -Supports-Loading-Mode: fenced-frame diff --git a/testing/web-platform/tests/fledge/tentative/resources/fledge-util.js b/testing/web-platform/tests/fledge/tentative/resources/fledge-util.js index 9f95a59e43a3..6432752e075c 100644 --- a/testing/web-platform/tests/fledge/tentative/resources/fledge-util.js +++ b/testing/web-platform/tests/fledge/tentative/resources/fledge-util.js @@ -30,6 +30,17 @@ function createSellerReportUrl(uuid, id = '1') { `seller_report_${id}`); } +// Much like above ReportUrl methods, except designed for beacons, which +// are expected to be POSTs. +function createBidderBeaconUrl(uuid, id = '1') { + return createTrackerUrl(window.location.origin, uuid, `track_post`, + `bidder_beacon_${id}`); +} +function createSellerBeaconUrl(uuid, id = '1') { + return createTrackerUrl(window.location.origin, uuid, `track_post`, + `seller_beacon_${id}`); +} + // 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. @@ -44,10 +55,13 @@ function generateUuid(test) { return uuid; } -// Repeatedly requests "request_list" URL until exactly the URLs listed -// in "expectedRequests" have been observed by the request tracker script (in +// Repeatedly requests "request_list" URL until exactly the entries in +// "expectedRequests" have been observed by the request tracker script (in // any order, since report URLs are not guaranteed to be sent in any order). // +// Elements of `expectedRequests` should either be URLs, in the case of GET +// requests, or ", body: " in the case of POST requests. +// // If any other strings are received from the tracking script, or the tracker // script reports an error, fails the test. async function waitForObservedRequests(uuid, expectedRequests) { @@ -129,9 +143,12 @@ function createDecisionScriptUrl(uuid, params = {}) { // Creates a renderUrl for an ad that runs the passed in "script". "uuid" has // no effect, beyond making the URL distinct between tests, and being verified -// by the decision logic script before accepting a bid. -function createRenderUrl(uuid) { - let url = new URL(`${BASE_URL}resources/fenced_frame.sub.html`); +// by the decision logic script before accepting a bid. "uuid" is expected to +// be last. +function createRenderUrl(uuid, script) { + let url = new URL(`${BASE_URL}resources/fenced-frame.sub.py`); + if (script) + url.searchParams.append('script', script); url.searchParams.append('uuid', uuid); return url.toString(); } @@ -232,11 +249,14 @@ async function runBasicFledgeTestExpectingNoWinner(test, testConfig = {}) { // the corresponding reporting method, the report is sent to an error URL. // Otherwise, the corresponding 'reportResult' / 'reportWin' values are run. // +// `renderUrlOverride` allows the ad URL of the joined InterestGroup to +// to be set by the caller. +// // Requesting error report URLs causes waitForObservedRequests() to throw // rather than hang. async function runReportTest(test, uuid, reportResultSuccessCondition, reportResult, reportWinSuccessCondition, reportWin, - expectedReportUrls) { + expectedReportUrls, renderUrlOverride) { if (reportResultSuccessCondition) { reportResult = `if (!(${reportResultSuccessCondition})) { sendReportTo('${createSellerReportUrl(uuid, 'error')}'); @@ -265,6 +285,8 @@ async function runReportTest(test, uuid, reportResultSuccessCondition, let interestGroupOverrides = { biddingLogicUrl: createBiddingScriptUrl(biddingScriptUrlParams) }; + if (renderUrlOverride) + interestGroupOverrides.ads = [{renderUrl: renderUrlOverride}] await joinInterestGroup(test, uuid, interestGroupOverrides); await runBasicFledgeAuctionAndNavigate( diff --git a/testing/web-platform/tests/fledge/tentative/resources/request_tracker.py b/testing/web-platform/tests/fledge/tentative/resources/request_tracker.py index 5fedd727debf..46da796f3010 100644 --- a/testing/web-platform/tests/fledge/tentative/resources/request_tracker.py +++ b/testing/web-platform/tests/fledge/tentative/resources/request_tracker.py @@ -14,7 +14,8 @@ from wptserve.utils import isomorphic_decode, isomorphic_encode # # Each uuid has a stash entry with a dictionary with two entries: # "trackedRequests" is a list of all observed requested URLs with a -# dispatch of "track_get". +# dispatch of "track_get" or "track_post". POSTS are in the format +# ", body: ". # "errors" is a list of an errors that occurred. # # A dispatch of "request_list" will return the "trackedRequests" dictionary @@ -63,6 +64,24 @@ def main(request, response): stash.put(uuid, server_state) return simple_response(request, response, 200, b"OK", b"") + # Tracks a request that's expected to be a POST. + # In addition to the method, check the Content-Type, which is currently + # always text/plain, and compare the body against the expected body. + if dispatch == b"track_post": + contentType = request.headers.get(b"Content-Type", b"missing") + if request.method != "POST": + server_state["errors"].append( + request.url + " has wrong method: " + request.method) + elif not contentType.startswith(b"text/plain"): + server_state["errors"].append( + request.url + " has wrong Content-Type: " + + contentType.decode("utf-8")) + else: + server_state["trackedRequests"].append( + request.url + ", body: " + request.body.decode("utf-8")) + stash.put(uuid, server_state) + return simple_response(request, response, 200, b"OK", b"") + # Report unrecognized dispatch line. server_state["errors"].append( request.url + " request with unknown dispatch value received: " +