[FLEDGE]: Start on WPT currency tests.

For now, this just covers checking of returned bids vs. perBuyerCurrency, and the syntax of both.

Change-Id: I9f6c7850d4c504671945532009856ae291b8d4b4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4974015
Commit-Queue: Maks Orlovich <morlovich@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1215496}
diff --git a/fledge/tentative/auction-config.https.window.js b/fledge/tentative/auction-config.https.window.js
index e4811b9..432be9c 100644
--- a/fledge/tentative/auction-config.https.window.js
+++ b/fledge/tentative/auction-config.https.window.js
@@ -7,7 +7,8 @@
 // META: variant=?6-10
 // META: variant=?11-15
 // META: variant=?16-20
-// META: variant=?21-last
+// META: variant=?21-25
+// META: variant=?26-last
 
 "use strict;"
 
@@ -276,3 +277,31 @@
     ],
   },
 });
+
+makeTest({
+  name: 'perBuyerCurrencies with invalid currency',
+  expect: EXPECT_PROMISE_ERROR,
+  expectPromiseError: EXPECT_EXCEPTION(TypeError),
+  auctionConfigOverrides: {perBuyerCurrencies: {'*': 'Dollars'}}
+});
+
+makeTest({
+  name: 'perBuyerCurrencies with invalid currency map key',
+  expect: EXPECT_PROMISE_ERROR,
+  expectPromiseError: EXPECT_EXCEPTION(TypeError),
+  auctionConfigOverrides: {perBuyerCurrencies: {'example': 'USD'}}
+});
+
+makeTest({
+  name: 'perBuyerCurrencies with non-https currency map key',
+  expect: EXPECT_PROMISE_ERROR,
+  expectPromiseError: EXPECT_EXCEPTION(TypeError),
+  auctionConfigOverrides: {perBuyerCurrencies: {'http://example.org/': 'USD'}}
+});
+
+makeTest({
+  name: 'perBuyerCurrencies not convertible to dictionary',
+  expect: EXPECT_PROMISE_ERROR,
+  expectPromiseError: EXPECT_EXCEPTION(TypeError),
+  auctionConfigOverrides: {perBuyerCurrencies: 123}
+});
diff --git a/fledge/tentative/currency.https.window.js b/fledge/tentative/currency.https.window.js
new file mode 100644
index 0000000..97802ce
--- /dev/null
+++ b/fledge/tentative/currency.https.window.js
@@ -0,0 +1,124 @@
+// 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-last
+
+'use strict;'
+
+// The tests in this file focus on calls to runAdAuction involving currency
+// handling.
+
+// Joins an interest group that bids 9USD on window.location.origin, and one
+// that bids 10CAD on OTHER_ORIGIN1, each with a reportWin() report.
+async function joinTwoCurrencyGroups(test, uuid) {
+  const reportWinURL = createBidderReportURL(uuid, 'USD');
+  const biddingURL = createBiddingScriptURL(
+      {bidCurrency: 'USD', reportWin: `sendReportTo('${reportWinURL}')`});
+  await joinInterestGroup(test, uuid, {biddingLogicURL: biddingURL});
+
+  const otherReportWinURL = createBidderReportURL(uuid, 'CAD', OTHER_ORIGIN1);
+  const otherBiddingURL = createBiddingScriptURL({
+    origin: OTHER_ORIGIN1,
+    bid: 10,
+    bidCurrency: 'CAD',
+    reportWin: `sendReportTo('${otherReportWinURL}')`
+  });
+  await joinCrossOriginInterestGroup(
+      test, uuid, OTHER_ORIGIN1, {biddingLogicURL: otherBiddingURL});
+}
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinInterestGroup(
+      test, uuid,
+      {biddingLogicURL: createBiddingScriptURL({bidCurrency: 'usd'})});
+  await runBasicFledgeTestExpectingNoWinner(test, uuid);
+}, 'Returning bid with invalid currency.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinInterestGroup(
+      test, uuid,
+      {biddingLogicURL: createBiddingScriptURL({bidCurrency: 'USD'})});
+  await runBasicFledgeTestExpectingWinner(test, uuid);
+}, 'Returning bid with currency, configuration w/o currency.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinInterestGroup(test, uuid);
+  await runBasicFledgeTestExpectingWinner(
+      test, uuid, {perBuyerCurrencies: {'*': 'USD'}});
+}, 'Returning bid w/o currency, configuration w/currency.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinInterestGroup(
+      test, uuid,
+      {biddingLogicURL: createBiddingScriptURL({bidCurrency: 'USD'})});
+  await runBasicFledgeTestExpectingWinner(
+      test, uuid, {perBuyerCurrencies: {'*': 'USD'}});
+}, 'Returning bid w/currency, configuration w/matching currency.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinInterestGroup(
+      test, uuid,
+      {biddingLogicURL: createBiddingScriptURL({bidCurrency: 'USD'})});
+  await runBasicFledgeTestExpectingNoWinner(
+      test, uuid, {perBuyerCurrencies: {'*': 'CAD'}});
+}, 'Returning bid w/currency, configuration w/different currency.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinTwoCurrencyGroups(test, uuid);
+  let auctionConfigOverrides = {
+    interestGroupBuyers: [window.location.origin, OTHER_ORIGIN1],
+    perBuyerCurrencies: {}
+  };
+  auctionConfigOverrides.perBuyerCurrencies['*'] = 'USD';
+  auctionConfigOverrides.perBuyerCurrencies[OTHER_ORIGIN1] = 'CAD';
+  await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfigOverrides);
+
+  // Since the scoring script doesn't actually look at the currencies,
+  // We expect 10CAD to win because 10 > 9
+  await waitForObservedRequests(uuid, [
+    createBidderReportURL(uuid, 'CAD', OTHER_ORIGIN1),
+    createSellerReportURL(uuid)
+  ]);
+}, 'Different currencies for different origins, all match.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinTwoCurrencyGroups(test, uuid);
+  let auctionConfigOverrides = {
+    interestGroupBuyers: [window.location.origin, OTHER_ORIGIN1],
+    perBuyerCurrencies: {}
+  };
+  auctionConfigOverrides.perBuyerCurrencies[window.location.origin] = 'USD';
+  auctionConfigOverrides.perBuyerCurrencies[OTHER_ORIGIN1] = 'EUR';
+  await runBasicFledgeAuctionAndNavigate(test, uuid, auctionConfigOverrides);
+
+  // Since the configuration for CAD script expects EUR only the USD bid goes
+  // through.
+  await waitForObservedRequests(
+      uuid, [createBidderReportURL(uuid, 'USD'), createSellerReportURL(uuid)]);
+}, 'Different currencies for different origins, USD one matches.');
+
+subsetTest(promise_test, async test => {
+  const uuid = generateUuid(test);
+  await joinTwoCurrencyGroups(test, uuid);
+  let auctionConfigOverrides = {
+    interestGroupBuyers: [window.location.origin, OTHER_ORIGIN1],
+    perBuyerCurrencies: {}
+  };
+  auctionConfigOverrides.perBuyerCurrencies['*'] = 'EUR';
+}, 'Different currencies for different origins, none match.');
+
+// TODO: look at currency passed in to scoring.
+// Conversion to uniform currency (integrate private aggregation to check)
+// --- also the passthrough and can't modify rule for things already in it.
+// Basic sellerCurrency checks (requires component auctions; can be
+// pass-through or modified bid).
diff --git a/fledge/tentative/resources/bidding-logic.sub.py b/fledge/tentative/resources/bidding-logic.sub.py
index 58fe220..c0d6114 100644
--- a/fledge/tentative/resources/bidding-logic.sub.py
+++ b/fledge/tentative/resources/bidding-logic.sub.py
@@ -37,10 +37,15 @@
         # Use bid query param if present. Otherwise, use a bid of 9.
         bid = (request.GET.first(b"bid", None) or b"9").decode("ASCII")
 
