summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fledge/tentative/clear-origin-joined-ad-interest-groups.https.window.js
blob: 7d6e715ac45d979b541cfb50f2044ef34178df26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
// 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-8
// META: variant=?9-12
// META: variant=?13-last

"use strict;"

///////////////////////////////////////////////////////////////////////////////
// Basic tests with no interest groups joined.
///////////////////////////////////////////////////////////////////////////////

subsetTest(promise_test, async test => {
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin);
}, 'clearOriginJoinedAdInterestGroups(), no groups joined, no group list.');

subsetTest(promise_test, async test => {
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin, []);
}, 'clearOriginJoinedAdInterestGroups(), no groups joined, group list.');

subsetTest(promise_test, async test => {
  try {
    await navigator.clearOriginJoinedAdInterestGroups(OTHER_ORIGIN1);
    throw 'Exception unexpectedly not thrown';
  } catch (e) {
    if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') {
      throw 'Wrong exception thrown: ' + e.toString();
    }
  }
}, 'clearOriginJoinedAdInterestGroups(), cross-origin, no groups joined, no group list.');

subsetTest(promise_test, async test => {
  try {
    await navigator.clearOriginJoinedAdInterestGroups(OTHER_ORIGIN1, []);
    throw 'Exception unexpectedly not thrown';
  } catch (e) {
    if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') {
      throw 'Wrong exception thrown: ' + e.toString();
    }
  }
}, 'clearOriginJoinedAdInterestGroups(), cross-origin, no groups joined, group list.');

///////////////////////////////////////////////////////////////////////////////
// Tests where interest groups are all owned by document.location.origin.
///////////////////////////////////////////////////////////////////////////////

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  // Join 3 groups.
  await joinInterestGroup(test, uuid);
  await joinInterestGroup(test, uuid, {name: 'group 2'});
  await joinInterestGroup(test, uuid, {name: 'group 3'});

  // A single clear should leave them all.
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin);

  // Confirm that they were left.
  await runBasicFledgeTestExpectingNoWinner(test, uuid);
}, 'clearOriginJoinedAdInterestGroups(), multiple groups joined, no group list.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  let group1ReportURL = createBidderReportURL(uuid, /*id=*/'1');
  let group2ReportURL = createBidderReportURL(uuid, /*id=*/'2');
  let group3ReportURL = createBidderReportURL(uuid, /*id=*/'3');

  // Join 3 groups, with distinct report URLs and increasing bid amounts.
  // Set "executionMode" to "group-by-origin" for two of them, since cross-origin
  // leaves removes all groups joined from the other origin with that execution
  // mode. Since clearOriginJoinedAdInterestGroups() only leaves interest
  // groups joined on the current origin, the executionMode should not matter.
  await joinInterestGroup(
      test, uuid,
      { name: 'group 1',
        executionMode: 'group-by-origin',
        biddingLogicURL: createBiddingScriptURL(
            { bid: 1, reportWin: `sendReportTo("${group1ReportURL}");`})});
  await joinInterestGroup(
      test, uuid,
      { name: 'group 2',
        biddingLogicURL: createBiddingScriptURL(
            { bid: 2, reportWin: `sendReportTo("${group2ReportURL}");`})});
  await joinInterestGroup(
      test, uuid,
      { name: 'group 3',
        executionMode: 'group-by-origin',
        biddingLogicURL: createBiddingScriptURL(
            { bid: 3, reportWin: `sendReportTo("${group3ReportURL}");`})});

  // Group 3 should win an auction, since it bids the most.
  await runBasicFledgeAuctionAndNavigate(test, uuid);
  await waitForObservedRequests(
      uuid, [group3ReportURL, createSellerReportURL(uuid)]);
  await fetch(createCleanupURL(uuid));

  // Clear, leaving group 1 in place, and run an auction, which group 1 should win.
  await navigator.clearOriginJoinedAdInterestGroups(
      window.location.origin, ['group 1']);
  await runBasicFledgeAuctionAndNavigate(test, uuid);
  await waitForObservedRequests(
      uuid, [group1ReportURL, createSellerReportURL(uuid)]);

  // Clear with an empty list, which should leave group 1 as well. Verify it can't
  // win an auction.
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin, []);
  await runBasicFledgeTestExpectingNoWinner(test, uuid);
}, 'clearOriginJoinedAdInterestGroups(), multiple groups joined, group list.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  // Join an interest group in a same-origin top-level window.
  await joinInterestGroupInTopLevelWindow(test, uuid, window.location.origin);

  // Make sure it was joined.
  await runBasicFledgeTestExpectingWinner(test, uuid);

  // Call "clearOriginJoinedAdInterestGroups()", which should leave the interest
  // group, since it was joined from a same-origin main frame.
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin);

  // Make sure group was left.
  await runBasicFledgeTestExpectingNoWinner(test, uuid);
}, 'clearOriginJoinedAdInterestGroups(), group joined from same-origin top-level context.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  // Create top-level browsing context for another origin, and have it join an
  // interest group owned by this document's origin.
  let topLevelWindow = await createTopLevelWindow(test, OTHER_ORIGIN1);
  let interestGroup = JSON.stringify(
      createInterestGroupForOrigin(uuid, window.location.origin));
  await runInFrame(test, topLevelWindow,
                   `await joinCrossOriginInterestGroup(test_instance, "${uuid}",
                                                       "${window.location.origin}",
                                                       ${interestGroup});`);

  // Call "clearOriginJoinedAdInterestGroups()", which should not leave the interest
  // group, since it was joined from a cross-origin main frame.
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin);

  // Make sure group was not left.
  await runBasicFledgeTestExpectingWinner(test, uuid);
}, 'clearOriginJoinedAdInterestGroups(), group joined from cross-origin top-level context.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  await joinInterestGroup(test, uuid);

  // In a cross-origin iframe, call clearOriginJoinedAdInterestGroups() both for the
  // iframe's origin and for the main frame's origin. The latter should throw an
  // exception, and neither should manage to leave the interest group.
  let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group');
  await runInFrame(test, iframe,
                   `// Call clearOriginJoinedAdInterestGroups() with the iframe's origin.
                    await navigator.clearOriginJoinedAdInterestGroups(window.location.origin);
                    try {
                      // Call clearOriginJoinedAdInterestGroups() with the main frame's origin.
                      await navigator.clearOriginJoinedAdInterestGroups("${window.location.origin}");
                    } catch (e) {
                      assert_true(e instanceof DOMException, "DOMException thrown");
                      assert_equals(e.name, "NotAllowedError", "NotAllowedError DOMException thrown");
                      return {result: "success"};
                    }
                    throw "Exception unexpectedly not thrown";`);

  // Confirm that the interest group was not left.
  await runBasicFledgeTestExpectingWinner(test, uuid);
}, "clearOriginJoinedAdInterestGroups(), cross-origin iframe tries to leave parent frame's group.");

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  // The possible results of calling clearOriginJoinedAdInterestGroups():

  // Doesn't throw an exception.
  const noExpectionURL = createTrackerURL(origin, uuid, "track_get", "no_exception");
  // Throws the exception it's expected to.
  const exceptionURL = createTrackerURL(origin, uuid, "track_get", "exception");
  // Throws the wrong exception.
  const badExpectionURL = createTrackerURL(origin, uuid, "track_get", "bad_exception");

  // Create a render URL that calls clearOriginJoinedAdInterestGroups() and
  // then requests one of the above tracking URLs, based on the resulting
  // behaviot.
  const renderURL = createRenderURL(
      uuid,
      `async function TryClear() {
         try {
           await navigator.clearOriginJoinedAdInterestGroups(
               "${window.location.origin}");
           await fetch("${noExpectionURL}");
         } catch (e) {
           if (e instanceof DOMException && e.name === "NotAllowedError") {
             await fetch("${exceptionURL}");
           } else {
             await fetch("${badExpectionURL}");
           }
         }
       }

       TryClear();`);

  await joinInterestGroup(
      test, uuid,
      {ads: [{ renderURL: renderURL}]});

  await runBasicFledgeAuctionAndNavigate(test, uuid);

  // This should wait until the clear call has thrown an exception.
  await waitForObservedRequests(
      uuid,
      [createBidderReportURL(uuid), createSellerReportURL(uuid), exceptionURL]);

  // Check the interest group was not left.
  await runBasicFledgeTestExpectingWinner(test, uuid);
}, 'clearOriginJoinedAdInterestGroups() in ad fenced frame throws an exception.');

