tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

get-interest-group-auction-data.https.window.js (31339B)


      1 // META: script=/resources/testdriver.js
      2 // META: script=/resources/testdriver-vendor.js
      3 // META: script=/common/utils.js
      4 // META: script=resources/ba-fledge-util.sub.js
      5 // META: script=resources/fledge-util.sub.js
      6 // META: script=third_party/cbor-js/cbor.js
      7 // META: script=/common/subset-tests.js
      8 // META: timeout=long
      9 // META: variant=?1-4
     10 // META: variant=?5-8
     11 // META: variant=?9-12
     12 // META: variant=?13-16
     13 // META: variant=?17-last
     14 
     15 "use strict";
     16 
     17 // These tests focus on the navigator.getInterestGroupAdAuctionData() method.
     18 
     19 // Checks various fields for decoded InterestGroupAdAuctionData that's
     20 // one IG owned by this origin, and returns that IG's info.
     21 function validateWithOneIg(decoded) {
     22  assert_equals(decoded.message.version, 0);
     23  assert_equals(decoded.message.publisher, window.location.hostname);
     24  assert_equals(typeof decoded.message.generationId, 'string');
     25  let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
     26  assert_array_equals(igMapKeys, [window.location.origin]);
     27  let igInfo = decoded.message.interestGroups[window.location.origin];
     28  assert_true(igInfo instanceof Array);
     29  assert_equals(igInfo.length, 1, 'number of IGs');
     30  return igInfo[0];
     31 }
     32 
     33 subsetTest(promise_test, async test => {
     34  const result = await navigator.getInterestGroupAdAuctionData({
     35    coordinatorOrigin: await BA.configureCoordinator(),
     36    seller: window.location.origin
     37  });
     38  assert_true(result.requestId !== null);
     39  assert_true(result.request.length === 0);
     40 }, 'getInterestGroupAdAuctionData() with no interest groups returns a zero length result.');
     41 
     42 async function testInvalidConfig(test, configObj, desc) {
     43  if (!configObj.coordinatorOrigin) {
     44    configObj.coordinatorOrigin = await BA.configureCoordinator();
     45  }
     46  await promise_rejects_js(
     47      test, TypeError, navigator.getInterestGroupAdAuctionData(configObj),
     48      desc);
     49 }
     50 
     51 subsetTest(promise_test, async test => {
     52  await testInvalidConfig(test, {}, 'no seller');
     53  await testInvalidConfig(test, {seller: 'example'}, 'invalid seller 1');
     54  await testInvalidConfig(
     55      test, {seller: 'http://example.org'}, 'invalid seller 2');
     56  await testInvalidConfig(
     57      test, {seller: 'https://example.org', coordinatorOrigin: 'example'},
     58      'invalid coordinator 1');
     59  await testInvalidConfig(
     60      test, {seller: 'https://example.org', coordinatorOrigin: 'example.org'},
     61      'invalid coordinator 2');
     62 
     63  await testInvalidConfig(
     64      test, {seller: 'https://example.org', perBuyerConfig: {'a': {}}},
     65      'invalid buyer 1');
     66 
     67  await testInvalidConfig(
     68      test,
     69      {seller: 'https://example.org', perBuyerConfig: {'http://a.com': {}}},
     70      'invalid buyer 2');
     71 
     72  await testInvalidConfig(
     73      test, {
     74        seller: 'https://example.org',
     75        perBuyerConfig: {'https://a.com': {}, 'http://b.com': {}}
     76      },
     77      'invalid buyer 3');
     78 
     79  await testInvalidConfig(
     80      test, {
     81        seller: 'https://example.org',
     82        perBuyerConfig: {'https://a.com': {}, 'https://b.com': {}}
     83      },
     84      'missing size info w/per-buyer config 1');
     85 
     86  await testInvalidConfig(
     87      test, {
     88        seller: 'https://example.org',
     89        perBuyerConfig:
     90            {'https://a.com': {targetSize: 400}, 'https://b.com': {}}
     91      },
     92      'missing size info w/per-buyer config 2');
     93 
     94  // These two actually succeed.
     95  let result = await navigator.getInterestGroupAdAuctionData({
     96    coordinatorOrigin: await BA.configureCoordinator(),
     97    seller: 'https://example.org',
     98    perBuyerConfig:
     99        {'https://a.com': {targetSize: 400}, 'https://b.com': {targetSize: 500}}
    100  });
    101  assert_true(result.requestId !== null);
    102 
    103  result = await navigator.getInterestGroupAdAuctionData({
    104    coordinatorOrigin: await BA.configureCoordinator(),
    105    seller: 'https://example.org',
    106    perBuyerConfig: {'https://a.com': {targetSize: 400}, 'https://b.com': {}},
    107    requestSize: 5000
    108  });
    109  assert_true(result.requestId !== null);
    110 }, 'getInterestGroupAdAuctionData() config checks');
    111 
    112 subsetTest(promise_test, async test => {
    113  const uuid = generateUuid(test);
    114  await joinInterestGroup(test, uuid);
    115 
    116  const result = await navigator.getInterestGroupAdAuctionData({
    117    coordinatorOrigin: await BA.configureCoordinator(),
    118    seller: window.location.origin
    119  });
    120  assert_true(result.requestId !== null);
    121  assert_true(result.request.length > 0);
    122 
    123  let decoded = await BA.decodeInterestGroupData(result.request);
    124 
    125  // Check that the required field and one IG (but no ad data) are here,
    126  // since we neither provided adRenderIds or asked for full data to be
    127  // included.
    128  let ig = validateWithOneIg(decoded);
    129  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    130  assert_array_equals(ig.ads, []);
    131  assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
    132  assert_equals(ig.browserSignals.bidCount, 0, 'bidCount');
    133  assert_array_equals(ig.browserSignals.prevWins, []);
    134 }, 'getInterestGroupAdAuctionData() with one interest group returns a valid result.');
    135 
    136 subsetTest(promise_test, async test => {
    137  const uuid = generateUuid(test);
    138  await joinInterestGroup(test, uuid, {
    139    ads: [
    140      {renderURL: createRenderURL(uuid) + '&a', adRenderId: 'a'},
    141      {renderURL: createRenderURL(uuid) + '&a', adRenderId: 'b'}
    142    ]
    143  });
    144 
    145  const result = await navigator.getInterestGroupAdAuctionData({
    146    coordinatorOrigin: await BA.configureCoordinator(),
    147    seller: window.location.origin
    148  });
    149  assert_true(result.requestId !== null);
    150  assert_true(result.request.length > 0);
    151 
    152  let decoded = await BA.decodeInterestGroupData(result.request);
    153  let ig = validateWithOneIg(decoded);
    154 
    155  // This ig should have two ads with adRenderIds, but not URLs.
    156  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    157  assert_array_equals(ig.ads, ['a', 'b']);
    158  assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
    159  assert_equals(ig.browserSignals.bidCount, 0, 'bidCount');
    160  assert_array_equals(ig.browserSignals.prevWins, []);
    161 }, 'getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds.');
    162 
    163 subsetTest(promise_test, async test => {
    164  const uuid = generateUuid(test);
    165  await joinInterestGroup(test, uuid, {
    166    auctionServerRequestFlags: ['omit-ads'],
    167    ads: [
    168      {renderURL: createRenderURL(uuid) + '&a', adRenderId: 'a'},
    169      {renderURL: createRenderURL(uuid) + '&a', adRenderId: 'b'}
    170    ]
    171  });
    172 
    173  const result = await navigator.getInterestGroupAdAuctionData({
    174    coordinatorOrigin: await BA.configureCoordinator(),
    175    seller: window.location.origin
    176  });
    177  assert_true(result.requestId !== null);
    178  assert_true(result.request.length > 0);
    179 
    180  let decoded = await BA.decodeInterestGroupData(result.request);
    181  let ig = validateWithOneIg(decoded);
    182 
    183  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    184  assert_not_own_property(ig, 'ads', 'no ads expected');
    185  assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
    186 }, 'getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds and omit-ads.');
    187 
    188 subsetTest(promise_test, async test => {
    189  const uuid = generateUuid(test);
    190 
    191  const adsArray = [
    192    {renderURL: createRenderURL(uuid) + '&a', adRenderId: 'a'},
    193    {renderURL: createRenderURL(uuid) + '&a', adRenderId: 'b'}
    194  ];
    195  await joinInterestGroup(
    196      test, uuid,
    197      {auctionServerRequestFlags: ['include-full-ads'], ads: adsArray});
    198 
    199  const result = await navigator.getInterestGroupAdAuctionData({
    200    coordinatorOrigin: await BA.configureCoordinator(),
    201    seller: window.location.origin
    202  });
    203  assert_true(result.requestId !== null);
    204  assert_true(result.request.length > 0);
    205 
    206  let decoded = await BA.decodeInterestGroupData(result.request);
    207  let ig = validateWithOneIg(decoded);
    208 
    209  // Since include-full-ads is on, this gets entire objects, not just
    210  // adRenderId.
    211  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    212  assert_equals(ig.ads.length, 2, '# of ads');
    213  assert_equals(ig.ads[0].renderURL, adsArray[0].renderURL, 'renderURL 0');
    214  assert_equals(ig.ads[1].renderURL, adsArray[1].renderURL, 'renderURL 1');
    215  assert_equals(ig.ads[0].adRenderId, adsArray[0].adRenderId, 'adRenderId 0');
    216  assert_equals(ig.ads[1].adRenderId, adsArray[1].adRenderId, 'adRenderId 1');
    217  assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
    218 }, 'getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds and include-full-ads.');
    219 
    220 // Returns an AuctionAdInterestGroup that sets all fields that can be exported
    221 // via getInterestGroupAdAuctionData().
    222 function makeTemplateIgConfig(uuid) {
    223  const adsArray = [
    224    {
    225      renderURL: createRenderURL(uuid) + '&a',
    226      adRenderId: 'a',
    227      metadata: 'ada',
    228      sizeGroup: 'small'
    229    },
    230    {
    231      renderURL: createRenderURL(uuid) + '&b',
    232      adRenderId: 'b',
    233      metadata: 'adb',
    234      sizeGroup: 'big'
    235    }
    236  ];
    237  const adComponentsArray = [
    238    {
    239      renderURL: 'https://example.org/ca',
    240      adRenderId: 'ca',
    241      metadata: 'compa',
    242      sizeGroup: 'big'
    243    },
    244    {
    245      renderURL: 'https://example.org/cb',
    246      adRenderId: 'cb',
    247      metadata: 'compb',
    248      sizeGroup: 'small'
    249    },
    250    {
    251      renderURL: 'https://example.org/cc',
    252      adRenderId: 'cc',
    253      metadata: 'compc',
    254      sizeGroup: 'big'
    255    },
    256  ];
    257  return {
    258    ads: adsArray,
    259    adComponents: adComponentsArray,
    260    adSizes: {
    261      's': {width: '100px', height: '30px'},
    262      'xl': {width: '1000px', height: '300px'}
    263    },
    264    sizeGroups: {'small': ['s'], 'big': ['xl']},
    265    trustedBiddingSignalsKeys: ['alpha', 'beta'],
    266    userBiddingSignals: 14
    267  };
    268 }
    269 
    270 subsetTest(promise_test, async test => {
    271  const uuid = generateUuid(test);
    272  const igConfig = makeTemplateIgConfig(uuid);
    273  igConfig.auctionServerRequestFlags = ['include-full-ads'];
    274  await joinInterestGroup(test, uuid, igConfig);
    275 
    276  const result = await navigator.getInterestGroupAdAuctionData({
    277    coordinatorOrigin: await BA.configureCoordinator(),
    278    seller: window.location.origin
    279  });
    280  assert_true(result.requestId !== null);
    281  assert_true(result.request.length > 0);
    282 
    283  let decoded = await BA.decodeInterestGroupData(result.request);
    284  let ig = validateWithOneIg(decoded);
    285 
    286  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    287  assert_true(ig.ads instanceof Array);
    288  assert_equals(ig.ads.length, 2, '# of ads');
    289  assert_equals(ig.ads[0].renderURL, igConfig.ads[0].renderURL, 'renderURL 0');
    290  assert_equals(ig.ads[1].renderURL, igConfig.ads[1].renderURL, 'renderURL 1');
    291  assert_equals(ig.ads[0].adRenderId, 'a', 'adRenderId 0');
    292  assert_equals(ig.ads[1].adRenderId, 'b', 'adRenderId 1');
    293  assert_equals(ig.ads[0].metadata, '"ada"', 'metadata 0');
    294  assert_equals(ig.ads[1].metadata, '"adb"', 'metadata 1');
    295  assert_equals(ig.ads[0].sizeGroup, 'small', 'sizegroup 0');
    296  assert_equals(ig.ads[1].sizeGroup, 'big', 'sizegroup 1');
    297 
    298  assert_true(ig.components instanceof Array);
    299  assert_equals(ig.components.length, 3, '# of component ads');
    300  assert_equals(
    301      ig.components[0].renderURL, igConfig.adComponents[0].renderURL,
    302      'component renderURL 0');
    303  assert_equals(
    304      ig.components[1].renderURL, igConfig.adComponents[1].renderURL,
    305      'component renderURL 1');
    306  assert_equals(
    307      ig.components[2].renderURL, igConfig.adComponents[2].renderURL,
    308      'component renderURL 2');
    309  assert_equals(ig.components[0].adRenderId, 'ca', 'component adRenderId 0');
    310  assert_equals(ig.components[1].adRenderId, 'cb', 'component adRenderId 1');
    311  assert_equals(ig.components[2].adRenderId, 'cc', 'component adRenderId 2');
    312  assert_equals(ig.components[0].metadata, '"compa"', 'component metadata 0');
    313  assert_equals(ig.components[1].metadata, '"compb"', 'component metadata 1');
    314  assert_equals(ig.components[2].metadata, '"compc"', 'component metadata 2');
    315  assert_equals(ig.components[0].sizeGroup, 'big', 'component sizegroup 0');
    316  assert_equals(ig.components[1].sizeGroup, 'small', 'component sizegroup 1');
    317  assert_equals(ig.components[2].sizeGroup, 'big', 'component sizegroup 2');
    318 
    319  assert_true(ig.biddingSignalsKeys instanceof Array);
    320  assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
    321  assert_equals(ig.userBiddingSignals, '14');
    322 }, 'getInterestGroupAdAuctionData() all IG data fields, with include-full-ads');
    323 
    324 subsetTest(promise_test, async test => {
    325  const uuid = generateUuid(test);
    326  const igConfig = makeTemplateIgConfig(uuid);
    327  await joinInterestGroup(test, uuid, igConfig);
    328 
    329  const result = await navigator.getInterestGroupAdAuctionData({
    330    coordinatorOrigin: await BA.configureCoordinator(),
    331    seller: window.location.origin
    332  });
    333  assert_true(result.requestId !== null);
    334  assert_true(result.request.length > 0);
    335 
    336  let decoded = await BA.decodeInterestGroupData(result.request);
    337  let ig = validateWithOneIg(decoded);
    338 
    339  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    340  assert_array_equals(ig.ads, ['a', 'b']);
    341 
    342  assert_true(ig.components instanceof Array);
    343  assert_array_equals(ig.ads, ['a', 'b']);
    344  assert_array_equals(ig.components, ['ca', 'cb', 'cc']);
    345 
    346  assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
    347  assert_equals(ig.userBiddingSignals, '14');
    348 }, 'getInterestGroupAdAuctionData() all IG data fields, w/o include-full-ads');
    349 
    350 subsetTest(promise_test, async test => {
    351  const uuid = generateUuid(test);
    352 
    353  const igConfig = makeTemplateIgConfig(uuid);
    354  igConfig.auctionServerRequestFlags = ['omit-user-bidding-signals'];
    355  await joinInterestGroup(test, uuid, igConfig);
    356 
    357  const result = await navigator.getInterestGroupAdAuctionData({
    358    coordinatorOrigin: await BA.configureCoordinator(),
    359    seller: window.location.origin
    360  });
    361  assert_true(result.requestId !== null);
    362  assert_true(result.request.length > 0);
    363 
    364  let decoded = await BA.decodeInterestGroupData(result.request);
    365  let ig = validateWithOneIg(decoded);
    366 
    367  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    368  assert_array_equals(ig.ads, ['a', 'b']);
    369 
    370  assert_true(ig.components instanceof Array);
    371  assert_array_equals(ig.ads, ['a', 'b']);
    372  assert_array_equals(ig.components, ['ca', 'cb', 'cc']);
    373 
    374  assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
    375  assert_false('userBiddingSignals' in ig, 'userBiddingSignals');
    376 }, 'getInterestGroupAdAuctionData() all IG data fields, with omit-user-bidding-signals');
    377 
    378 subsetTest(promise_test, async test => {
    379  const uuid = generateUuid(test);
    380 
    381  const igConfig = makeTemplateIgConfig(uuid);
    382 
    383  // Join twice.
    384  await joinInterestGroup(test, uuid, igConfig);
    385  await joinInterestGroup(test, uuid, igConfig);
    386 
    387  // And run an auction. This is a local auction, not a B&A one, run to update
    388  // bid/win stats.
    389  await runBasicFledgeAuctionAndNavigate(test, uuid);
    390  await waitForObservedRequests(
    391      uuid, [createBidderReportURL(uuid), createSellerReportURL(uuid)]);
    392 
    393  const result = await navigator.getInterestGroupAdAuctionData({
    394    coordinatorOrigin: await BA.configureCoordinator(),
    395    seller: window.location.origin
    396  });
    397  assert_true(result.requestId !== null);
    398  assert_true(result.request.length > 0);
    399 
    400  let decoded = await BA.decodeInterestGroupData(result.request);
    401  let ig = validateWithOneIg(decoded);
    402  assert_equals(ig.browserSignals.joinCount, 2, 'joinCount');
    403  assert_equals(ig.browserSignals.bidCount, 1, 'bidCount');
    404 
    405  // RecencyMs is the # of milliseconds since the join. We can't exactly say
    406  // what it is, but it shouldn't be too huge.
    407  assert_true(typeof ig.browserSignals.recencyMs === 'number');
    408  assert_between_inclusive(
    409      ig.browserSignals.recencyMs, 0, 60000,
    410      'RecencyMs is between 0 and 60 seconds');
    411  // It's also supposed to be an integer.
    412  assert_equals(
    413      ig.browserSignals.recencyMs, Math.round(ig.browserSignals.recencyMs),
    414      'RecencyMs is an integer');
    415 
    416  // One win. The format here depends highly on whether full ads are used or
    417  // not.
    418  assert_true(
    419      ig.browserSignals.prevWins instanceof Array, 'prevWins is an array');
    420  assert_equals(ig.browserSignals.prevWins.length, 1, 'prevWins length');
    421  assert_true(
    422      ig.browserSignals.prevWins[0] instanceof Array,
    423      'prevWins[0] is an array');
    424  assert_equals(ig.browserSignals.prevWins[0].length, 2, 'prevWins[0] length');
    425 
    426  // prevWins[0][0] is the time delta in second again.
    427  let prevWinTime = ig.browserSignals.prevWins[0][0];
    428  assert_true(typeof prevWinTime === 'number');
    429  assert_between_inclusive(
    430      prevWinTime, 0, 60, 'prevWinTime is between 0 and 60 seconds');
    431  // It's also supposed to be an integer.
    432  assert_equals(
    433      prevWinTime, Math.round(prevWinTime), 'prevWinTime is an integer');
    434 
    435  // prevWins[0][1] is the adRenderId of the winner.
    436  assert_equals(ig.browserSignals.prevWins[0][1], 'a');
    437 }, 'getInterestGroupAdAuctionData() browserSignals');
    438 
    439 subsetTest(promise_test, async test => {
    440  const uuid = generateUuid(test);
    441 
    442  const igConfig = makeTemplateIgConfig(uuid);
    443  igConfig.auctionServerRequestFlags = ['include-full-ads'];
    444 
    445  // Join twice.
    446  await joinInterestGroup(test, uuid, igConfig);
    447  await joinInterestGroup(test, uuid, igConfig);
    448 
    449  // And run an auction. This is a local auction, not a B&A one, run to update
    450  // bid/win stats.
    451  await runBasicFledgeAuctionAndNavigate(test, uuid);
    452  await waitForObservedRequests(
    453      uuid, [createBidderReportURL(uuid), createSellerReportURL(uuid)]);
    454 
    455  const result = await navigator.getInterestGroupAdAuctionData({
    456    coordinatorOrigin: await BA.configureCoordinator(),
    457    seller: window.location.origin
    458  });
    459  assert_true(result.requestId !== null);
    460  assert_true(result.request.length > 0);
    461 
    462  let decoded = await BA.decodeInterestGroupData(result.request);
    463  let ig = validateWithOneIg(decoded);
    464  assert_equals(ig.browserSignals.joinCount, 2, 'joinCount');
    465  assert_equals(ig.browserSignals.bidCount, 1, 'bidCount');
    466 
    467  // RecencyMs is the # of milliseconds since the join. We can't exactly say
    468  // what it is, but it shouldn't be too huge.
    469  assert_true(typeof ig.browserSignals.recencyMs === 'number');
    470  assert_between_inclusive(
    471      ig.browserSignals.recencyMs, 0, 60000,
    472      'RecencyMs is between 0 and 60 seconds');
    473  // It's also supposed to be an integer.
    474  assert_equals(
    475      ig.browserSignals.recencyMs, Math.round(ig.browserSignals.recencyMs),
    476      'RecencyMs is an integer');
    477 
    478  // One win. The format here depends highly on whether full ads are used or
    479  // not.
    480  assert_true(
    481      ig.browserSignals.prevWins instanceof Array, 'prevWins is an array');
    482  assert_equals(ig.browserSignals.prevWins.length, 1, 'prevWins length');
    483  assert_true(
    484      ig.browserSignals.prevWins[0] instanceof Array,
    485      'prevWins[0] is an array');
    486  assert_equals(ig.browserSignals.prevWins[0].length, 2, 'prevWins[0] length');
    487 
    488  // prevWins[0][0] is the time delta in second again.
    489  let prevWinTime = ig.browserSignals.prevWins[0][0];
    490  assert_true(typeof prevWinTime === 'number');
    491  assert_between_inclusive(
    492      prevWinTime, 0, 60, 'prevWinTime is between 0 and 60 seconds');
    493  // It's also supposed to be an integer.
    494  assert_equals(
    495      prevWinTime, Math.round(prevWinTime), 'prevWinTime is an integer');
    496 
    497  // prevWins[0][1] is an ad object w/include-full-ads on (with renderURL,
    498  // metadata, and adRenderId).
    499  let prevWinAd = ig.browserSignals.prevWins[0][1];
    500  assert_equals(
    501      prevWinAd.renderURL, igConfig.ads[0].renderURL, 'prevWin ad renderURL');
    502  assert_equals(prevWinAd.metadata, '"ada"', 'prevWin ad metadata');
    503  assert_equals(prevWinAd.adRenderId, 'a', 'prevWin ad adRenderId');
    504 }, 'getInterestGroupAdAuctionData() browserSignals with include-full-ads');
    505 
    506 subsetTest(promise_test, async test => {
    507  const uuid = generateUuid(test);
    508 
    509  const igTemplate = makeTemplateIgConfig(uuid);
    510  await joinInterestGroup(test, uuid, {...igTemplate, name: 'first'});
    511  await joinInterestGroup(test, uuid, {...igTemplate, name: 'second'});
    512 
    513  const result = await navigator.getInterestGroupAdAuctionData({
    514    coordinatorOrigin: await BA.configureCoordinator(),
    515    seller: window.location.origin
    516  });
    517  assert_true(result.requestId !== null);
    518  assert_true(result.request.length > 0);
    519 
    520  let decoded = await BA.decodeInterestGroupData(result.request);
    521  assert_equals(decoded.message.version, 0);
    522  assert_equals(decoded.message.publisher, window.location.hostname);
    523  assert_equals(typeof decoded.message.generationId, 'string');
    524 
    525  let origin = window.location.origin;
    526  let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
    527  assert_array_equals(igMapKeys, [origin]);
    528  assert_equals(decoded.message.interestGroups[origin].length, 2);
    529  let names = [
    530    decoded.message.interestGroups[origin][0].name,
    531    decoded.message.interestGroups[origin][1].name
    532  ];
    533  assert_array_equals(names.sort(), ['first', 'second']);
    534 }, 'getInterestGroupAdAuctionData() with multiple interest groups');
    535 
    536 async function joinCrossOriginIG(test, uuid, origin, name) {
    537  let iframe = await createIframe(test, origin, 'join-ad-interest-group');
    538  await runInFrame(
    539      test, iframe,
    540      `await joinInterestGroup(test_instance, "${uuid}", {name: "${name}"});`);
    541 }
    542 
    543 subsetTest(promise_test, async test => {
    544  const uuid = generateUuid(test);
    545 
    546  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN1, 'o1');
    547  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN2, 'o2');
    548  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN3, 'o3');
    549  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN4, 'o4');
    550 
    551  const result = await navigator.getInterestGroupAdAuctionData({
    552    coordinatorOrigin: await BA.configureCoordinator(),
    553    seller: window.location.origin
    554  });
    555  assert_true(result.requestId !== null);
    556  assert_true(result.request.length > 0);
    557 
    558  let decoded = await BA.decodeInterestGroupData(result.request);
    559  assert_equals(decoded.message.version, 0);
    560  assert_equals(decoded.message.publisher, window.location.hostname);
    561  assert_equals(typeof decoded.message.generationId, 'string');
    562  let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
    563  assert_array_equals(
    564      igMapKeys.sort(),
    565      [OTHER_ORIGIN1, OTHER_ORIGIN2, OTHER_ORIGIN3, OTHER_ORIGIN4].sort());
    566  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN1].length, 1);
    567  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN1][0].name, 'o1');
    568  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2].length, 1);
    569  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2][0].name, 'o2');
    570  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3].length, 1);
    571  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3][0].name, 'o3');
    572  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN4].length, 1);
    573  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN4][0].name, 'o4');
    574 }, 'getInterestGroupAdAuctionData() with multiple buyers');
    575 
    576 subsetTest(promise_test, async test => {
    577  const uuid = generateUuid(test);
    578 
    579  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN1, 'o1');
    580  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN2, 'o2');
    581  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN3, 'o3');
    582  await joinCrossOriginIG(test, uuid, OTHER_ORIGIN4, 'o4');
    583 
    584  let config = {
    585    coordinatorOrigin: await BA.configureCoordinator(),
    586    seller: window.location.origin,
    587    perBuyerConfig: {},
    588    requestSize: 5000
    589  };
    590  config.perBuyerConfig[OTHER_ORIGIN2] = {};
    591  config.perBuyerConfig[OTHER_ORIGIN3] = {};
    592  const result = await navigator.getInterestGroupAdAuctionData(config);
    593  assert_true(result.requestId !== null);
    594  assert_true(result.request.length > 0);
    595 
    596  let decoded = await BA.decodeInterestGroupData(result.request);
    597  assert_equals(decoded.message.version, 0);
    598  assert_equals(decoded.message.publisher, window.location.hostname);
    599  assert_equals(typeof decoded.message.generationId, 'string');
    600  let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
    601  assert_array_equals(igMapKeys.sort(), [OTHER_ORIGIN2, OTHER_ORIGIN3].sort());
    602  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2].length, 1);
    603  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2][0].name, 'o2');
    604  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3].length, 1);
    605  assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3][0].name, 'o3');
    606 }, 'getInterestGroupAdAuctionData() uses perBuyerConfig to select buyers');
    607 
    608 subsetTest(promise_test, async test => {
    609  const uuid = generateUuid(test);
    610  await joinInterestGroup(test, uuid);
    611 
    612  const result = await navigator.getInterestGroupAdAuctionData({
    613    coordinatorOrigin: await BA.configureCoordinator(),
    614    seller: window.location.origin
    615  });
    616  assert_true(result.requestId !== null);
    617  assert_true(result.request.length > 0);
    618 
    619  let decoded = await BA.decodeInterestGroupData(result.request);
    620 
    621  assert_own_property(decoded.message, 'enforceKAnon');
    622  assert_equals(decoded.message.enforceKAnon, true);
    623 }, 'getInterestGroupAdAuctionData() requests k-anon.');
    624 
    625 
    626 /*************************************************************************
    627 * Tests for the multi-seller variant of the API
    628 *************************************************************************/
    629 
    630 async function validateForSeller(adAuctionData, seller) {
    631  assert_equals(adAuctionData.seller, seller);
    632  assert_not_own_property(adAuctionData, 'error');
    633  assert_own_property(adAuctionData, 'request');
    634  assert_true(adAuctionData.request.length > 0);
    635 
    636  let decoded = await BA.decodeInterestGroupData(adAuctionData.request);
    637  let ig = validateWithOneIg(decoded);
    638 
    639  assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
    640  assert_array_equals(ig.ads, ['a', 'b']);
    641 
    642  assert_true(ig.components instanceof Array);
    643  assert_array_equals(ig.components, ['ca', 'cb', 'cc']);
    644 
    645  assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
    646  assert_equals(ig.userBiddingSignals, '14');
    647 }
    648 
    649 subsetTest(promise_test, async test => {
    650  const uuid = generateUuid(test);
    651  const igConfig = makeTemplateIgConfig(uuid);
    652  await joinInterestGroup(test, uuid, igConfig);
    653 
    654  const result = await navigator.getInterestGroupAdAuctionData({
    655    sellers: [{
    656      coordinatorOrigin: await BA.configureCoordinator(),
    657      seller: window.location.origin,
    658    }]
    659  });
    660 
    661  assert_true(result.requestId !== null);
    662  assert_own_property(result, 'requests');
    663  assert_equals(result.requests.length, 1);
    664  await validateForSeller(result.requests[0], window.location.origin);
    665 }, 'getInterestGroupAdAuctionData() multi-seller with single seller');
    666 
    667 subsetTest(promise_test, async test => {
    668  const uuid = generateUuid(test);
    669  const igConfig = makeTemplateIgConfig(uuid);
    670  await joinInterestGroup(test, uuid, igConfig);
    671 
    672  const result = await navigator.getInterestGroupAdAuctionData({
    673    sellers: [{
    674        coordinatorOrigin: await BA.configureCoordinator(),
    675        seller: window.location.origin,
    676      }, {
    677        coordinatorOrigin: await BA.configureCoordinator(),
    678        seller: OTHER_ORIGIN1,
    679    }]
    680  });
    681 
    682  assert_true(result.requestId !== null);
    683  assert_own_property(result, 'requests');
    684  assert_equals(result.requests.length, 2, JSON.stringify(result));
    685  result.requests.sort((a,b)=> (a.seller < b.seller ? -1 : +(a.seller > b.seller)));
    686 
    687  await validateForSeller(result.requests[0], OTHER_ORIGIN1);
    688  await validateForSeller(result.requests[1], window.location.origin);
    689 
    690  assert_not_equals(result.requests[0].request.toString(), result.requests[1].request.toString());
    691 }, 'getInterestGroupAdAuctionData() multi-seller with multiple sellers - valid');
    692 
    693 subsetTest(promise_test, async test => {
    694  const uuid = generateUuid(test);
    695  const igConfig = makeTemplateIgConfig(uuid);
    696  await joinInterestGroup(test, uuid, igConfig);
    697 
    698  const result = await navigator.getInterestGroupAdAuctionData({
    699    sellers: [{
    700        coordinatorOrigin: await BA.configureCoordinator(),
    701        seller: window.location.origin,
    702      }, {
    703        coordinatorOrigin: "https://invalid.coordinator.test/",
    704        seller: OTHER_ORIGIN1,
    705    }]
    706  });
    707 
    708  assert_true(result.requestId !== null);
    709  assert_own_property(result, 'requests');
    710  assert_equals(result.requests.length, 2, JSON.stringify(result));
    711  result.requests.sort((a,b)=> (a.seller < b.seller ? -1 : +(a.seller > b.seller)));
    712 
    713  assert_equals(result.requests[0].seller, OTHER_ORIGIN1);
    714  assert_own_property(result.requests[0], 'error');
    715  assert_not_own_property(result.requests[0], 'request');
    716 
    717  await validateForSeller(result.requests[1], window.location.origin);
    718 }, 'getInterestGroupAdAuctionData() multi-seller with multiple sellers - one invalid coordinator');
    719 
    720 subsetTest(promise_test, async test => {
    721  const uuid = generateUuid(test);
    722  const igConfig = makeTemplateIgConfig(uuid);
    723  await joinInterestGroup(test, uuid, igConfig);
    724 
    725  await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
    726    sellers: [{
    727        coordinatorOrigin: await BA.configureCoordinator(),
    728        seller: window.location.origin,
    729      }, {
    730        coordinatorOrigin: await BA.configureCoordinator(),
    731        seller: "http://not.secure.test/",
    732    }]
    733  }));
    734 }, 'getInterestGroupAdAuctionData() multi-seller with multiple sellers - one invalid seller');
    735 
    736 subsetTest(promise_test, async test => {
    737  const uuid = generateUuid(test);
    738  const igConfig = makeTemplateIgConfig(uuid);
    739  await joinInterestGroup(test, uuid, igConfig);
    740 
    741  await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
    742  }));
    743 }, 'getInterestGroupAdAuctionData() one of "seller" and "sellers" is required');
    744 
    745 subsetTest(promise_test, async test => {
    746  const uuid = generateUuid(test);
    747  const igConfig = makeTemplateIgConfig(uuid);
    748  await joinInterestGroup(test, uuid, igConfig);
    749 
    750  await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
    751    seller: window.location.origin,
    752    sellers: [{
    753      coordinatorOrigin: await BA.configureCoordinator(),
    754      seller: window.location.origin,
    755    }]
    756  }));
    757 }, 'getInterestGroupAdAuctionData() doesn\'t allow "seller" and "sellers" fields');
    758 
    759 subsetTest(promise_test, async test => {
    760  const uuid = generateUuid(test);
    761  const igConfig = makeTemplateIgConfig(uuid);
    762  await joinInterestGroup(test, uuid, igConfig);
    763 
    764  await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
    765    coordinatorOrigin: window.location.origin,
    766    sellers: [{
    767      coordinatorOrigin: await BA.configureCoordinator(),
    768      seller: window.location.origin,
    769    }]
    770  }));
    771 }, 'getInterestGroupAdAuctionData() doesn\'t allow "coordinatorOrigin" and "sellers" fields');
    772 
    773 subsetTest(promise_test, async test => {
    774  const uuid = generateUuid(test);
    775  const igConfig = makeTemplateIgConfig(uuid);
    776  await joinInterestGroup(test, uuid, igConfig);
    777 
    778  await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
    779    sellers: [{
    780      coordinatorOrigin: await BA.configureCoordinator(),
    781      seller: window.location.origin,
    782    }, {
    783      coordinatorOrigin: await BA.configureCoordinator(),
    784      seller: window.location.origin,
    785    }
    786  ]
    787  }));
    788 }, 'getInterestGroupAdAuctionData() doesn\'t allow duplicate sellers in "sellers" field');
    789 
    790 subsetTest(promise_test, async test => {
    791  const uuid = generateUuid(test);
    792  const igConfig = makeTemplateIgConfig(uuid);
    793  await joinInterestGroup(test, uuid, igConfig);
    794 
    795  const result = await navigator.getInterestGroupAdAuctionData({
    796    sellers: []
    797  });
    798  assert_equals(result.requestId, "");
    799  assert_array_equals(result.requests, []);
    800 }, 'getInterestGroupAdAuctionData() with no sellers');