+        bidCurrency = ""
+        bidCurrencyParam = request.GET.first(b"bidCurrency", None)
+        if bidCurrencyParam != None:
+            bidCurrency = "bidCurrency: '" + bidCurrencyParam.decode("ASCII") + "',"
+
         allowComponentAuction = ""
         allowComponentAuctionParam = request.GET.first(b"allowComponentAuction", None)
         if allowComponentAuctionParam != None:
-          allowComponentAuction = f"allowComponentAuction: {allowComponentAuctionParam.decode('ASCII')},"
+            allowComponentAuction = f"allowComponentAuction: {allowComponentAuctionParam.decode('ASCII')},"
 
         body += f"""
             function generateBid(interestGroup, auctionSignals, perBuyerSignals,
@@ -49,6 +54,7 @@
               {{{{GET[generateBid]}}}};
               return {{
                 bid: {bid},
+                {bidCurrency}
                 {allowComponentAuction}
                 render: interestGroup.ads[0].renderURL
               }};
diff --git a/fledge/tentative/resources/fledge-util.sub.js b/fledge/tentative/resources/fledge-util.sub.js
index d500307..9bc1690 100644
--- a/fledge/tentative/resources/fledge-util.sub.js
+++ b/fledge/tentative/resources/fledge-util.sub.js
@@ -151,6 +151,8 @@
     url.searchParams.append('error', params.error);
   if (params.bid)
     url.searchParams.append('bid', params.bid);
+  if (params.bidCurrency)
+    url.searchParams.append('bidCurrency', params.bidCurrency);
   if (params.allowComponentAuction !== undefined)
     url.searchParams.append('allowComponentAuction', JSON.stringify(params.allowComponentAuction))
   return url.toString();