diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/private-aggregation | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/private-aggregation')
14 files changed, 850 insertions, 0 deletions
diff --git a/testing/web-platform/tests/private-aggregation/protected-audience-surface-failure.https.html b/testing/web-platform/tests/private-aggregation/protected-audience-surface-failure.https.html new file mode 100644 index 0000000000..b512afc25d --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/protected-audience-surface-failure.https.html @@ -0,0 +1,70 @@ +<!doctype html> +<meta name=timeout content=long> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="resources/protected-audience-helper-module.js"></script> + +<body> +<script> +'use strict'; + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 340282366920938463463374607431768211456n, value: 1 }'; + + await runReportTest(test, uuid, + { scoreAd: + `try { + privateAggregation.contributeToHistogram(${contribution}); + } catch { + forDebuggingOnly.reportAdAuctionWin('${createWritingURL(uuid)}'); + }`}, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with too large bucket in scoreAd()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: -1n, value: 1 }'; + + await runReportTest(test, uuid, + { reportResult: + `try { + privateAggregation.contributeToHistogram(${contribution}); + } catch { + sendReportTo('${createWritingURL(uuid)}'); + }`}, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with negative bucket in reportResult()'); + + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 1, value: 1 }'; + + await runReportTest(test, uuid, + { generateBid: + `try { + privateAggregation.contributeToHistogram(${contribution}); + } catch { + forDebuggingOnly.reportAdAuctionWin('${createWritingURL(uuid)}'); + }`}, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with non-BigInt bucket in generateBid()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 1n, value: -1 }'; + + await runReportTest(test, uuid, + { reportWin: + `try { + privateAggregation.contributeToHistogram(${contribution}); + } catch { + sendReportTo('${createWritingURL(uuid)}'); + }`}, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with negative value in reportWin()'); + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/protected-audience-surface-success.https.html b/testing/web-platform/tests/private-aggregation/protected-audience-surface-success.https.html new file mode 100644 index 0000000000..1d89032109 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/protected-audience-surface-success.https.html @@ -0,0 +1,98 @@ +<!doctype html> +<meta name=timeout content=long> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="resources/protected-audience-helper-module.js"></script> + +<body> +<script> +'use strict'; + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 1n, value: 1 }'; + + await runReportTest(test, uuid, + { scoreAd: + `privateAggregation.contributeToHistogram(${contribution}); + forDebuggingOnly.reportAdAuctionWin('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with positive bucket in scoreAd()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 0n, value: 1 }'; + + await runReportTest(test, uuid, + { reportResult: + `privateAggregation.contributeToHistogram(${contribution}); + sendReportTo('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with zero bucket in reportResult()'); + + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 18446744073709551616n, value: 1 }'; + + await runReportTest(test, uuid, + { generateBid: + `privateAggregation.contributeToHistogram(${contribution}); + forDebuggingOnly.reportAdAuctionWin('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with large bucket in generateBid()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 340282366920938463463374607431768211455n, value: 1 }'; + + await runReportTest(test, uuid, + { reportWin: + `privateAggregation.contributeToHistogram(${contribution}); + sendReportTo('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with max bucket in reportWin()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 1n, value: 1 }'; + + await runReportTest(test, uuid, + { scoreAd: + `privateAggregation.contributeToHistogram(${contribution}); + forDebuggingOnly.reportAdAuctionWin('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with positive value in scoreAd()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 1n, value: 0 }'; + + await runReportTest(test, uuid, + { reportResult: + `privateAggregation.contributeToHistogram(${contribution}); + sendReportTo('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with zero value in reportResult()'); + +promise_test(async test => { + const uuid = generateUuid(); + const contribution = '{ bucket: 1n, value: 2.3 }'; + + await runReportTest(test, uuid, + { generateBid: + `privateAggregation.contributeToHistogram(${contribution}); + forDebuggingOnly.reportAdAuctionWin('${createWritingURL(uuid)}');` + }, + /*expectedNumReports=*/ 1); +}, 'contributeToHistogram() with non-integer value in generateBid()'); + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/resources/protected-audience-helper-module.js b/testing/web-platform/tests/private-aggregation/resources/protected-audience-helper-module.js new file mode 100644 index 0000000000..be4f01379e --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/resources/protected-audience-helper-module.js @@ -0,0 +1,209 @@ +// This file is adapted from /fledge/tentative/resources/fledge-util.js, +// removing unnecessary logic and modifying to allow it to be run in the +// private-aggregation directory. + +"use strict;" + +const FULL_URL = window.location.href; +let BASE_URL = FULL_URL.substring(0, FULL_URL.lastIndexOf('/') + 1) +const BASE_PATH = (new URL(BASE_URL)).pathname; +const DEFAULT_INTEREST_GROUP_NAME = 'default name'; + +// Use python script files under fledge directory +const FLEDGE_DIR = '/fledge/tentative/'; +const FLEDGE_BASE_URL = BASE_URL.replace(BASE_PATH, FLEDGE_DIR); + +// Sleep method that waits for prescribed number of milliseconds. +const sleep = ms => new Promise(resolve => step_timeout(resolve, ms)); + +// Generates a UUID by token. +function generateUuid() { + let uuid = token(); + return uuid; +} + +// Creates a URL that will be sent to the handler. +// `uuid` is used to identify the stash shard to use. +// `operate` is used to set action as write or read. +// `report` is used to carry the message for write requests. +function createReportingURL(uuid, operation, report = 'default-report') { + let url = new URL(`${window.location.origin}${BASE_PATH}resources/protected_audience_event_level_report_handler.py`); + url.searchParams.append('uuid', uuid); + url.searchParams.append('operation', operation); + + if (report) + url.searchParams.append('report', report); + + return url.toString(); +} + +function createWritingURL(uuid, report) { + return createReportingURL(uuid, 'write'); +} + +function createReadingURL(uuid) { + return createReportingURL(uuid, 'read'); +} + +async function waitForObservedReports(uuid, expectedNumReports, timeout = 5000 /*ms*/) { + expectedReports = Array(expectedNumReports).fill('default-report'); + const reportURL = createReadingURL(uuid); + let startTime = performance.now(); + + while (performance.now() - startTime < timeout) { + let response = await fetch(reportURL, { credentials: 'omit', mode: 'cors' }); + let actualReports = await response.json(); + + // If expected number of reports have been observed, compare with list of + // all expected reports and exit. + if (actualReports.length == expectedReports.length) { + assert_array_equals(actualReports.sort(), expectedReports); + return; + } + + await sleep(/*ms=*/ 100); + } + assert_unreached("Report fetching timed out: " + uuid); +} + +// Creates a bidding script with the provided code in the method bodies. The +// bidding script's generateBid() method will return a bid of 9 for the first +// ad, after the passed in code in the "generateBid" input argument has been +// run, unless it returns something or throws. +// +// The default reportWin() method is empty. +function createBiddingScriptURL(params = {}) { + let url = new URL(`${FLEDGE_BASE_URL}resources/bidding-logic.sub.py`); + if (params.generateBid) + url.searchParams.append('generateBid', params.generateBid); + if (params.reportWin) + url.searchParams.append('reportWin', params.reportWin); + if (params.error) + url.searchParams.append('error', params.error); + if (params.bid) + url.searchParams.append('bid', params.bid); + return url.toString(); +} + +// Creates a decision script with the provided code in the method bodies. The +// decision script's scoreAd() method will reject ads with renderURLs that +// don't ends with "uuid", and will return a score equal to the bid, after the +// passed in code in the "scoreAd" input argument has been run, unless it +// returns something or throws. +// +// The default reportResult() method is empty. +function createDecisionScriptURL(uuid, params = {}) { + let url = new URL(`${FLEDGE_BASE_URL}resources/decision-logic.sub.py`); + url.searchParams.append('uuid', uuid); + if (params.scoreAd) + url.searchParams.append('scoreAd', params.scoreAd); + if (params.reportResult) + url.searchParams.append('reportResult', params.reportResult); + if (params.error) + url.searchParams.append('error', params.error); + return url.toString(); +} + +// 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. "uuid" is expected to +// be last. +function createRenderURL(uuid, script) { + let url = new URL(`${FLEDGE_BASE_URL}resources/fenced-frame.sub.py`); + if (script) + url.searchParams.append('script', script); + url.searchParams.append('uuid', uuid); + return url.toString(); +} + +// Joins an interest group that, by default, is owned by the current frame's +// origin, is named DEFAULT_INTEREST_GROUP_NAME, has a bidding script that +// issues a bid of 9 with a renderURL of "https://not.checked.test/${uuid}". +// `interestGroupOverrides` is required to override fields in the joined +// interest group. +async function joinInterestGroup(test, uuid, interestGroupOverrides) { + const INTEREST_GROUP_LIFETIME_SECS = 60; + + let interestGroup = { + owner: window.location.origin, + name: DEFAULT_INTEREST_GROUP_NAME, + ads: [{renderURL: createRenderURL(uuid)}], + ...interestGroupOverrides + }; + + await navigator.joinAdInterestGroup(interestGroup, + INTEREST_GROUP_LIFETIME_SECS); + test.add_cleanup( + async () => {await navigator.leaveAdInterestGroup(interestGroup)}); +} + +// Runs a FLEDGE auction and returns the result. `auctionConfigOverrides` is +// required to override fields in the auction configuration. +async function runBasicFledgeAuction(test, uuid, auctionConfigOverrides) { + let auctionConfig = { + seller: window.location.origin, + interestGroupBuyers: [window.location.origin], + resolveToConfig: true, + ...auctionConfigOverrides + }; + return await navigator.runAdAuction(auctionConfig); +} + +// Calls runBasicFledgeAuction(), expecting the auction to have a winner. +// Creates a fenced frame that will be destroyed on completion of "test", and +// navigates it to the URN URL returned by the auction. Does not wait for the +// fenced frame to finish loading, since there's no API that can do that. +async function runBasicFledgeAuctionAndNavigate(test, uuid, + auctionConfigOverrides) { + let config = await runBasicFledgeAuction(test, uuid, auctionConfigOverrides); + assert_true(config instanceof FencedFrameConfig, + `Wrong value type returned from auction: ${config.constructor.type}`); + + let fencedFrame = document.createElement('fencedframe'); + fencedFrame.mode = 'opaque-ads'; + fencedFrame.config = config; + document.body.appendChild(fencedFrame); + test.add_cleanup(() => { document.body.removeChild(fencedFrame); }); +} + +// Joins an interest group and runs an auction, expecting no winner to be +// returned. "testConfig" can optionally modify the interest group or +// auctionConfig. +async function runBasicFledgeTestExpectingNoWinner(test, testConfig) { + const uuid = generateUuid(test); + await joinInterestGroup(test, uuid, testConfig.interestGroupOverrides); + let result = await runBasicFledgeAuction( + test, uuid, testConfig.auctionConfigOverrides); + assert_true(result === null, 'Auction unexpectedly had a winner'); +} + +// Test helper for report phase of auctions that lets the caller specify the +// body of scoreAd(), reportResult(), generateBid() and reportWin(), as well as +// additional arguments to be passed to joinAdInterestGroup() and runAdAuction() +async function runReportTest(test, uuid, codeToInsert, + expectedNumReports = 0, overrides = {}) { + let generateBid = codeToInsert.generateBid; + let scoreAd = codeToInsert.scoreAd; + let reportWin = codeToInsert.reportWin; + let reportResult = codeToInsert.reportResult; + + let extraInterestGroupOverrides = overrides.joinAdInterestGroup || {} + let extraAuctionConfigOverrides = overrides.runAdAuction || {} + + let interestGroupOverrides = { + biddingLogicURL: createBiddingScriptURL({ generateBid, reportWin }), + ...extraInterestGroupOverrides + }; + let auctionConfigOverrides = { + decisionLogicURL: createDecisionScriptURL( + uuid, { scoreAd, reportResult }), + ...extraAuctionConfigOverrides + } + + await joinInterestGroup(test, uuid, interestGroupOverrides); + await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfigOverrides); + + if (expectedNumReports) { + await waitForObservedReports(uuid, expectedNumReports); + } +} diff --git a/testing/web-platform/tests/private-aggregation/resources/protected_audience_event_level_report_handler.py b/testing/web-platform/tests/private-aggregation/resources/protected_audience_event_level_report_handler.py new file mode 100644 index 0000000000..c77b9e19c8 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/resources/protected_audience_event_level_report_handler.py @@ -0,0 +1,43 @@ +"""Handler to receive message from protected audience worklets, such as +sendReportTo() and forDebuggingOnly.reportAdAuctionWin(). + +This handler only supports read and write operations from the URL parameters. +""" + +import json +from typing import List, Tuple + +from wptserve.request import Request +from wptserve.response import Response + +Header = Tuple[str, str] +ResponseTuple = Tuple[int, List[Header], str] + +def main(request: Request, response: Response) -> ResponseTuple: + operation = request.GET.first(b"operation").decode('utf-8') + uuid = request.GET.first(b"uuid").decode('utf-8') + if operation == "read": + with request.server.stash.lock: + stash_reports = request.server.stash.take(key=uuid) + if stash_reports is None: + stash_reports = [] + else: + request.server.stash.put(key=uuid, value=stash_reports) + + return 200, [("Content-Type", "application/json")], json.dumps(stash_reports) + elif operation == "write": + report = request.GET.first(b"report").decode('utf-8') + + if report is None: + return 400, [("Content-Type", "application/json")], json.dumps({'error': 'Missing report.', 'uuid': uuid}) + + with request.server.stash.lock: + stash_reports = request.server.stash.take(key=uuid) + if stash_reports is None: + stash_reports = [] + stash_reports.append(report) + request.server.stash.put(key=uuid, value=stash_reports) + + return 200, [("Content-Type", "application/json")], json.dumps({'msg': 'Recorded report ' + uuid}) + else: + return 400, [("Content-Type", "application/json")], json.dumps({'error': 'Invalid operation.', 'uuid': uuid}) diff --git a/testing/web-platform/tests/private-aggregation/resources/reports.py b/testing/web-platform/tests/private-aggregation/resources/reports.py new file mode 100644 index 0000000000..0f6fd8255a --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/resources/reports.py @@ -0,0 +1,88 @@ +"""Methods for the report-shared-storage and report-protected-audience endpoints (including debug endpoints)""" +import json +from typing import List, Optional, Tuple, Union +import urllib.parse + +from wptserve.request import Request +from wptserve.stash import Stash +from wptserve.utils import isomorphic_decode, isomorphic_encode + +# Arbitrary key used to access the reports in the stash. +REPORTS_KEY = "9d285691-4386-45ad-9a79-d2ec29557bfe" + +CLEAR_STASH_AS_BYTES = isomorphic_encode("clear_stash") + +Header = Tuple[str, str] +Status = Union[int, Tuple[int, str]] +Response = Tuple[Status, List[Header], str] + +def get_request_origin(request: Request) -> str: + return "%s://%s" % (request.url_parts.scheme, + request.url_parts.netloc) + +def handle_post_request(request: Request) -> Response: + """Handles POST request for reports. + + Retrieves the report from the request body and stores the report in the + stash. If clear_stash is specified in the query params, clears the stash. + """ + if request.GET.get(CLEAR_STASH_AS_BYTES): + clear_stash(request.server.stash) + return 200, [], "Stash successfully cleared." + + store_report(request.server.stash, get_request_origin(request), + request.body.decode("utf-8")) + return 200, [], "" + + +def handle_get_request(request: Request) -> Response: + """Handles GET request for reports. + + Retrieves and returns all reports from the stash. + """ + headers = [("Content-Type", "application/json")] + reports = take_reports(request.server.stash, get_request_origin(request)) + headers.append(("Access-Control-Allow-Origin", "*")) + return 200, headers, json.dumps(reports) + + +def store_report(stash: Stash, origin: str, report: str) -> None: + """Stores the report in the stash. Report here is a JSON.""" + with stash.lock: + reports_dict = stash.take(REPORTS_KEY) + if not reports_dict: + reports_dict = {} + reports = reports_dict.get(origin, []) + reports.append(report) + reports_dict[origin] = reports + stash.put(REPORTS_KEY, reports_dict) + return None + +def clear_stash(stash: Stash) -> None: + "Clears the stash." + stash.take(REPORTS_KEY) + return None + +def take_reports(stash: Stash, origin: str) -> List[str]: + """Takes all the reports from the stash and returns them.""" + with stash.lock: + reports_dict = stash.take(REPORTS_KEY) + if not reports_dict: + reports_dict = {} + + reports = reports_dict.pop(origin, []) + stash.put(REPORTS_KEY, reports_dict) + return reports + + +def handle_request(request: Request) -> Response: + """Handles request to get or store reports.""" + if request.method == "POST": + return handle_post_request(request) + if request.method == "GET": + return handle_get_request(request) + + return (405, "Method Not Allowed"), [("Content-Type", "application/json")], json.dumps({ + "code": 405, + "message": "Only GET or POST methods are supported." + }) diff --git a/testing/web-platform/tests/private-aggregation/resources/shared-storage-helper-module.js b/testing/web-platform/tests/private-aggregation/resources/shared-storage-helper-module.js new file mode 100644 index 0000000000..f5a8533d0f --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/resources/shared-storage-helper-module.js @@ -0,0 +1,23 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +class ContributeToHistogramOperation { + async run(urls, data) { + if (data.enableDebugMode) { + privateAggregation.enableDebugMode(data.enableDebugModeArgs); + + if (data.enableDebugModeExtraTime) { + privateAggregation.enableDebugMode(data.enableDebugModeArgs); + } + } + for (const contribution of data.contributions) { + privateAggregation.contributeToHistogram(contribution); + } + + // If an error occurs, the default URL will be picked instead. + return 1; + } +} + +register('contribute-to-histogram', ContributeToHistogramOperation); diff --git a/testing/web-platform/tests/private-aggregation/resources/util.js b/testing/web-platform/tests/private-aggregation/resources/util.js new file mode 100644 index 0000000000..24e156446f --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/resources/util.js @@ -0,0 +1,24 @@ +// Execute Private Aggregation functions in shared storage worklet given +// `paa_data`, and expect that success/failure result is `expected_error`. +async function VerifyContributeToHistogram(paa_data, expected_error) { + const ancestor_key = token(); + let url0 = generateURL("/shared-storage/resources/frame0.html", + [ancestor_key]); + let url1 = generateURL("/shared-storage/resources/frame1.html", + [ancestor_key]); + + await addModuleOnce("/private-aggregation/resources/shared-storage-helper-module.js"); + + let select_url_result = await sharedStorage.selectURL( + "contribute-to-histogram", [{url: url0}, {url: url1}], + {data: paa_data, keepAlive: true}); + + attachFencedFrame(select_url_result, 'opaque-ads'); + const result = await nextValueFromServer(ancestor_key); + + if (expected_error) { + assert_equals(result, "frame0_loaded"); + } else { + assert_equals(result, "frame1_loaded"); + } +} diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-permissions-policy-none.https.html b/testing/web-platform/tests/private-aggregation/shared-storage-permissions-policy-none.https.html new file mode 100644 index 0000000000..3593ed71ea --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-permissions-policy-none.https.html @@ -0,0 +1,23 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/shared-storage/resources/util.js"></script> +<script src="/private-aggregation/resources/util.js"></script> +<script src="/fenced-frame/resources/utils.js"></script> + +<body> +<script> +'use strict'; + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'contributeToHistogram() with disabled "private-aggregation" permissions policy'); + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-permissions-policy-none.https.html.headers b/testing/web-platform/tests/private-aggregation/shared-storage-permissions-policy-none.https.html.headers new file mode 100644 index 0000000000..8781910151 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-permissions-policy-none.https.html.headers @@ -0,0 +1 @@ +Permissions-Policy: private-aggregation=() diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-surface-context-id.https.html b/testing/web-platform/tests/private-aggregation/shared-storage-surface-context-id.https.html new file mode 100644 index 0000000000..3b0e1b3d74 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-surface-context-id.https.html @@ -0,0 +1,73 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/shared-storage/resources/util.js"></script> +<script src="/private-aggregation/resources/util.js"></script> +<script src="/fenced-frame/resources/utils.js"></script> + +<body> +<script> +'use strict'; + +promise_test(async () => { + await addModuleOnce("/private-aggregation/resources/private-aggregation-helper-module.js"); + + const data = { + contributions: [{bucket: 1n, value: 2}] + }; + const privateAggregationConfig = { + contextId: "example_context_id" + }; + + await sharedStorage.run("contribute-to-histogram", + {data, privateAggregationConfig, keepAlive: true}); +}, 'set context ID'); + +promise_test(async () => { + await addModuleOnce("/private-aggregation/resources/private-aggregation-helper-module.js"); + + const data = { + contributions: [{bucket: 1n, value: 2}] + }; + const privateAggregationConfig = { + contextId: "" + }; + + await sharedStorage.run("contribute-to-histogram", + {data, privateAggregationConfig, keepAlive: true}); +}, 'set empty context ID'); + +promise_test(async () => { + await addModuleOnce("/private-aggregation/resources/private-aggregation-helper-module.js"); + + const data = { + contributions: [{bucket: 1n, value: 2}] + }; + const privateAggregationConfig = { + contextId: "an_example_of_a_context_id_with_the_exact_maximum_allowed_length" + }; + + await sharedStorage.run("contribute-to-histogram", + {data, privateAggregationConfig, keepAlive: true}); +}, 'set max length context ID'); + +promise_test(async (test) => { + await addModuleOnce("/private-aggregation/resources/private-aggregation-helper-module.js"); + + const data = { + contributions: [{bucket: 1n, value: 2}] + }; + const privateAggregationConfig = { + contextId: "this_is_an_example_of_a_context_id_that_is_too_long_to_be_allowed" + }; + + return promise_rejects_dom( + test, "DataError", + sharedStorage.run("contribute-to-histogram", + {data, privateAggregationConfig, keepAlive: true})); +}, 'set too long context ID'); + + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-surface-failure-2.https.html b/testing/web-platform/tests/private-aggregation/shared-storage-surface-failure-2.https.html new file mode 100644 index 0000000000..b39ecd8d74 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-surface-failure-2.https.html @@ -0,0 +1,26 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/shared-storage/resources/util.js"></script> +<script src="/private-aggregation/resources/util.js"></script> +<script src="/fenced-frame/resources/utils.js"></script> + +<body> +<script> +'use strict'; + +// Note: This file should contain at most 6 shared storage subtests due to the +// budget on selectURL(). + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 1n, value: -2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'contributeToHistogram() with a negative value'); + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-surface-failure.https.html b/testing/web-platform/tests/private-aggregation/shared-storage-surface-failure.https.html new file mode 100644 index 0000000000..9dc62b1bb7 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-surface-failure.https.html @@ -0,0 +1,74 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/shared-storage/resources/util.js"></script> +<script src="/private-aggregation/resources/util.js"></script> +<script src="/fenced-frame/resources/utils.js"></script> + +<body> +<script> +'use strict'; + +// Note: This file should contain at most 6 shared storage subtests due to the +// budget on selectURL(). + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 340282366920938463463374607431768211456n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'contributeToHistogram() with a bucket too large'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: -1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'contributeToHistogram() with negative bucket'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 1, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'contributeToHistogram() with non-BigInt bucket'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + enableDebugModeArgs: 1234n, + contributions: [{bucket: 1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'Invalid enableDebugMode argument'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + enableDebugModeArgs: {debugKey: 1234}, + contributions: [{bucket: 1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'contributeToHistogram() with a non-BigInt debugKey'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + enableDebugModeExtraTime: true, + contributions: [{bucket: 1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/true); +}, 'enableDebugMode called twice'); + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-surface-success-2.https.html b/testing/web-platform/tests/private-aggregation/shared-storage-surface-success-2.https.html new file mode 100644 index 0000000000..8203fd11ea --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-surface-success-2.https.html @@ -0,0 +1,27 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/shared-storage/resources/util.js"></script> +<script src="/private-aggregation/resources/util.js"></script> +<script src="/fenced-frame/resources/utils.js"></script> + +<body> +<script> +'use strict'; + +// Note: This file should contain at most 6 shared storage subtests due to the +// budget on selectURL(). + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + enableDebugModeArgs: {debugKey: 1234n}, + contributions: [{bucket: 1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'contributeToHistogram() with a valid debugKey'); + +</script> +</body> diff --git a/testing/web-platform/tests/private-aggregation/shared-storage-surface-success.https.html b/testing/web-platform/tests/private-aggregation/shared-storage-surface-success.https.html new file mode 100644 index 0000000000..7012180c71 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/shared-storage-surface-success.https.html @@ -0,0 +1,71 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/shared-storage/resources/util.js"></script> +<script src="/private-aggregation/resources/util.js"></script> +<script src="/fenced-frame/resources/utils.js"></script> + +<body> +<script> +'use strict'; + +// Note: This file should contain at most 6 shared storage subtests due to the +// budget on selectURL(). + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 1n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'basic contributeToHistogram() test'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 0n, value: 2}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'contributeToHistogram() with a zero bucket'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 1n, value: 0}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'contributeToHistogram() with a zero value'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 18446744073709551616n, value: 5}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'contributeToHistogram() with a large bucket'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 340282366920938463463374607431768211455n, value: 5}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'contributeToHistogram() with a max bucket'); + +promise_test(async () => { + const paa_data = { + enableDebugMode: true, + contributions: [{bucket: 1n, value: 2.3}] + }; + + await VerifyContributeToHistogram(paa_data, /*expected_error=*/false); +}, 'contributeToHistogram() with a non-integer value'); + +</script> +</body> |