• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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