clear-origin-joined-ad-interest-groups.https.window.js (14218B)
1 // META: script=/resources/testdriver.js 2 // META: script=/resources/testdriver-vendor.js 3 // META: script=/common/utils.js 4 // META: script=resources/fledge-util.sub.js 5 // META: script=/common/subset-tests.js 6 // META: timeout=long 7 // META: variant=?1-4 8 // META: variant=?5-8 9 // META: variant=?9-12 10 // META: variant=?13-last 11 12 "use strict"; 13 14 /////////////////////////////////////////////////////////////////////////////// 15 // Basic tests with no interest groups joined. 16 /////////////////////////////////////////////////////////////////////////////// 17 18 subsetTest(promise_test, async test => { 19 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin); 20 }, 'clearOriginJoinedAdInterestGroups(), no groups joined, no group list.'); 21 22 subsetTest(promise_test, async test => { 23 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin, []); 24 }, 'clearOriginJoinedAdInterestGroups(), no groups joined, group list.'); 25 26 subsetTest(promise_test, async test => { 27 try { 28 await navigator.clearOriginJoinedAdInterestGroups(OTHER_ORIGIN1); 29 throw 'Exception unexpectedly not thrown'; 30 } catch (e) { 31 if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') { 32 throw 'Wrong exception thrown: ' + e.toString(); 33 } 34 } 35 }, 'clearOriginJoinedAdInterestGroups(), cross-origin, no groups joined, no group list.'); 36 37 subsetTest(promise_test, async test => { 38 try { 39 await navigator.clearOriginJoinedAdInterestGroups(OTHER_ORIGIN1, []); 40 throw 'Exception unexpectedly not thrown'; 41 } catch (e) { 42 if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') { 43 throw 'Wrong exception thrown: ' + e.toString(); 44 } 45 } 46 }, 'clearOriginJoinedAdInterestGroups(), cross-origin, no groups joined, group list.'); 47 48 /////////////////////////////////////////////////////////////////////////////// 49 // Tests where interest groups are all owned by document.location.origin. 50 /////////////////////////////////////////////////////////////////////////////// 51 52 subsetTest(promise_test, async test => { 53 const uuid = generateUuid(test); 54 55 // Join 3 groups. 56 await joinInterestGroup(test, uuid); 57 await joinInterestGroup(test, uuid, {name: 'group 2'}); 58 await joinInterestGroup(test, uuid, {name: 'group 3'}); 59 60 // A single clear should leave them all. 61 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin); 62 63 // Confirm that they were left. 64 await runBasicFledgeTestExpectingNoWinner(test, uuid); 65 }, 'clearOriginJoinedAdInterestGroups(), multiple groups joined, no group list.'); 66 67 subsetTest(promise_test, async test => { 68 const uuid = generateUuid(test); 69 70 let group1ReportURL = createBidderReportURL(uuid, /*id=*/'1'); 71 let group2ReportURL = createBidderReportURL(uuid, /*id=*/'2'); 72 let group3ReportURL = createBidderReportURL(uuid, /*id=*/'3'); 73 74 // Join 3 groups, with distinct report URLs and increasing bid amounts. 75 // Set "executionMode" to "group-by-origin" for two of them, since cross-origin 76 // leaves removes all groups joined from the other origin with that execution 77 // mode. Since clearOriginJoinedAdInterestGroups() only leaves interest 78 // groups joined on the current origin, the executionMode should not matter. 79 await joinInterestGroup( 80 test, uuid, 81 { name: 'group 1', 82 executionMode: 'group-by-origin', 83 biddingLogicURL: createBiddingScriptURL( 84 { bid: 1, reportWin: `sendReportTo("${group1ReportURL}");`})}); 85 await joinInterestGroup( 86 test, uuid, 87 { name: 'group 2', 88 biddingLogicURL: createBiddingScriptURL( 89 { bid: 2, reportWin: `sendReportTo("${group2ReportURL}");`})}); 90 await joinInterestGroup( 91 test, uuid, 92 { name: 'group 3', 93 executionMode: 'group-by-origin', 94 biddingLogicURL: createBiddingScriptURL( 95 { bid: 3, reportWin: `sendReportTo("${group3ReportURL}");`})}); 96 97 // Group 3 should win an auction, since it bids the most. 98 await runBasicFledgeAuctionAndNavigate(test, uuid); 99 await waitForObservedRequests( 100 uuid, [group3ReportURL, createSellerReportURL(uuid)]); 101 await fetch(createCleanupURL(uuid)); 102 103 // Clear, leaving group 1 in place, and run an auction, which group 1 should win. 104 await navigator.clearOriginJoinedAdInterestGroups( 105 window.location.origin, ['group 1']); 106 await runBasicFledgeAuctionAndNavigate(test, uuid); 107 await waitForObservedRequests( 108 uuid, [group1ReportURL, createSellerReportURL(uuid)]); 109 110 // Clear with an empty list, which should leave group 1 as well. Verify it can't 111 // win an auction. 112 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin, []); 113 await runBasicFledgeTestExpectingNoWinner(test, uuid); 114 }, 'clearOriginJoinedAdInterestGroups(), multiple groups joined, group list.'); 115 116 subsetTest(promise_test, async test => { 117 const uuid = generateUuid(test); 118 119 // Join an interest group in a same-origin top-level window. 120 await joinInterestGroupInTopLevelWindow(test, uuid, window.location.origin); 121 122 // Make sure it was joined. 123 await runBasicFledgeTestExpectingWinner(test, uuid); 124 125 // Call "clearOriginJoinedAdInterestGroups()", which should leave the interest 126 // group, since it was joined from a same-origin main frame. 127 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin); 128 129 // Make sure group was left. 130 await runBasicFledgeTestExpectingNoWinner(test, uuid); 131 }, 'clearOriginJoinedAdInterestGroups(), group joined from same-origin top-level context.'); 132 133 subsetTest(promise_test, async test => { 134 const uuid = generateUuid(test); 135 136 // Create top-level browsing context for another origin, and have it join an 137 // interest group owned by this document's origin. 138 let topLevelWindow = await createTopLevelWindow(test, OTHER_ORIGIN1); 139 let interestGroup = JSON.stringify( 140 createInterestGroupForOrigin(uuid, window.location.origin)); 141 await runInFrame(test, topLevelWindow, 142 `await joinCrossOriginInterestGroup(test_instance, "${uuid}", 143 "${window.location.origin}", 144 ${interestGroup});`); 145 146 // Call "clearOriginJoinedAdInterestGroups()", which should not leave the interest 147 // group, since it was joined from a cross-origin main frame. 148 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin); 149 150 // Make sure group was not left. 151 await runBasicFledgeTestExpectingWinner(test, uuid); 152 }, 'clearOriginJoinedAdInterestGroups(), group joined from cross-origin top-level context.'); 153 154 subsetTest(promise_test, async test => { 155 const uuid = generateUuid(test); 156 157 await joinInterestGroup(test, uuid); 158 159 // In a cross-origin iframe, call clearOriginJoinedAdInterestGroups() both for the 160 // iframe's origin and for the main frame's origin. The latter should throw an 161 // exception, and neither should manage to leave the interest group. 162 let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group'); 163 await runInFrame(test, iframe, 164 `// Call clearOriginJoinedAdInterestGroups() with the iframe's origin. 165 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin); 166 try { 167 // Call clearOriginJoinedAdInterestGroups() with the main frame's origin. 168 await navigator.clearOriginJoinedAdInterestGroups("${window.location.origin}"); 169 } catch (e) { 170 assert_true(e instanceof DOMException, "DOMException thrown"); 171 assert_equals(e.name, "NotAllowedError", "NotAllowedError DOMException thrown"); 172 return {result: "success"}; 173 } 174 throw "Exception unexpectedly not thrown";`); 175 176 // Confirm that the interest group was not left. 177 await runBasicFledgeTestExpectingWinner(test, uuid); 178 }, "clearOriginJoinedAdInterestGroups(), cross-origin iframe tries to leave parent frame's group."); 179 180 subsetTest(promise_test, async test => { 181 const uuid = generateUuid(test); 182 183 // The possible results of calling clearOriginJoinedAdInterestGroups(): 184 185 // Doesn't throw an exception. 186 const noExpectionURL = createTrackerURL(origin, uuid, "track_get", "no_exception"); 187 // Throws the exception it's expected to. 188 const exceptionURL = createTrackerURL(origin, uuid, "track_get", "exception"); 189 // Throws the wrong exception. 190 const badExpectionURL = createTrackerURL(origin, uuid, "track_get", "bad_exception"); 191 192 // Create a render URL that calls clearOriginJoinedAdInterestGroups() and 193 // then requests one of the above tracking URLs, based on the resulting 194 // behaviot. 195 const renderURL = createRenderURL( 196 uuid, 197 `async function TryClear() { 198 try { 199 await navigator.clearOriginJoinedAdInterestGroups( 200 "${window.location.origin}"); 201 await fetch("${noExpectionURL}"); 202 } catch (e) { 203 if (e instanceof DOMException && e.name === "NotAllowedError") { 204 await fetch("${exceptionURL}"); 205 } else { 206 await fetch("${badExpectionURL}"); 207 } 208 } 209 } 210 211 TryClear();`); 212 213 await joinInterestGroup( 214 test, uuid, 215 {ads: [{ renderURL: renderURL}]}); 216 217 await runBasicFledgeAuctionAndNavigate(test, uuid); 218 219 // This should wait until the clear call has thrown an exception. 220 await waitForObservedRequests( 221 uuid, 222 [createBidderReportURL(uuid), createSellerReportURL(uuid), exceptionURL]); 223 224 // Check the interest group was not left. 225 await runBasicFledgeTestExpectingWinner(test, uuid); 226 }, 'clearOriginJoinedAdInterestGroups() in ad fenced frame throws an exception.'); 227 228 /////////////////////////////////////////////////////////////////////////////// 229 // Tests where some interest groups are owned by another origin. 230 /////////////////////////////////////////////////////////////////////////////// 231 232 subsetTest(promise_test, async test => { 233 const uuid = generateUuid(test); 234 235 // Join interest group in iframe and make sure it was joined. 236 let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group'); 237 await runInFrame(test, iframe, 238 `await joinInterestGroup(test_instance, "${uuid}"); 239 await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`); 240 241 // In the main frame, Call clearOriginJoinedAdInterestGroups() for both the main 242 // frame's origin, and the origin of the iframe / joined interest group. Neither 243 // should leave the group, and the second should throw. 244 await navigator.clearOriginJoinedAdInterestGroups(window.location.origin); 245 try { 246 await navigator.clearOriginJoinedAdInterestGroups(OTHER_ORIGIN1); 247 throw 'Exception unexpectedly not thrown'; 248 } catch (e) { 249 if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') { 250 throw 'Wrong exception thrown: ' + e.toString(); 251 } 252 } 253 254 // In an iframe, confirm the group was never left. 255 await runInFrame(test, iframe, 256 `await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`); 257 }, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined in iframe, try to clear in main frame.'); 258 259 subsetTest(promise_test, async test => { 260 const uuid = generateUuid(test); 261 262 let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group'); 263 await runInFrame(test, iframe, 264 `await joinInterestGroup(test_instance, "${uuid}"); 265 266 // Confirm that trying to clear the interest group using the main frame's 267 // origin throws, and does not leave the group. 268 try { 269 await navigator.clearOriginJoinedAdInterestGroups("${window.location.origin}"); 270 throw 'Exception unexpectedly not thrown'; 271 } catch (e) { 272 if (!(e instanceof DOMException) || e.name !== 'NotAllowedError') { 273 throw 'Wrong exception thrown: ' + e.toString(); 274 } 275 } 276 await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`); 277 }, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined in iframe, clear call in iframe passing main frame origin.'); 278 279 subsetTest(promise_test, async test => { 280 const uuid = generateUuid(test); 281 282 let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group'); 283 await runInFrame(test, iframe, 284 `await joinInterestGroup(test_instance, "${uuid}"); 285 286 // Clear call with the origin of the cross-origin iframe. 287 // This should successfully leave the interest group. 288 await navigator.clearOriginJoinedAdInterestGroups("${OTHER_ORIGIN1}"); 289 290 // Verify the group was left. 291 await runBasicFledgeTestExpectingNoWinner(test_instance, "${uuid}");`); 292 }, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined in iframe, clear call in iframe passing iframe origin.'); 293 294 subsetTest(promise_test, async test => { 295 const uuid = generateUuid(test); 296 297 // Join an OTHER_ORIGIN1 interest group in an OTHER_ORIGIN1 main frame. 298 let topLevelWindow = await createTopLevelWindow(test, OTHER_ORIGIN1); 299 await runInFrame(test, topLevelWindow, 300 `await joinInterestGroup(test_instance, "${uuid}");`); 301 302 let iframe = await createIframe(test, OTHER_ORIGIN1, 'join-ad-interest-group'); 303 304 await runInFrame(test, iframe, 305 `// Clear call from an OTHER_ORIGIN1 iframe on a different 306 // origin's main frame. This should not clear the interest 307 // group that was just joined, because the joining origin 308 // does not match. 309 await navigator.clearOriginJoinedAdInterestGroups("${OTHER_ORIGIN1}"); 310 311 // Verify the group was not left. 312 await runBasicFledgeTestExpectingWinner(test_instance, "${uuid}");`); 313 }, 'clearOriginJoinedAdInterestGroups(). Cross-origin interest group joined from another joining origin, clear call in iframe.');