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