///////////////////////////////////////////////////////////////////////////////
// Tests where some interest groups are owned by another origin.
///////////////////////////////////////////////////////////////////////////////

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  // Join interest group in iframe and make sure it was joined.
  let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group');
  await runInFrame(test, iframe,
                   `await joinInterestGroup(test_instance, "${uuid}");
                    await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`);

  // In the main frame, Call clearOriginJoinedAdInterestGroups() for both the main
  // frame's origin, and the origin of the iframe / joined interest group. Neither
  // should leave the group, and the second should throw.
  await navigator.clearOriginJoinedAdInterestGroups(window.location.origin);
  try {
    await navigator.clearOriginJoinedAdInterestGroups(OTHER_ORIGIN1);
    throw 'Exception unexpectedly not thrown';
  } catch (e) {
    if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') {
      throw 'Wrong exception thrown: ' + e.toString();
    }
  }

  // In an iframe, confirm the group was never left.
  await runInFrame(test, iframe,
      `await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`);
}, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined in iframe, try to clear in main frame.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group');
  await runInFrame(test, iframe,
                   `await joinInterestGroup(test_instance, "${uuid}");

                    // Confirm that trying to clear the interest group using the main frame's
                    // origin throws, and does not leave the group.
                    try {
                      await navigator.clearOriginJoinedAdInterestGroups("${window.location.origin}");
                      throw 'Exception unexpectedly not thrown';
                    } catch (e) {
                      if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') {
                        throw 'Wrong exception thrown: ' + e.toString();
                      }
                    }
                    await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`);
}, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined in iframe, clear call in iframe passing main frame origin.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group');
  await runInFrame(test, iframe,
                   `await joinInterestGroup(test_instance, "${uuid}");

                    // Clear call with the origin of the cross-origin iframe.
                    // This should successfully leave the interest group.
                    await navigator.clearOriginJoinedAdInterestGroups("${OTHER_ORIGIN1}");

                    // Verify the group was left.
                    await runBasicFledgeTestExpectingNoWinner(test_instance, "${uuid}");`);
}, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined in iframe, clear call in iframe passing iframe origin.');

subsetTest(promise_test, async test => {
  const uuid = generateUuid(test);

  // Join an OTHER_ORIGIN1 interest group in an OTHER_ORIGIN1 main frame.
  let topLevelWindow = await createTopLevelWindow(test, OTHER_ORIGIN1);
  await runInFrame(test, topLevelWindow,
                   `await joinInterestGroup(test_instance, "${uuid}");`);

  let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group');

  await runInFrame(test, iframe,
                   `// Clear call from an OTHER_ORIGIN1 iframe on a different
                    // origin's main frame. This should not clear the interest
                    // group that was just joined, because the joining origin
                    // does not match.
                    await navigator.clearOriginJoinedAdInterestGroups("${OTHER_ORIGIN1}");

                    // Verify the group was not left.
                    await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`);
}, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined from another joining origin, clear call in iframe.');