1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/first_party_sets/global_first_party_sets.h"
6
7 #include "base/containers/flat_map.h"
8 #include "base/version.h"
9 #include "net/base/schemeful_site.h"
10 #include "net/first_party_sets/first_party_set_entry.h"
11 #include "net/first_party_sets/first_party_set_entry_override.h"
12 #include "net/first_party_sets/first_party_set_metadata.h"
13 #include "net/first_party_sets/first_party_sets_context_config.h"
14 #include "net/first_party_sets/local_set_declaration.h"
15 #include "net/first_party_sets/sets_mutation.h"
16 #include "testing/gmock/include/gmock/gmock-matchers.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
20 #include "url/gurl.h"
21
22 using ::testing::IsEmpty;
23 using ::testing::Optional;
24 using ::testing::Pair;
25 using ::testing::UnorderedElementsAre;
26
27 namespace net {
28
29 namespace {
30
31 const base::Version kVersion("1.2.3");
32 const SchemefulSite kPrimary(GURL("https://primary.test"));
33 const SchemefulSite kPrimary2(GURL("https://primary2.test"));
34 const SchemefulSite kPrimary3(GURL("https://primary3.test"));
35 const SchemefulSite kAssociated1(GURL("https://associated1.test"));
36 const SchemefulSite kAssociated1Cctld(GURL("https://associated1.cctld"));
37 const SchemefulSite kAssociated1Cctld2(GURL("https://associated1.cctld2"));
38 const SchemefulSite kAssociated2(GURL("https://associated2.test"));
39 const SchemefulSite kAssociated3(GURL("https://associated3.test"));
40 const SchemefulSite kAssociated4(GURL("https://associated4.test"));
41 const SchemefulSite kAssociated5(GURL("https://associated5.test"));
42 const SchemefulSite kService(GURL("https://service.test"));
43
CollectEffectiveSetEntries(const GlobalFirstPartySets & sets,const FirstPartySetsContextConfig & config)44 base::flat_map<SchemefulSite, FirstPartySetEntry> CollectEffectiveSetEntries(
45 const GlobalFirstPartySets& sets,
46 const FirstPartySetsContextConfig& config) {
47 base::flat_map<SchemefulSite, FirstPartySetEntry> got;
48 sets.ForEachEffectiveSetEntry(
49 config, [&](const SchemefulSite& site, const FirstPartySetEntry& entry) {
50 EXPECT_FALSE(got.contains(site));
51 got[site] = entry;
52 return true;
53 });
54
55 // Consistency check: verify that all of the returned entries are what we'd
56 // get if we called FindEntry directly.
57 for (const auto& [site, entry] : got) {
58 EXPECT_EQ(sets.FindEntry(site, config).value(), entry);
59 }
60 return got;
61 }
62
63 } // namespace
64
65 class GlobalFirstPartySetsTest : public ::testing::Test {
66 public:
67 GlobalFirstPartySetsTest() = default;
68 };
69
TEST_F(GlobalFirstPartySetsTest,CtorSkipsInvalidVersion)70 TEST_F(GlobalFirstPartySetsTest, CtorSkipsInvalidVersion) {
71 GlobalFirstPartySets sets(
72 base::Version(), /*entries=*/
73 {
74 {kPrimary,
75 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
76 {kAssociated1,
77 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
78 },
79 /*aliases=*/{});
80
81 EXPECT_THAT(
82 sets.FindEntries({kPrimary, kAssociated1}, FirstPartySetsContextConfig()),
83 IsEmpty());
84 }
85
TEST_F(GlobalFirstPartySetsTest,Clone)86 TEST_F(GlobalFirstPartySetsTest, Clone) {
87 base::Version version("1.2.3.4.5");
88 const SchemefulSite example(GURL("https://example.test"));
89 const SchemefulSite example_cctld(GURL("https://example.cctld"));
90 const SchemefulSite member1(GURL("https://member1.test"));
91 const FirstPartySetEntry entry(example, SiteType::kPrimary, absl::nullopt);
92 const FirstPartySetEntry member1_entry(example, SiteType::kAssociated, 1);
93
94 const SchemefulSite foo(GURL("https://foo.test"));
95 const SchemefulSite member2(GURL("https://member2.test"));
96 const FirstPartySetEntry foo_entry(foo, SiteType::kPrimary, absl::nullopt);
97 const FirstPartySetEntry member2_entry(foo, SiteType::kAssociated, 1);
98
99 GlobalFirstPartySets sets(version,
100 /*entries=*/
101 {{example, entry}, {member1, member1_entry}},
102 /*aliases=*/{{example_cctld, example}});
103 sets.ApplyManuallySpecifiedSet(LocalSetDeclaration(
104 /*set_entries=*/{{foo, foo_entry}, {member2, member2_entry}},
105 /*aliases=*/{}));
106
107 EXPECT_EQ(sets, sets.Clone());
108 }
109
TEST_F(GlobalFirstPartySetsTest,FindEntry_Nonexistent)110 TEST_F(GlobalFirstPartySetsTest, FindEntry_Nonexistent) {
111 SchemefulSite example(GURL("https://example.test"));
112
113 EXPECT_THAT(
114 GlobalFirstPartySets().FindEntry(example, FirstPartySetsContextConfig()),
115 absl::nullopt);
116 }
117
TEST_F(GlobalFirstPartySetsTest,FindEntry_Exists)118 TEST_F(GlobalFirstPartySetsTest, FindEntry_Exists) {
119 SchemefulSite example(GURL("https://example.test"));
120 SchemefulSite decoy_site(GURL("https://decoy.test"));
121 FirstPartySetEntry entry(example, SiteType::kPrimary, absl::nullopt);
122 FirstPartySetEntry decoy_entry(example, SiteType::kAssociated, 1);
123
124 EXPECT_THAT(GlobalFirstPartySets(kVersion,
125 {
126 {example, entry},
127 {decoy_site, decoy_entry},
128 },
129 {})
130 .FindEntry(example, FirstPartySetsContextConfig()),
131 Optional(entry));
132 }
133
TEST_F(GlobalFirstPartySetsTest,FindEntry_NoNormalization)134 TEST_F(GlobalFirstPartySetsTest, FindEntry_NoNormalization) {
135 SchemefulSite https_example(GURL("https://example.test"));
136 SchemefulSite wss_example(GURL("wss://example.test"));
137 FirstPartySetEntry entry(https_example, SiteType::kPrimary, absl::nullopt);
138
139 EXPECT_THAT(GlobalFirstPartySets(kVersion,
140 {
141 {https_example, entry},
142 },
143 {})
144 .FindEntry(wss_example, FirstPartySetsContextConfig()),
145 absl::nullopt);
146 }
147
TEST_F(GlobalFirstPartySetsTest,FindEntry_ExistsViaOverride)148 TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverride) {
149 SchemefulSite example(GURL("https://example.test"));
150 FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
151 FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
152
153 FirstPartySetsContextConfig config(
154 {{example, net::FirstPartySetEntryOverride(override_entry)}});
155
156 EXPECT_THAT(GlobalFirstPartySets(kVersion,
157 {
158 {example, public_entry},
159 },
160 {})
161 .FindEntry(example, config),
162 Optional(override_entry));
163 }
164
TEST_F(GlobalFirstPartySetsTest,FindEntry_RemovedViaOverride)165 TEST_F(GlobalFirstPartySetsTest, FindEntry_RemovedViaOverride) {
166 SchemefulSite example(GURL("https://example.test"));
167 FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
168
169 FirstPartySetsContextConfig config(
170 {{example, net::FirstPartySetEntryOverride()}});
171
172 EXPECT_THAT(GlobalFirstPartySets(kVersion,
173 {
174 {example, public_entry},
175 },
176 {})
177 .FindEntry(example, config),
178 absl::nullopt);
179 }
180
TEST_F(GlobalFirstPartySetsTest,FindEntry_ExistsViaAlias)181 TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaAlias) {
182 SchemefulSite example(GURL("https://example.test"));
183 SchemefulSite example_cctld(GURL("https://example.cctld"));
184 FirstPartySetEntry entry(example, SiteType::kPrimary, absl::nullopt);
185
186 EXPECT_THAT(GlobalFirstPartySets(kVersion,
187 {
188 {example, entry},
189 },
190 {{example_cctld, example}})
191 .FindEntry(example_cctld, FirstPartySetsContextConfig()),
192 Optional(entry));
193 }
194
TEST_F(GlobalFirstPartySetsTest,FindEntry_ExistsViaOverrideWithDecoyAlias)195 TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverrideWithDecoyAlias) {
196 SchemefulSite example(GURL("https://example.test"));
197 SchemefulSite example_cctld(GURL("https://example.cctld"));
198 FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
199 FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
200
201 FirstPartySetsContextConfig config(
202 {{example_cctld, net::FirstPartySetEntryOverride(override_entry)}});
203
204 EXPECT_THAT(GlobalFirstPartySets(kVersion,
205 {
206 {example, public_entry},
207 },
208 {{example_cctld, example}})
209 .FindEntry(example_cctld, config),
210 Optional(override_entry));
211 }
212
TEST_F(GlobalFirstPartySetsTest,FindEntry_RemovedViaOverrideWithDecoyAlias)213 TEST_F(GlobalFirstPartySetsTest, FindEntry_RemovedViaOverrideWithDecoyAlias) {
214 SchemefulSite example(GURL("https://example.test"));
215 SchemefulSite example_cctld(GURL("https://example.cctld"));
216 FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
217
218 FirstPartySetsContextConfig config(
219 {{example_cctld, net::FirstPartySetEntryOverride()}});
220
221 EXPECT_THAT(GlobalFirstPartySets(kVersion,
222 {
223 {example, public_entry},
224 },
225 {{example_cctld, example}})
226 .FindEntry(example_cctld, config),
227 absl::nullopt);
228 }
229
TEST_F(GlobalFirstPartySetsTest,FindEntry_AliasesIgnoredForConfig)230 TEST_F(GlobalFirstPartySetsTest, FindEntry_AliasesIgnoredForConfig) {
231 SchemefulSite example(GURL("https://example.test"));
232 SchemefulSite example_cctld(GURL("https://example.cctld"));
233 FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
234 FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
235
236 FirstPartySetsContextConfig config(
237 {{example, net::FirstPartySetEntryOverride(override_entry)}});
238
239 // FindEntry should ignore aliases when using the customizations. Public
240 // aliases only apply to sites in the public sets.
241 EXPECT_THAT(GlobalFirstPartySets(kVersion,
242 {
243 {example, public_entry},
244 },
245 {{example_cctld, example}})
246 .FindEntry(example_cctld, config),
247 public_entry);
248 }
249
TEST_F(GlobalFirstPartySetsTest,Empty_Empty)250 TEST_F(GlobalFirstPartySetsTest, Empty_Empty) {
251 EXPECT_TRUE(GlobalFirstPartySets().empty());
252 }
253
TEST_F(GlobalFirstPartySetsTest,Empty_NonemptyEntries)254 TEST_F(GlobalFirstPartySetsTest, Empty_NonemptyEntries) {
255 EXPECT_FALSE(
256 GlobalFirstPartySets(
257 kVersion,
258 {
259 {kPrimary,
260 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
261 {kAssociated4,
262 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
263 },
264 {})
265 .empty());
266 }
267
TEST_F(GlobalFirstPartySetsTest,Empty_NonemptyManualSet)268 TEST_F(GlobalFirstPartySetsTest, Empty_NonemptyManualSet) {
269 GlobalFirstPartySets sets;
270 sets.ApplyManuallySpecifiedSet(LocalSetDeclaration(
271 /*set_entries=*/
272 {
273 {kPrimary,
274 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
275 {kAssociated4,
276 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
277 },
278 /*aliases=*/{}));
279 EXPECT_FALSE(sets.empty());
280 }
281
TEST_F(GlobalFirstPartySetsTest,InvalidPublicSetsVersion_NonemptyManualSet)282 TEST_F(GlobalFirstPartySetsTest, InvalidPublicSetsVersion_NonemptyManualSet) {
283 GlobalFirstPartySets sets(
284 base::Version(), /*entries=*/
285 {
286 {kPrimary,
287 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
288 {kAssociated1,
289 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
290 },
291 /*aliases=*/{});
292 ASSERT_TRUE(sets.empty());
293 sets.ApplyManuallySpecifiedSet(LocalSetDeclaration(
294 /*set_entries=*/
295 {
296 {kPrimary,
297 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
298 {kAssociated4,
299 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
300 },
301 /*aliases=*/{}));
302
303 // The manual set should still be available, even though the component was
304 // invalid.
305 EXPECT_FALSE(sets.empty());
306 EXPECT_THAT(
307 sets.FindEntries({kPrimary, kAssociated1, kAssociated4},
308 FirstPartySetsContextConfig()),
309 UnorderedElementsAre(
310 Pair(kPrimary,
311 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
312 Pair(kAssociated4,
313 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0))));
314 }
315
TEST_F(GlobalFirstPartySetsTest,ForEachEffectiveSetEntry_ManualSetAndConfig_FullIteration)316 TEST_F(GlobalFirstPartySetsTest,
317 ForEachEffectiveSetEntry_ManualSetAndConfig_FullIteration) {
318 GlobalFirstPartySets global_sets;
319 global_sets.ApplyManuallySpecifiedSet(LocalSetDeclaration(
320 /*set_entries=*/
321 {
322 {kPrimary,
323 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
324 {kAssociated4,
325 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
326 {kAssociated5,
327 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
328 },
329 /*aliases=*/{}));
330
331 // Modify kPrimary's set by removing kAssociated5 and modifying kAssociated4,
332 // via policy.
333 FirstPartySetsContextConfig config = global_sets.ComputeConfig(SetsMutation(
334 /*replacement_sets=*/
335 {
336 {
337 {kPrimary,
338 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
339 {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
340 absl::nullopt)},
341 {kAssociated1Cctld,
342 FirstPartySetEntry(kPrimary, SiteType::kAssociated,
343 absl::nullopt)},
344 {kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
345 absl::nullopt)},
346 {kService,
347 FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)},
348 },
349 },
350 /*addition_sets=*/{}));
351
352 // Note that since the policy sets take precedence over the manual set,
353 // kAssociated5 is no longer in an FPS.
354 EXPECT_THAT(
355 CollectEffectiveSetEntries(global_sets, config),
356 UnorderedElementsAre(
357 Pair(kAssociated1Cctld,
358 FirstPartySetEntry(kPrimary, SiteType::kAssociated,
359 absl::nullopt)),
360 Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
361 absl::nullopt)),
362 Pair(kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
363 absl::nullopt)),
364 Pair(kPrimary,
365 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
366 Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService,
367 absl::nullopt))));
368 }
369
370 class PopulatedGlobalFirstPartySetsTest : public GlobalFirstPartySetsTest {
371 public:
PopulatedGlobalFirstPartySetsTest()372 PopulatedGlobalFirstPartySetsTest()
373 : global_sets_(
374 kVersion,
375 {
376 {kPrimary, FirstPartySetEntry(kPrimary,
377 SiteType::kPrimary,
378 absl::nullopt)},
379 {kAssociated1,
380 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
381 {kAssociated2,
382 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
383 {kService, FirstPartySetEntry(kPrimary,
384 SiteType::kService,
385 absl::nullopt)},
386 {kPrimary2, FirstPartySetEntry(kPrimary2,
387 SiteType::kPrimary,
388 absl::nullopt)},
389 {kAssociated3,
390 FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)},
391 },
392 {
393 {kAssociated1Cctld, kAssociated1},
394 }) {}
395
global_sets()396 GlobalFirstPartySets& global_sets() { return global_sets_; }
397
398 private:
399 GlobalFirstPartySets global_sets_;
400 };
401
TEST_F(PopulatedGlobalFirstPartySetsTest,ApplyManuallySpecifiedSet_DeduplicatesPrimaryPrimary)402 TEST_F(PopulatedGlobalFirstPartySetsTest,
403 ApplyManuallySpecifiedSet_DeduplicatesPrimaryPrimary) {
404 // kPrimary overlaps as primary of both sets, so the existing set should be
405 // wiped out.
406 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
407 /*set_entries=*/
408 {
409 {kPrimary,
410 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
411 {kAssociated4,
412 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
413 },
414 /*aliases=*/{}));
415
416 EXPECT_THAT(
417 global_sets().FindEntries(
418 {
419 kPrimary,
420 kAssociated1,
421 kAssociated2,
422 kAssociated4,
423 kService,
424 kAssociated1Cctld,
425 },
426 FirstPartySetsContextConfig()),
427 UnorderedElementsAre(
428 Pair(kPrimary,
429 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
430 Pair(kAssociated4,
431 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0))));
432 }
433
TEST_F(PopulatedGlobalFirstPartySetsTest,ApplyManuallySpecifiedSet_DeduplicatesPrimaryNonprimary)434 TEST_F(PopulatedGlobalFirstPartySetsTest,
435 ApplyManuallySpecifiedSet_DeduplicatesPrimaryNonprimary) {
436 // kPrimary overlaps as a primary of the public set and non-primary of the CLI
437 // set, so the existing set should be wiped out.
438 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
439 /*set_entries=*/
440 {
441 {kPrimary3,
442 FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)},
443 {kPrimary, FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)},
444 },
445 /*aliases=*/{}));
446
447 EXPECT_THAT(
448 global_sets().FindEntries(
449 {
450 kPrimary,
451 kAssociated1,
452 kAssociated2,
453 kAssociated4,
454 kService,
455 kPrimary3,
456 kAssociated1Cctld,
457 },
458 FirstPartySetsContextConfig()),
459 UnorderedElementsAre(
460 Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary,
461 absl::nullopt)),
462 Pair(kPrimary,
463 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0))));
464 }
465
TEST_F(PopulatedGlobalFirstPartySetsTest,ApplyManuallySpecifiedSet_DeduplicatesNonprimaryPrimary)466 TEST_F(PopulatedGlobalFirstPartySetsTest,
467 ApplyManuallySpecifiedSet_DeduplicatesNonprimaryPrimary) {
468 // kAssociated1 overlaps as a non-primary of the public set and primary of the
469 // CLI set, so the CLI set should steal it and wipe out its alias, but
470 // otherwise leave the set intact.
471 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
472 /*set_entries=*/
473 {
474 {kAssociated1,
475 FirstPartySetEntry(kAssociated1, SiteType::kPrimary, absl::nullopt)},
476 {kAssociated4,
477 FirstPartySetEntry(kAssociated1, SiteType::kAssociated, 0)},
478 },
479 /*aliases=*/{}));
480
481 EXPECT_THAT(
482 global_sets().FindEntries(
483 {
484 kPrimary,
485 kAssociated1,
486 kAssociated2,
487 kAssociated4,
488 kService,
489 kPrimary3,
490 kAssociated1Cctld,
491 },
492 FirstPartySetsContextConfig()),
493 UnorderedElementsAre(
494 Pair(kPrimary,
495 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
496 Pair(kAssociated2,
497 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)),
498 Pair(kService,
499 FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)),
500 Pair(kAssociated1,
501 FirstPartySetEntry(kAssociated1, SiteType::kPrimary,
502 absl::nullopt)),
503 Pair(kAssociated4,
504 FirstPartySetEntry(kAssociated1, SiteType::kAssociated, 0))));
505 }
506
TEST_F(PopulatedGlobalFirstPartySetsTest,ApplyManuallySpecifiedSet_DeduplicatesNonprimaryNonprimary)507 TEST_F(PopulatedGlobalFirstPartySetsTest,
508 ApplyManuallySpecifiedSet_DeduplicatesNonprimaryNonprimary) {
509 // kAssociated1 overlaps as a non-primary of the public set and non-primary of
510 // the CLI set, so the CLI set should steal it and wipe out its alias.
511 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
512 /*set_entries=*/
513 {
514 {kPrimary3,
515 FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)},
516 {kAssociated1,
517 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)},
518 },
519 /*aliases=*/{}));
520
521 EXPECT_THAT(
522 global_sets().FindEntries(
523 {
524 kPrimary,
525 kAssociated1,
526 kAssociated2,
527 kAssociated4,
528 kService,
529 kPrimary3,
530 kAssociated1Cctld,
531 },
532 FirstPartySetsContextConfig()),
533 UnorderedElementsAre(
534 Pair(kPrimary,
535 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
536 Pair(kAssociated2,
537 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)),
538 Pair(kService,
539 FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)),
540 Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary,
541 absl::nullopt)),
542 Pair(kAssociated1,
543 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0))));
544 }
545
TEST_F(PopulatedGlobalFirstPartySetsTest,ApplyManuallySpecifiedSet_PrunesInducedSingletons)546 TEST_F(PopulatedGlobalFirstPartySetsTest,
547 ApplyManuallySpecifiedSet_PrunesInducedSingletons) {
548 // Steal kAssociated3, so that kPrimary2 becomes a singleton, and verify that
549 // kPrimary2 is no longer considered in a set.
550 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
551 /*set_entries=*/
552 {
553 {kPrimary3,
554 FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)},
555 {kAssociated3,
556 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)},
557 },
558 /*aliases=*/{}));
559
560 EXPECT_THAT(
561 global_sets().FindEntries({kPrimary2}, FirstPartySetsContextConfig()),
562 IsEmpty());
563 }
564
TEST_F(PopulatedGlobalFirstPartySetsTest,ApplyManuallySpecifiedSet_RespectsManualAlias)565 TEST_F(PopulatedGlobalFirstPartySetsTest,
566 ApplyManuallySpecifiedSet_RespectsManualAlias) {
567 // Both the public sets and the locally-defined set define an alias for
568 // kAssociated1, but both define a different set for that site too. Only the
569 // locally-defined alias should be observable.
570 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
571 /*set_entries=*/
572 {
573 {kPrimary3,
574 FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)},
575 {kAssociated1,
576 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)},
577 },
578 /*aliases=*/{
579 {kAssociated1Cctld2, kAssociated1},
580 }));
581
582 EXPECT_THAT(
583 global_sets().FindEntries(
584 {
585 kAssociated1,
586 kAssociated1Cctld,
587 kAssociated1Cctld2,
588 },
589 FirstPartySetsContextConfig()),
590 UnorderedElementsAre(
591 Pair(kAssociated1,
592 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)),
593 Pair(kAssociated1Cctld2,
594 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0))));
595 }
596
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachPublicSetEntry_FullIteration)597 TEST_F(PopulatedGlobalFirstPartySetsTest, ForEachPublicSetEntry_FullIteration) {
598 int count = 0;
599 EXPECT_TRUE(global_sets().ForEachPublicSetEntry(
600 [&](const SchemefulSite& site, const FirstPartySetEntry& entry) {
601 ++count;
602 return true;
603 }));
604 EXPECT_EQ(count, 7);
605 }
606
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachPublicSetEntry_EarlyReturn)607 TEST_F(PopulatedGlobalFirstPartySetsTest, ForEachPublicSetEntry_EarlyReturn) {
608 int count = 0;
609 EXPECT_FALSE(global_sets().ForEachPublicSetEntry(
610 [&](const SchemefulSite& site, const FirstPartySetEntry& entry) {
611 ++count;
612 return count < 4;
613 }));
614 EXPECT_EQ(count, 4);
615 }
616
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachEffectiveSetEntry_PublicSetsOnly_FullIteration)617 TEST_F(PopulatedGlobalFirstPartySetsTest,
618 ForEachEffectiveSetEntry_PublicSetsOnly_FullIteration) {
619 EXPECT_THAT(
620 CollectEffectiveSetEntries(global_sets(), FirstPartySetsContextConfig()),
621 UnorderedElementsAre(
622 Pair(kAssociated1Cctld,
623 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)),
624 Pair(kAssociated1,
625 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)),
626 Pair(kAssociated2,
627 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)),
628 Pair(kAssociated3,
629 FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)),
630 Pair(kPrimary,
631 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
632 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
633 absl::nullopt)),
634 Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService,
635 absl::nullopt))));
636 }
637
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachEffectiveSetEntry_PublicSetsWithManualSet_FullIteration)638 TEST_F(PopulatedGlobalFirstPartySetsTest,
639 ForEachEffectiveSetEntry_PublicSetsWithManualSet_FullIteration) {
640 // Replace kPrimary's set (including the alias and service site) with just
641 // {kPrimary, kAssociated4}.
642 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
643 /*set_entries=*/
644 {
645 {kPrimary,
646 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
647 {kAssociated4,
648 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
649 },
650 /*aliases=*/{}));
651
652 EXPECT_THAT(
653 CollectEffectiveSetEntries(global_sets(), FirstPartySetsContextConfig()),
654 UnorderedElementsAre(
655 Pair(kAssociated3,
656 FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)),
657 Pair(kAssociated4,
658 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)),
659 Pair(kPrimary,
660 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
661 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
662 absl::nullopt))));
663 }
664
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachEffectiveSetEntry_PublicSetsWithConfig_FullIteration)665 TEST_F(PopulatedGlobalFirstPartySetsTest,
666 ForEachEffectiveSetEntry_PublicSetsWithConfig_FullIteration) {
667 // Modify kPrimary's set by removing kAssociated2 and adding kAssociated4, via
668 // policy.
669 FirstPartySetsContextConfig config = global_sets().ComputeConfig(SetsMutation(
670 /*replacement_sets=*/
671 {
672 {
673 {kPrimary,
674 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
675 {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
676 absl::nullopt)},
677 {kAssociated1Cctld,
678 FirstPartySetEntry(kPrimary, SiteType::kAssociated,
679 absl::nullopt)},
680 {kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
681 absl::nullopt)},
682 {kService,
683 FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)},
684 },
685 },
686 /*addition_sets=*/{}));
687
688 EXPECT_THAT(
689 CollectEffectiveSetEntries(global_sets(), config),
690 UnorderedElementsAre(
691 Pair(kAssociated1Cctld,
692 FirstPartySetEntry(kPrimary, SiteType::kAssociated,
693 absl::nullopt)),
694 Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
695 absl::nullopt)),
696 Pair(kAssociated3,
697 FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)),
698 Pair(kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
699 absl::nullopt)),
700 Pair(kPrimary,
701 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
702 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
703 absl::nullopt)),
704 Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService,
705 absl::nullopt))));
706 }
707
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachEffectiveSetEntry_PublicSetsWithManualSetAndConfig_FullIteration)708 TEST_F(
709 PopulatedGlobalFirstPartySetsTest,
710 ForEachEffectiveSetEntry_PublicSetsWithManualSetAndConfig_FullIteration) {
711 // Replace kPrimary's set (including the alias and service site) with just
712 // {kPrimary, kAssociated4, kAssociated5}.
713 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
714 /*set_entries=*/
715 {
716 {kPrimary,
717 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
718 {kAssociated4,
719 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
720 {kAssociated5,
721 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
722 },
723 /*aliases=*/{}));
724
725 // Modify kPrimary's set by removing kAssociated2 and adding kAssociated4, via
726 // policy.
727 FirstPartySetsContextConfig config = global_sets().ComputeConfig(SetsMutation(
728 /*replacement_sets=*/
729 {
730 {
731 {kPrimary,
732 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
733 {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
734 absl::nullopt)},
735 {kAssociated1Cctld,
736 FirstPartySetEntry(kPrimary, SiteType::kAssociated,
737 absl::nullopt)},
738 {kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
739 absl::nullopt)},
740 {kService,
741 FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)},
742 },
743 },
744 /*addition_sets=*/{}));
745
746 // Note that since the policy sets take precedence over the manual set,
747 // kAssociated5 is no longer in an FPS.
748 EXPECT_THAT(
749 CollectEffectiveSetEntries(global_sets(), config),
750 UnorderedElementsAre(
751 Pair(kAssociated1Cctld,
752 FirstPartySetEntry(kPrimary, SiteType::kAssociated,
753 absl::nullopt)),
754 Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
755 absl::nullopt)),
756 Pair(kAssociated3,
757 FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)),
758 Pair(kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
759 absl::nullopt)),
760 Pair(kPrimary,
761 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
762 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
763 absl::nullopt)),
764 Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService,
765 absl::nullopt))));
766 }
767
TEST_F(PopulatedGlobalFirstPartySetsTest,ForEachEffectiveSetEntry_PublicSetsWithManualSetAndConfig_ManualAliasOverlap)768 TEST_F(
769 PopulatedGlobalFirstPartySetsTest,
770 ForEachEffectiveSetEntry_PublicSetsWithManualSetAndConfig_ManualAliasOverlap) {
771 global_sets().ApplyManuallySpecifiedSet(LocalSetDeclaration(
772 /*set_entries=*/
773 {
774 {kPrimary,
775 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
776 {kAssociated1,
777 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
778 },
779 /*aliases=*/{
780 {kAssociated1Cctld2, kAssociated1},
781 }));
782
783 FirstPartySetsContextConfig config = global_sets().ComputeConfig(SetsMutation(
784 /*replacement_sets=*/
785 {
786 {
787 {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
788 absl::nullopt)},
789 {kAssociated1,
790 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
791 absl::nullopt)},
792 },
793 },
794 /*addition_sets=*/{}));
795
796 EXPECT_THAT(
797 CollectEffectiveSetEntries(global_sets(), config),
798 UnorderedElementsAre(
799 Pair(kAssociated1,
800 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
801 absl::nullopt)),
802 Pair(kPrimary,
803 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
804 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
805 absl::nullopt))));
806 }
807
TEST_F(PopulatedGlobalFirstPartySetsTest,ComputeMetadata)808 TEST_F(PopulatedGlobalFirstPartySetsTest, ComputeMetadata) {
809 SchemefulSite nonmember(GURL("https://nonmember.test"));
810 SchemefulSite nonmember1(GURL("https://nonmember1.test"));
811 FirstPartySetEntry primary_entry(kPrimary, SiteType::kPrimary, absl::nullopt);
812 FirstPartySetEntry associated_entry(kPrimary, SiteType::kAssociated, 0);
813
814 // Works as usual for sites that are in First-Party sets.
815 EXPECT_EQ(global_sets().ComputeMetadata(kAssociated1, &kAssociated1,
816 FirstPartySetsContextConfig()),
817 FirstPartySetMetadata(&associated_entry, &associated_entry));
818 EXPECT_EQ(global_sets().ComputeMetadata(kPrimary, &kAssociated1,
819 FirstPartySetsContextConfig()),
820 FirstPartySetMetadata(&primary_entry, &associated_entry));
821 EXPECT_EQ(global_sets().ComputeMetadata(kAssociated1, &kPrimary,
822 FirstPartySetsContextConfig()),
823 FirstPartySetMetadata(&associated_entry, &primary_entry));
824
825 EXPECT_EQ(global_sets().ComputeMetadata(nonmember, &kAssociated1,
826 FirstPartySetsContextConfig()),
827 FirstPartySetMetadata(nullptr, &associated_entry));
828 EXPECT_EQ(global_sets().ComputeMetadata(kAssociated1, &nonmember,
829 FirstPartySetsContextConfig()),
830 FirstPartySetMetadata(&associated_entry, nullptr));
831
832 EXPECT_EQ(global_sets().ComputeMetadata(nonmember, &nonmember,
833 FirstPartySetsContextConfig()),
834 FirstPartySetMetadata(nullptr, nullptr));
835 }
836
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Empty)837 TEST_F(GlobalFirstPartySetsTest, ComputeConfig_Empty) {
838 EXPECT_EQ(GlobalFirstPartySets(
839 kVersion,
840 /*entries=*/
841 {
842 {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary,
843 absl::nullopt)},
844 {kAssociated1,
845 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
846 },
847 /*aliases=*/{})
848 .ComputeConfig(SetsMutation({}, {})),
849 FirstPartySetsContextConfig());
850 }
851
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Replacements_NoIntersection_NoRemoval)852 TEST_F(GlobalFirstPartySetsTest,
853 ComputeConfig_Replacements_NoIntersection_NoRemoval) {
854 GlobalFirstPartySets sets(
855 kVersion,
856 /*entries=*/
857 {
858 {kPrimary,
859 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
860 {kAssociated1,
861 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
862 },
863 /*aliases=*/{});
864 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
865 /*replacement_sets=*/
866 {
867 {
868 {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
869 absl::nullopt)},
870 {kAssociated2,
871 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
872 absl::nullopt)},
873 },
874 },
875 /*addition_sets=*/{}));
876 EXPECT_THAT(
877 sets.FindEntries({kAssociated2, kPrimary2}, config),
878 UnorderedElementsAre(
879 Pair(kAssociated2,
880 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
881 absl::nullopt)),
882 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
883 absl::nullopt))));
884 }
885
886 // The common associated site between the policy and existing set is removed
887 // from its previous set.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Replacements_ReplacesExistingAssociatedSite_RemovedFromFormerSet)888 TEST_F(
889 GlobalFirstPartySetsTest,
890 ComputeConfig_Replacements_ReplacesExistingAssociatedSite_RemovedFromFormerSet) {
891 GlobalFirstPartySets sets(
892 kVersion,
893 /*entries=*/
894 {
895 {kPrimary,
896 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
897 {kAssociated1,
898 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
899 {kAssociated2,
900 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
901 },
902 /*aliases=*/{});
903 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
904 /*replacement_sets=*/
905 {
906 {
907 {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
908 absl::nullopt)},
909 {kAssociated2,
910 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
911 absl::nullopt)},
912 },
913 },
914 /*addition_sets=*/{}));
915 EXPECT_THAT(
916 sets.FindEntries({kPrimary2, kAssociated2}, config),
917 UnorderedElementsAre(
918 Pair(kAssociated2,
919 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
920 absl::nullopt)),
921 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
922 absl::nullopt))));
923 }
924
925 // The common primary between the policy and existing set is removed and its
926 // former associated sites are removed since they are now unowned.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Replacements_ReplacesExistingPrimary_RemovesFormerAssociatedSites)927 TEST_F(
928 GlobalFirstPartySetsTest,
929 ComputeConfig_Replacements_ReplacesExistingPrimary_RemovesFormerAssociatedSites) {
930 GlobalFirstPartySets sets(
931 kVersion,
932 /*entries=*/
933 {
934 {kPrimary,
935 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
936 {kAssociated1,
937 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
938 {kAssociated2,
939 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
940 },
941 /*aliases=*/{});
942 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
943 /*replacement_sets=*/
944 {
945 {
946 {kPrimary,
947 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
948 {kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
949 absl::nullopt)},
950 },
951 },
952 /*addition_sets=*/{}));
953 EXPECT_THAT(
954 sets.FindEntries({kAssociated3, kPrimary, kAssociated1, kAssociated2},
955 config),
956 UnorderedElementsAre(
957 Pair(kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
958 absl::nullopt)),
959 Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary,
960 absl::nullopt))));
961 }
962
963 // The common associated site between the policy and existing set is removed and
964 // any leftover singletons are deleted.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Replacements_ReplacesExistingAssociatedSite_RemovesSingletons)965 TEST_F(
966 GlobalFirstPartySetsTest,
967 ComputeConfig_Replacements_ReplacesExistingAssociatedSite_RemovesSingletons) {
968 GlobalFirstPartySets sets(
969 kVersion,
970 /*entries=*/
971 {
972 {kPrimary,
973 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
974 {kAssociated1,
975 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
976 },
977 /*aliases=*/{});
978 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
979 /*replacement_sets=*/
980 {
981 {
982 {kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary,
983 absl::nullopt)},
984 {kAssociated1,
985 FirstPartySetEntry(kPrimary3, SiteType::kAssociated,
986 absl::nullopt)},
987 },
988 },
989 /*addition_sets=*/{}));
990 EXPECT_THAT(
991 sets.FindEntries({kAssociated1, kPrimary3, kPrimary}, config),
992 UnorderedElementsAre(
993 Pair(kAssociated1,
994 FirstPartySetEntry(kPrimary3, SiteType::kAssociated,
995 absl::nullopt)),
996 Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary,
997 absl::nullopt))));
998 }
999
1000 // The policy set and the existing set have nothing in common so the policy set
1001 // gets added in without updating the existing set.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Additions_NoIntersection_AddsWithoutUpdating)1002 TEST_F(GlobalFirstPartySetsTest,
1003 ComputeConfig_Additions_NoIntersection_AddsWithoutUpdating) {
1004 GlobalFirstPartySets sets(
1005 kVersion,
1006 /*entries=*/
1007 {
1008 {kPrimary,
1009 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1010 {kAssociated1,
1011 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
1012 },
1013 /*aliases=*/{});
1014 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1015 /*replacement_sets=*/{},
1016 /*addition_sets=*/{
1017 {
1018 {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
1019 absl::nullopt)},
1020 {kAssociated2,
1021 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
1022 absl::nullopt)},
1023 },
1024 }));
1025 EXPECT_THAT(
1026 sets.FindEntries({kAssociated2, kPrimary2}, config),
1027 UnorderedElementsAre(
1028 Pair(kAssociated2,
1029 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
1030 absl::nullopt)),
1031 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
1032 absl::nullopt))));
1033 }
1034
1035 // The primary of a policy set is also an associated site in an existing set.
1036 // The policy set absorbs all sites in the existing set into its
1037 // associated sites.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Additions_PolicyPrimaryIsExistingAssociatedSite_PolicySetAbsorbsExistingSet)1038 TEST_F(
1039 GlobalFirstPartySetsTest,
1040 ComputeConfig_Additions_PolicyPrimaryIsExistingAssociatedSite_PolicySetAbsorbsExistingSet) {
1041 GlobalFirstPartySets sets(
1042 kVersion,
1043 /*entries=*/
1044 {
1045 {kPrimary,
1046 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1047 {kAssociated1,
1048 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
1049 },
1050 /*aliases=*/{});
1051 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1052 /*replacement_sets=*/{},
1053 /*addition_sets=*/{
1054 {
1055 {kAssociated1,
1056 FirstPartySetEntry(kAssociated1, SiteType::kPrimary,
1057 absl::nullopt)},
1058 {kAssociated2,
1059 FirstPartySetEntry(kAssociated1, SiteType::kAssociated,
1060 absl::nullopt)},
1061 {kAssociated3,
1062 FirstPartySetEntry(kAssociated1, SiteType::kAssociated,
1063 absl::nullopt)},
1064 },
1065 }));
1066 EXPECT_THAT(
1067 sets.FindEntries({kPrimary, kAssociated2, kAssociated3, kAssociated1},
1068 config),
1069 UnorderedElementsAre(
1070 Pair(kPrimary, FirstPartySetEntry(kAssociated1, SiteType::kAssociated,
1071 absl::nullopt)),
1072 Pair(kAssociated2,
1073 FirstPartySetEntry(kAssociated1, SiteType::kAssociated,
1074 absl::nullopt)),
1075 Pair(kAssociated3,
1076 FirstPartySetEntry(kAssociated1, SiteType::kAssociated,
1077 absl::nullopt)),
1078 Pair(kAssociated1,
1079 FirstPartySetEntry(kAssociated1, SiteType::kPrimary,
1080 absl::nullopt))));
1081 }
1082
1083 // The primary of a policy set is also a primary of an existing set.
1084 // The policy set absorbs all of its primary's existing associated sites into
1085 // its associated sites.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_Additions_PolicyPrimaryIsExistingPrimary_PolicySetAbsorbsExistingAssociatedSites)1086 TEST_F(
1087 GlobalFirstPartySetsTest,
1088 ComputeConfig_Additions_PolicyPrimaryIsExistingPrimary_PolicySetAbsorbsExistingAssociatedSites) {
1089 GlobalFirstPartySets sets(
1090 kVersion,
1091 /*entries=*/
1092 {
1093 {kPrimary,
1094 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1095 {kAssociated1,
1096 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
1097 {kAssociated3,
1098 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
1099 },
1100 /*aliases=*/{});
1101 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1102 /*replacement_sets=*/{},
1103 /*addition_sets=*/{{
1104 {kPrimary,
1105 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1106 {kAssociated2,
1107 FirstPartySetEntry(kPrimary, SiteType::kAssociated, absl::nullopt)},
1108 }}));
1109 EXPECT_THAT(
1110 sets.FindEntries({kAssociated1, kAssociated2, kAssociated3, kPrimary},
1111 config),
1112 UnorderedElementsAre(
1113 Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
1114 absl::nullopt)),
1115 Pair(kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
1116 absl::nullopt)),
1117 Pair(kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
1118 absl::nullopt)),
1119 Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary,
1120 absl::nullopt))));
1121 }
1122
1123 // Existing set overlaps with both replacement and addition set.
TEST_F(GlobalFirstPartySetsTest,ComputeConfig_ReplacementsAndAdditions_SetListsOverlapWithSameExistingSet)1124 TEST_F(
1125 GlobalFirstPartySetsTest,
1126 ComputeConfig_ReplacementsAndAdditions_SetListsOverlapWithSameExistingSet) {
1127 GlobalFirstPartySets sets(
1128 kVersion,
1129 /*entries=*/
1130 {
1131 {kPrimary,
1132 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1133 {kAssociated1,
1134 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
1135 {kAssociated2,
1136 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)},
1137 },
1138 /*aliases=*/{});
1139 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1140 /*replacement_sets=*/
1141 {
1142 {
1143 {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
1144 absl::nullopt)},
1145 {kAssociated1,
1146 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
1147 absl::nullopt)},
1148 },
1149 },
1150 /*addition_sets=*/{
1151 {
1152 {kPrimary,
1153 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1154 {kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
1155 absl::nullopt)},
1156 },
1157 }));
1158 EXPECT_THAT(
1159 sets.FindEntries(
1160 {kAssociated1, kAssociated2, kAssociated3, kPrimary, kPrimary2},
1161 config),
1162 UnorderedElementsAre(
1163 Pair(kAssociated1,
1164 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
1165 absl::nullopt)),
1166 Pair(kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
1167 absl::nullopt)),
1168 Pair(kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated,
1169 absl::nullopt)),
1170 Pair(kPrimary,
1171 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)),
1172 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
1173 absl::nullopt))));
1174 }
1175
TEST_F(GlobalFirstPartySetsTest,TransitiveOverlap_TwoCommonPrimaries)1176 TEST_F(GlobalFirstPartySetsTest, TransitiveOverlap_TwoCommonPrimaries) {
1177 SchemefulSite primary0(GURL("https://primary0.test"));
1178 SchemefulSite associated_site0(GURL("https://associatedsite0.test"));
1179 SchemefulSite primary1(GURL("https://primary1.test"));
1180 SchemefulSite associated_site1(GURL("https://associatedsite1.test"));
1181 SchemefulSite primary2(GURL("https://primary2.test"));
1182 SchemefulSite associated_site2(GURL("https://associatedsite2.test"));
1183 SchemefulSite primary42(GURL("https://primary42.test"));
1184 SchemefulSite associated_site42(GURL("https://associatedsite42.test"));
1185 // {primary1, {associated_site1}} and {primary2, {associated_site2}}
1186 // transitively overlap with the existing set. primary1 takes primaryship of
1187 // the normalized addition set since it was provided first. The other addition
1188 // sets are unaffected.
1189 GlobalFirstPartySets sets(
1190 kVersion,
1191 /*entries=*/
1192 {
1193 {primary1,
1194 FirstPartySetEntry(primary1, SiteType::kPrimary, absl::nullopt)},
1195 {primary2, FirstPartySetEntry(primary1, SiteType::kAssociated, 0)},
1196 },
1197 /*aliases=*/{});
1198 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1199 /*replacement_sets=*/{},
1200 /*addition_sets=*/{
1201 {{primary0,
1202 FirstPartySetEntry(primary0, SiteType::kPrimary, absl::nullopt)},
1203 {associated_site0,
1204 FirstPartySetEntry(primary0, SiteType::kAssociated,
1205 absl::nullopt)}},
1206 {{primary1,
1207 FirstPartySetEntry(primary1, SiteType::kPrimary, absl::nullopt)},
1208 {associated_site1,
1209 FirstPartySetEntry(primary1, SiteType::kAssociated,
1210 absl::nullopt)}},
1211 {{primary2,
1212 FirstPartySetEntry(primary2, SiteType::kPrimary, absl::nullopt)},
1213 {associated_site2,
1214 FirstPartySetEntry(primary2, SiteType::kAssociated,
1215 absl::nullopt)}},
1216 {{primary42,
1217 FirstPartySetEntry(primary42, SiteType::kPrimary, absl::nullopt)},
1218 {associated_site42,
1219 FirstPartySetEntry(primary42, SiteType::kAssociated,
1220 absl::nullopt)}},
1221 }));
1222 EXPECT_THAT(
1223 sets.FindEntries(
1224 {
1225 associated_site0,
1226 associated_site1,
1227 associated_site2,
1228 associated_site42,
1229 primary0,
1230 primary1,
1231 primary2,
1232 primary42,
1233 },
1234 config),
1235 UnorderedElementsAre(
1236 Pair(associated_site0,
1237 FirstPartySetEntry(primary0, SiteType::kAssociated,
1238 absl::nullopt)),
1239 Pair(associated_site1,
1240 FirstPartySetEntry(primary1, SiteType::kAssociated,
1241 absl::nullopt)),
1242 Pair(associated_site2,
1243 FirstPartySetEntry(primary1, SiteType::kAssociated,
1244 absl::nullopt)),
1245 Pair(associated_site42,
1246 FirstPartySetEntry(primary42, SiteType::kAssociated,
1247 absl::nullopt)),
1248 Pair(primary0,
1249 FirstPartySetEntry(primary0, SiteType::kPrimary, absl::nullopt)),
1250 Pair(primary1,
1251 FirstPartySetEntry(primary1, SiteType::kPrimary, absl::nullopt)),
1252 Pair(primary2, FirstPartySetEntry(primary1, SiteType::kAssociated,
1253 absl::nullopt)),
1254 Pair(primary42, FirstPartySetEntry(primary42, SiteType::kPrimary,
1255 absl::nullopt))));
1256 }
1257
TEST_F(GlobalFirstPartySetsTest,TransitiveOverlap_TwoCommonAssociatedSites)1258 TEST_F(GlobalFirstPartySetsTest, TransitiveOverlap_TwoCommonAssociatedSites) {
1259 SchemefulSite primary0(GURL("https://primary0.test"));
1260 SchemefulSite associated_site0(GURL("https://associatedsite0.test"));
1261 SchemefulSite primary1(GURL("https://primary1.test"));
1262 SchemefulSite associated_site1(GURL("https://associatedsite1.test"));
1263 SchemefulSite primary2(GURL("https://primary2.test"));
1264 SchemefulSite associated_site2(GURL("https://associatedsite2.test"));
1265 SchemefulSite primary42(GURL("https://primary42.test"));
1266 SchemefulSite associated_site42(GURL("https://associatedsite42.test"));
1267 // {primary1, {associated_site1}} and {primary2, {associated_site2}}
1268 // transitively overlap with the existing set. primary2 takes primaryship of
1269 // the normalized addition set since it was provided first. The other addition
1270 // sets are unaffected.
1271 GlobalFirstPartySets sets(
1272 kVersion,
1273 /*entries=*/
1274 {
1275 {primary2,
1276 FirstPartySetEntry(primary2, SiteType::kPrimary, absl::nullopt)},
1277 {primary1, FirstPartySetEntry(primary2, SiteType::kAssociated, 0)},
1278 },
1279 /*aliases=*/{});
1280 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1281 /*replacement_sets=*/{},
1282 /*addition_sets=*/{
1283 {{primary0,
1284 FirstPartySetEntry(primary0, SiteType::kPrimary, absl::nullopt)},
1285 {associated_site0,
1286 FirstPartySetEntry(primary0, SiteType::kAssociated,
1287 absl::nullopt)}},
1288 {{primary2,
1289 FirstPartySetEntry(primary2, SiteType::kPrimary, absl::nullopt)},
1290 {associated_site2,
1291 FirstPartySetEntry(primary2, SiteType::kAssociated,
1292 absl::nullopt)}},
1293 {{primary1,
1294 FirstPartySetEntry(primary1, SiteType::kPrimary, absl::nullopt)},
1295 {associated_site1,
1296 FirstPartySetEntry(primary1, SiteType::kAssociated,
1297 absl::nullopt)}},
1298 {{primary42,
1299 FirstPartySetEntry(primary42, SiteType::kPrimary, absl::nullopt)},
1300 {associated_site42,
1301 FirstPartySetEntry(primary42, SiteType::kAssociated,
1302 absl::nullopt)}},
1303 }));
1304 EXPECT_THAT(
1305 sets.FindEntries(
1306 {
1307 associated_site0,
1308 associated_site1,
1309 associated_site2,
1310 associated_site42,
1311 primary0,
1312 primary1,
1313 primary2,
1314 primary42,
1315 },
1316 config),
1317 UnorderedElementsAre(
1318 Pair(associated_site0,
1319 FirstPartySetEntry(primary0, SiteType::kAssociated,
1320 absl::nullopt)),
1321 Pair(associated_site1,
1322 FirstPartySetEntry(primary2, SiteType::kAssociated,
1323 absl::nullopt)),
1324 Pair(associated_site2,
1325 FirstPartySetEntry(primary2, SiteType::kAssociated,
1326 absl::nullopt)),
1327 Pair(associated_site42,
1328 FirstPartySetEntry(primary42, SiteType::kAssociated,
1329 absl::nullopt)),
1330 Pair(primary0,
1331 FirstPartySetEntry(primary0, SiteType::kPrimary, absl::nullopt)),
1332 Pair(primary1, FirstPartySetEntry(primary2, SiteType::kAssociated,
1333 absl::nullopt)),
1334 Pair(primary2,
1335 FirstPartySetEntry(primary2, SiteType::kPrimary, absl::nullopt)),
1336 Pair(primary42, FirstPartySetEntry(primary42, SiteType::kPrimary,
1337 absl::nullopt))));
1338 }
1339
TEST_F(GlobalFirstPartySetsTest,InvalidPublicSetsVersion_ComputeConfig)1340 TEST_F(GlobalFirstPartySetsTest, InvalidPublicSetsVersion_ComputeConfig) {
1341 const GlobalFirstPartySets sets(
1342 base::Version(), /*entries=*/
1343 {
1344 {kPrimary,
1345 FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)},
1346 {kAssociated1,
1347 FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)},
1348 },
1349 /*aliases=*/{});
1350 ASSERT_TRUE(sets.empty());
1351
1352 FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation(
1353 /*replacement_sets=*/
1354 {
1355 {
1356 {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
1357 absl::nullopt)},
1358 {kAssociated2,
1359 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
1360 absl::nullopt)},
1361 },
1362 },
1363 /*addition_sets=*/{}));
1364
1365 // The config should still be nonempty, even though the component was invalid.
1366 EXPECT_FALSE(config.empty());
1367
1368 EXPECT_THAT(
1369 sets.FindEntries(
1370 {
1371 kPrimary,
1372 kPrimary2,
1373 kAssociated1,
1374 kAssociated2,
1375 },
1376 config),
1377 UnorderedElementsAre(
1378 Pair(kAssociated2,
1379 FirstPartySetEntry(kPrimary2, SiteType::kAssociated,
1380 absl::nullopt)),
1381 Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary,
1382 absl::nullopt))));
1383 }
1384
1385 class GlobalFirstPartySetsWithConfigTest
1386 : public PopulatedGlobalFirstPartySetsTest {
1387 public:
GlobalFirstPartySetsWithConfigTest()1388 GlobalFirstPartySetsWithConfigTest()
1389 : config_({
1390 // New entry:
1391 {kPrimary3, net::FirstPartySetEntryOverride(
1392 FirstPartySetEntry(kPrimary3,
1393 SiteType::kPrimary,
1394 absl::nullopt))},
1395 // Removed entry:
1396 {kAssociated1, net::FirstPartySetEntryOverride()},
1397 // Remapped entry:
1398 {kAssociated3,
1399 net::FirstPartySetEntryOverride(
1400 FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0))},
1401 // Removed alias:
1402 {kAssociated1Cctld, net::FirstPartySetEntryOverride()},
1403 }) {}
1404
config()1405 FirstPartySetsContextConfig& config() { return config_; }
1406
1407 private:
1408 FirstPartySetsContextConfig config_;
1409 };
1410
TEST_F(GlobalFirstPartySetsWithConfigTest,ComputeMetadata)1411 TEST_F(GlobalFirstPartySetsWithConfigTest, ComputeMetadata) {
1412 FirstPartySetEntry example_primary_entry(kPrimary, SiteType::kPrimary,
1413 absl::nullopt);
1414 FirstPartySetEntry foo_primary_entry(kPrimary3, SiteType::kPrimary,
1415 absl::nullopt);
1416 FirstPartySetEntry foo_associated_entry(kPrimary3, SiteType::kAssociated, 0);
1417
1418 // kAssociated1 has been removed from its set.
1419 EXPECT_EQ(global_sets().ComputeMetadata(kAssociated1, &kPrimary, config()),
1420 FirstPartySetMetadata(nullptr, &example_primary_entry));
1421
1422 // kAssociated3 and kPrimary3 are sites in a new set.
1423 EXPECT_EQ(global_sets().ComputeMetadata(kAssociated3, &kPrimary3, config()),
1424 FirstPartySetMetadata(
1425
1426 &foo_associated_entry, &foo_primary_entry));
1427 }
1428
1429 } // namespace net
1430