blob: c3c97d60c614424262590027d415132ff8d8e756 [file] [log] [blame]
// 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-10
// META: variant=?11-20
// META: variant=?21-30
// META: variant=?31-40
// META: variant=?41-50
// META: variant=?51-60
// META: variant=?61-70
// META: variant=?71-80
// META: variant=?81-last
"use strict;"
// These tests are focused on joinAdInterestGroup() and leaveAdInterestGroup().
// Most join tests do not run auctions, but instead only check the result of
// the returned promise, since testing that interest groups are actually
// joined, and that each interestGroup field behaves as intended, are covered
// by other tests.
// Minimal fields needed for a valid interest group. Used in most test cases.
const BASE_INTEREST_GROUP = {
owner: window.location.origin,
name: 'default name',
}
// Each test case attempts to join and then leave an interest group, checking
// if any exceptions are thrown from either operation.
const SIMPLE_JOIN_LEAVE_TEST_CASES = [
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: null
},
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: {}
},
// Basic success test case.
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: BASE_INTEREST_GROUP
},
// "owner" tests
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: { name: 'default name' }
},
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: { ...BASE_INTEREST_GROUP,
owner: null}
},
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: { ...BASE_INTEREST_GROUP,
owner: window.location.origin.replace('https', 'http')}
},
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: { ...BASE_INTEREST_GROUP,
owner: window.location.origin.replace('https', 'wss')}
},
// Cross-origin joins and leaves are not allowed without .well-known
// permissions.
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: { ...BASE_INTEREST_GROUP,
owner: '{{hosts[][www]}}' }
},
// "name" tests
{ expectJoinSucces: false,
expectLeaveSucces: false,
interestGroup: { owner: window.location.origin }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
name: ''}
},
// "priority" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priority: 1}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priority: 0}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priority: -1.5}
},
// "priorityVector" tests
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priorityVector: null}
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priorityVector: 1}
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priorityVector: {a: 'apple'}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priorityVector: {}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priorityVector: {a: 1}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
priorityVector: {'a': 1, 'b': -4.5, 'a.b': 0}}
},
// "prioritySignalsOverrides" tests
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
prioritySignalsOverrides: null}
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
prioritySignalsOverrides: 1}
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
prioritySignalsOverrides: {a: 'apple'}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
prioritySignalsOverrides: {}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
prioritySignalsOverrides: {a: 1}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
prioritySignalsOverrides: {'a': 1, 'b': -4.5, 'a.b': 0}}
},
// "enableBiddingSignalsPrioritization" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
enableBiddingSignalsPrioritization: true}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
enableBiddingSignalsPrioritization: false}
},
// "biddingLogicURL" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingLogicURL: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingLogicURL: 'https://{{hosts[][www]}}/foo.js' }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingLogicURL: 'data:text/javascript,Foo' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingLogicURL: `${window.location.origin}/foo.js`}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingLogicURL: 'relative/path' }
},
// "biddingWasmHelperURL" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingWasmHelperURL: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingWasmHelperURL: 'https://{{hosts[][www]}}/foo.js' }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingWasmHelperURL: 'data:application/wasm,Foo' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingWasmHelperURL: `${window.location.origin}/foo.js`}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
biddingWasmHelperURL: 'relative/path' }
},
// "dailyUpdateUrl" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
dailyUpdateUrl: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
dailyUpdateUrl: 'https://{{hosts[][www]}}/foo.js' }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
dailyUpdateUrl: 'data:application/wasm,Foo' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
dailyUpdateUrl: `${window.location.origin}/foo.js`}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
dailyUpdateUrl: 'relative/path' }
},
// "executionMode" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
executionMode: 'compatibility' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
executionMode: 'groupByOrigin' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
executionMode: 'unknownValuesAreValid' }
},
// "trustedBiddingSignalsURL" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsURL: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsURL: 'https://{{hosts[][www]}}/foo.js' }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsURL: 'data:application/json,{}' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsURL: `${window.location.origin}/foo.js`}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsURL: 'relative/path' }
},
// "trustedBiddingSignalsKeys" tests
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsKeys: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsKeys: {}}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsKeys: []}
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
trustedBiddingSignalsKeys: ['a', 4, 'Foo']}
},
// "userBiddingSignals" tests
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
userBiddingSignals: null }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
userBiddingSignals: 'foo' }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
userBiddingSignals: 15 }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
userBiddingSignals: [5, 'foo', [-6.4, {a: 'b'}]] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
userBiddingSignals: {a: [5, 'foo', {b: -6.4}] }}
},
// "ads" tests
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: 5 }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: {} }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [] }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [{}] }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [{metadata: [{a:'b'}, 'c'], 1:[2,3]}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [{renderURL: 'https://somewhere.test/'}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [{renderURL: 'https://somewhere.test/'},
{renderURL: 'https://somewhere-else.test/'}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [{renderURL: 'https://somewhere.test/',
metadata: null}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
ads: [{renderURL: 'https://somewhere.test/',
metadata: null,
someOtherField: 'foo'}] }
},
// "adComponents" tests
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: null }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: 5 }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: {} }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [] }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [{}] }
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [{metadata: [{a:'b'}, 'c'], 1:[2,3]}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [{renderURL: 'https://somewhere.test/'}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [{renderURL: 'https://somewhere.test/'},
{renderURL: 'https://elsewhere.test/'}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [{renderURL: 'https://somewhere.test/',
metadata: null}] }
},
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
adComponents: [{renderURL: 'https://somewhere.test/',
metadata: null,
someOtherField: 'foo'}] }
},
// Miscellaneous tests.
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
extra: false,
fields: {do:'not'},
matter: 'at',
all: [3,4,5] }
},
// Interest group dictionaries must be less than 1 MB (1048576 bytes), so
// test that here by using a large name on an otherwise valid interest group
// dictionary. The first case is the largest name value that still results in
// a valid dictionary, whereas the second test case produces a dictionary
// that's one byte too large.
{ expectJoinSucces: true,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
name: 'a'.repeat(1048520)
},
testCaseName: "Largest possible interest group dictionary",
},
{ expectJoinSucces: false,
expectLeaveSucces: true,
interestGroup: { ...BASE_INTEREST_GROUP,
name: 'a'.repeat(1048521)
},
testCaseName: "Oversized interest group dictionary",
},
];
for (testCase of SIMPLE_JOIN_LEAVE_TEST_CASES) {
var test_name = 'Join and leave interest group: ';
if ('testCaseName' in testCase) {
test_name += testCase.testCaseName;
} else {
test_name += JSON.stringify(testCase);
}
subsetTest(promise_test, (async (testCase) => {
const INTEREST_GROUP_LIFETIME_SECS = 1;
let join_promise = navigator.joinAdInterestGroup(testCase.interestGroup,
INTEREST_GROUP_LIFETIME_SECS);
assert_true(join_promise instanceof Promise, "join should return a promise");
if (testCase.expectJoinSucces) {
assert_equals(await join_promise, undefined);
} else {
let joinExceptionThrown = false;
try {
await join_promise;
} catch (e) {
joinExceptionThrown = true;
}
assert_true(joinExceptionThrown, 'Exception not thrown on join.');
}
let leave_promise = navigator.leaveAdInterestGroup(testCase.interestGroup);
assert_true(leave_promise instanceof Promise, "leave should return a promise");
if (testCase.expectLeaveSucces) {
assert_equals(await leave_promise, undefined);
} else {
let leaveExceptionThrown = false;
try {
await leave_promise;
} catch (e) {
leaveExceptionThrown = true;
}
assert_true(leaveExceptionThrown, 'Exception not thrown on leave.');
}
}).bind(undefined, testCase), test_name);
}
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
// Joining an interest group without a bidding script and run an auction.
// There should be no winner.
await joinInterestGroup(test, uuid, { biddingLogicURL: null });
assert_equals(null, await runBasicFledgeAuction(test, uuid),
'Auction unexpectedly had a winner');
// Joining an interest group with a bidding script and the same owner/name as
// the previously joined interest group, and re-run the auction. There should
// be a winner this time.
await joinInterestGroup(test, uuid);
let config = await runBasicFledgeAuction(test, uuid);
assert_true(config instanceof FencedFrameConfig,
'Wrong value type returned from auction: ' +
config.constructor.name);
// Re-join the first interest group, and re-run the auction. The interest
// group should be overwritten again, and there should be no winner.
await joinInterestGroup(test, uuid, { biddingLogicURL: null });
assert_equals(null, await runBasicFledgeAuction(test, uuid),
'Auction unexpectedly had a winner');
}, 'Join same interest group overwrites old matching group.');
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
// Join an interest group, run an auction to make sure it was joined.
await joinInterestGroup(test, uuid);
let config = await runBasicFledgeAuction(test, uuid);
assert_true(config instanceof FencedFrameConfig,
'Wrong value type returned from auction: ' +
config.constructor.name);
// Leave the interest group, re-run the auction. There should be no winner.
await leaveInterestGroup();
assert_equals(null, await runBasicFledgeAuction(test, uuid),
'Auction unexpectedly had a winner');
}, 'Leaving interest group actually leaves interest group.');
subsetTest(promise_test, async test => {
// This should not throw.
await leaveInterestGroup({ name: 'Never join group' });
}, 'Leave an interest group that was never joined.');
///////////////////////////////////////////////////////////////////////////////
// Expiration tests
///////////////////////////////////////////////////////////////////////////////
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
// Joins the default interest group, with a 0.2 second duration.
await joinInterestGroup(test, uuid, {}, 0.2);
// Keep on running auctions until interest group duration expires.
// Unfortunately, there's no duration that's guaranteed to be long enough to
// be be able to win an auction once, but short enough to prevent this test
// from running too long, so can't check the interest group won at least one
// auction.
while (await runBasicFledgeAuction(test, uuid) !== null);
}, 'Interest group duration.');
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
// Join interest group with a duration of -600. The interest group should
// immediately expire, and not be allowed to participate in auctions.
await joinInterestGroup(test, uuid, {}, -600);
assert_true(await runBasicFledgeAuction(test, uuid) === null);
}, 'Interest group duration of -600.');
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
// Join a long-lived interest group.
await joinInterestGroup(test, uuid, {}, 600);
// Make sure interest group with a non-default timeout was joined.
assert_true(await runBasicFledgeAuction(test, uuid) !== null);
// Re-join interest group with a duration value of 0.2 seconds.
await joinInterestGroup(test, uuid, {}, 0.2);
// Keep on running auctions until interest group expires.
while (await runBasicFledgeAuction(test, uuid) !== null);
}, 'Interest group test with overwritten duration.');
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
// Join a long-lived interest group.
await joinInterestGroup(test, uuid, {}, 600);
// Re-join interest group with a duration value of 0.2 seconds. The new
// duration should take precedence, and the interest group should immediately
// expire.
await joinInterestGroup(test, uuid, {}, -600);
assert_true(await runBasicFledgeAuction(test, uuid) === null);
}, 'Interest group test with overwritten duration of -600.');