xref: /aosp_15_r20/external/cronet/net/reporting/reporting_service_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 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/reporting/reporting_service.h"
6 
7 #include <memory>
8 #include <optional>
9 #include <string>
10 
11 #include "base/functional/bind.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/time/tick_clock.h"
16 #include "base/values.h"
17 #include "net/base/features.h"
18 #include "net/base/isolation_info.h"
19 #include "net/base/network_anonymization_key.h"
20 #include "net/base/schemeful_site.h"
21 #include "net/reporting/mock_persistent_reporting_store.h"
22 #include "net/reporting/reporting_browsing_data_remover.h"
23 #include "net/reporting/reporting_cache.h"
24 #include "net/reporting/reporting_context.h"
25 #include "net/reporting/reporting_endpoint.h"
26 #include "net/reporting/reporting_policy.h"
27 #include "net/reporting/reporting_report.h"
28 #include "net/reporting/reporting_service.h"
29 #include "net/reporting/reporting_test_util.h"
30 #include "net/test/test_with_task_environment.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "url/gurl.h"
34 #include "url/origin.h"
35 
36 namespace net {
37 namespace {
38 
39 using CommandType = MockPersistentReportingStore::Command::Type;
40 
41 // The tests are parametrized on a boolean value which represents whether to use
42 // a MockPersistentReportingStore (if false, no store is used).
43 class ReportingServiceTest : public ::testing::TestWithParam<bool>,
44                              public WithTaskEnvironment {
45  protected:
46   const GURL kUrl_ = GURL("https://origin/path");
47   const GURL kUrl2_ = GURL("https://origin2/path");
48   const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
49   const url::Origin kOrigin2_ = url::Origin::Create(kUrl2_);
50   const GURL kEndpoint_ = GURL("https://endpoint/");
51   const GURL kEndpoint2_ = GURL("https://endpoint2/");
52   const std::string kUserAgent_ = "Mozilla/1.0";
53   const std::string kGroup_ = "group";
54   const std::string kGroup2_ = "group2";
55   const std::string kType_ = "type";
56   const std::optional<base::UnguessableToken> kReportingSource_ =
57       base::UnguessableToken::Create();
58   const NetworkAnonymizationKey kNak_ =
59       NetworkAnonymizationKey::CreateSameSite(SchemefulSite(kOrigin_));
60   const NetworkAnonymizationKey kNak2_ =
61       NetworkAnonymizationKey::CreateSameSite(SchemefulSite(kOrigin2_));
62   const ReportingEndpointGroupKey kGroupKey_ =
63       ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_);
64   const ReportingEndpointGroupKey kGroupKey2_ =
65       ReportingEndpointGroupKey(kNak2_, kOrigin2_, kGroup_);
66   const IsolationInfo kIsolationInfo_ =
67       IsolationInfo::Create(IsolationInfo::RequestType::kOther,
68                             kOrigin_,
69                             kOrigin_,
70                             SiteForCookies::FromOrigin(kOrigin_));
71 
ReportingServiceTest()72   ReportingServiceTest() {
73     feature_list_.InitAndEnableFeature(
74         features::kPartitionNelAndReportingByNetworkIsolationKey);
75     Init();
76   }
77 
78   // Initializes, or re-initializes, |service_| and its dependencies.
Init()79   void Init() {
80     if (GetParam()) {
81       store_ = std::make_unique<MockPersistentReportingStore>();
82     } else {
83       store_ = nullptr;
84     }
85 
86     auto test_context = std::make_unique<TestReportingContext>(
87         &clock_, &tick_clock_, ReportingPolicy(), store_.get());
88     context_ = test_context.get();
89 
90     service_ = ReportingService::CreateForTesting(std::move(test_context));
91   }
92 
93   // If the store exists, simulate finishing loading the store, which should
94   // make the rest of the test run synchronously.
FinishLoading(bool load_success)95   void FinishLoading(bool load_success) {
96     if (store_) {
97       store_->FinishLoading(load_success);
98     }
99   }
100 
store()101   MockPersistentReportingStore* store() { return store_.get(); }
context()102   TestReportingContext* context() { return context_; }
service()103   ReportingService* service() { return service_.get(); }
104 
105  private:
106   base::test::ScopedFeatureList feature_list_;
107 
108   base::SimpleTestClock clock_;
109   base::SimpleTestTickClock tick_clock_;
110 
111   std::unique_ptr<MockPersistentReportingStore> store_;
112   std::unique_ptr<ReportingService> service_;
113   raw_ptr<TestReportingContext> context_ = nullptr;
114 };
115 
TEST_P(ReportingServiceTest,QueueReport)116 TEST_P(ReportingServiceTest, QueueReport) {
117   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
118                          kType_, base::Value::Dict(), 0);
119   FinishLoading(true /* load_success */);
120 
121   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
122   context()->cache()->GetReports(&reports);
123   ASSERT_EQ(1u, reports.size());
124   EXPECT_EQ(kUrl_, reports[0]->url);
125   EXPECT_EQ(kNak_, reports[0]->network_anonymization_key);
126   EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
127   EXPECT_EQ(kGroup_, reports[0]->group);
128   EXPECT_EQ(kType_, reports[0]->type);
129 }
130 
TEST_P(ReportingServiceTest,QueueReportSanitizeUrl)131 TEST_P(ReportingServiceTest, QueueReportSanitizeUrl) {
132   // Same as kUrl_ but with username, password, and fragment.
133   GURL url = GURL("https://username:password@origin/path#fragment");
134   service()->QueueReport(url, kReportingSource_, kNak_, kUserAgent_, kGroup_,
135                          kType_, base::Value::Dict(), 0);
136   FinishLoading(true /* load_success */);
137 
138   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
139   context()->cache()->GetReports(&reports);
140   ASSERT_EQ(1u, reports.size());
141   EXPECT_EQ(kUrl_, reports[0]->url);
142   EXPECT_EQ(kNak_, reports[0]->network_anonymization_key);
143   EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
144   EXPECT_EQ(kGroup_, reports[0]->group);
145   EXPECT_EQ(kType_, reports[0]->type);
146 }
147 
TEST_P(ReportingServiceTest,DontQueueReportInvalidUrl)148 TEST_P(ReportingServiceTest, DontQueueReportInvalidUrl) {
149   GURL url = GURL("https://");
150   // This does not trigger an attempt to load from the store because the url
151   // is immediately rejected as invalid.
152   service()->QueueReport(url, kReportingSource_, kNak_, kUserAgent_, kGroup_,
153                          kType_, base::Value::Dict(), 0);
154 
155   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
156   context()->cache()->GetReports(&reports);
157   ASSERT_EQ(0u, reports.size());
158 }
159 
TEST_P(ReportingServiceTest,QueueReportNetworkIsolationKeyDisabled)160 TEST_P(ReportingServiceTest, QueueReportNetworkIsolationKeyDisabled) {
161   base::test::ScopedFeatureList feature_list;
162   feature_list.InitAndDisableFeature(
163       features::kPartitionNelAndReportingByNetworkIsolationKey);
164 
165   // Re-create the store, so it reads the new feature value.
166   Init();
167 
168   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
169                          kType_, base::Value::Dict(), 0);
170   FinishLoading(true /* load_success */);
171 
172   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
173   context()->cache()->GetReports(&reports);
174   ASSERT_EQ(1u, reports.size());
175 
176   // NetworkAnonymizationKey should be empty, instead of kNak_;
177   EXPECT_EQ(NetworkAnonymizationKey(), reports[0]->network_anonymization_key);
178   EXPECT_NE(kNak_, reports[0]->network_anonymization_key);
179 
180   EXPECT_EQ(kUrl_, reports[0]->url);
181   EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
182   EXPECT_EQ(kGroup_, reports[0]->group);
183   EXPECT_EQ(kType_, reports[0]->type);
184 }
185 
TEST_P(ReportingServiceTest,ProcessReportToHeader)186 TEST_P(ReportingServiceTest, ProcessReportToHeader) {
187   service()->ProcessReportToHeader(kOrigin_, kNak_,
188                                    "{\"endpoints\":[{\"url\":\"" +
189                                        kEndpoint_.spec() +
190                                        "\"}],"
191                                        "\"group\":\"" +
192                                        kGroup_ +
193                                        "\","
194                                        "\"max_age\":86400}");
195   FinishLoading(true /* load_success */);
196 
197   EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
198   EXPECT_TRUE(context()->cache()->GetEndpointForTesting(
199       ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_), kEndpoint_));
200 }
201 
TEST_P(ReportingServiceTest,ProcessReportingEndpointsHeader)202 TEST_P(ReportingServiceTest, ProcessReportingEndpointsHeader) {
203   base::test::ScopedFeatureList feature_list;
204   feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
205   auto parsed_header =
206       ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\"");
207   ASSERT_TRUE(parsed_header.has_value());
208   service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
209                                            kIsolationInfo_, *parsed_header);
210   FinishLoading(true /* load_success */);
211 
212   // Endpoint should not be part of the persistent store.
213   EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
214   // Endpoint should be associated with the reporting source.
215   ReportingEndpoint cached_endpoint =
216       context()->cache()->GetV1EndpointForTesting(*kReportingSource_, kGroup_);
217   EXPECT_TRUE(cached_endpoint);
218 
219   // Ensure that the NAK is stored properly with the endpoint group.
220   EXPECT_FALSE(cached_endpoint.group_key.network_anonymization_key.IsEmpty());
221 }
222 
TEST_P(ReportingServiceTest,ProcessReportingEndpointsHeaderNetworkIsolationKeyDisabled)223 TEST_P(ReportingServiceTest,
224        ProcessReportingEndpointsHeaderNetworkIsolationKeyDisabled) {
225   base::test::ScopedFeatureList feature_list;
226   feature_list.InitWithFeatures(
227       {net::features::kDocumentReporting},
228       {features::kPartitionNelAndReportingByNetworkIsolationKey});
229 
230   // Re-create the store, so it reads the new feature value.
231   Init();
232 
233   auto parsed_header =
234       ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\"");
235   ASSERT_TRUE(parsed_header.has_value());
236   service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
237                                            kIsolationInfo_, *parsed_header);
238   FinishLoading(true /* load_success */);
239 
240   // Endpoint should not be part of the persistent store.
241   EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
242   // Endpoint should be associated with the reporting source.
243   ReportingEndpoint cached_endpoint =
244       context()->cache()->GetV1EndpointForTesting(*kReportingSource_, kGroup_);
245   EXPECT_TRUE(cached_endpoint);
246 
247   // When isolation is disabled, cached endpoints should have a null NAK.
248   EXPECT_TRUE(cached_endpoint.group_key.network_anonymization_key.IsEmpty());
249 }
250 
TEST_P(ReportingServiceTest,SendReportsAndRemoveSource)251 TEST_P(ReportingServiceTest, SendReportsAndRemoveSource) {
252   base::test::ScopedFeatureList feature_list;
253   feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
254   auto parsed_header =
255       ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\", " +
256                               kGroup2_ + "=\"" + kEndpoint2_.spec() + "\"");
257   ASSERT_TRUE(parsed_header.has_value());
258   service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
259                                            kIsolationInfo_, *parsed_header);
260   // This report should be sent immediately, starting the delivery agent timer.
261   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
262                          kType_, base::Value::Dict(), 0);
263 
264   FinishLoading(true /* load_success */);
265 
266   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
267   context()->cache()->GetReports(&reports);
268   ASSERT_EQ(1u, reports.size());
269   EXPECT_EQ(0u, context()->cache()->GetReportCountWithStatusForTesting(
270                     ReportingReport::Status::QUEUED));
271 
272   // Now simulate the source being destroyed.
273   service()->SendReportsAndRemoveSource(*kReportingSource_);
274 
275   // There should be no queued reports, but the previously sent report should
276   // still be pending.
277   EXPECT_EQ(0u, context()->cache()->GetReportCountWithStatusForTesting(
278                     ReportingReport::Status::QUEUED));
279   EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
280                     ReportingReport::Status::PENDING));
281   // Source should be marked as expired.
282   ASSERT_TRUE(
283       context()->cache()->GetExpiredSources().contains(*kReportingSource_));
284 }
285 
286 // Flaky in ChromeOS: crbug.com/1356127
287 #if BUILDFLAG(IS_CHROMEOS)
288 #define MAYBE_SendReportsAndRemoveSourceWithPendingReports \
289   DISABLED_SendReportsAndRemoveSourceWithPendingReports
290 #else
291 #define MAYBE_SendReportsAndRemoveSourceWithPendingReports \
292   SendReportsAndRemoveSourceWithPendingReports
293 #endif
TEST_P(ReportingServiceTest,MAYBE_SendReportsAndRemoveSourceWithPendingReports)294 TEST_P(ReportingServiceTest,
295        MAYBE_SendReportsAndRemoveSourceWithPendingReports) {
296   base::test::ScopedFeatureList feature_list;
297   feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
298   auto parsed_header =
299       ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\", " +
300                               kGroup2_ + "=\"" + kEndpoint2_.spec() + "\"");
301   ASSERT_TRUE(parsed_header.has_value());
302   service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
303                                            kIsolationInfo_, *parsed_header);
304   // This report should be sent immediately, starting the delivery agent timer.
305   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
306                          kType_, base::Value::Dict(), 0);
307 
308   FinishLoading(true /* load_success */);
309 
310   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
311   context()->cache()->GetReports(&reports);
312   ASSERT_EQ(1u, reports.size());
313   EXPECT_EQ(0u, context()->cache()->GetReportCountWithStatusForTesting(
314                     ReportingReport::Status::QUEUED));
315   EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
316                     ReportingReport::Status::PENDING));
317 
318   // Queue another report, which should remain queued.
319   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
320                          kType_, base::Value::Dict(), 0);
321   EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
322                     ReportingReport::Status::QUEUED));
323   EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
324                     ReportingReport::Status::PENDING));
325 
326   // Now simulate the source being destroyed.
327   service()->SendReportsAndRemoveSource(*kReportingSource_);
328 
329   // The report should still be queued, while the source should be marked as
330   // expired. (The original report is still pending.)
331   EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
332                     ReportingReport::Status::QUEUED));
333   EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
334                     ReportingReport::Status::PENDING));
335   ASSERT_TRUE(
336       context()->cache()->GetExpiredSources().contains(kReportingSource_));
337 }
338 
TEST_P(ReportingServiceTest,ProcessReportingEndpointsHeaderPathAbsolute)339 TEST_P(ReportingServiceTest, ProcessReportingEndpointsHeaderPathAbsolute) {
340   base::test::ScopedFeatureList feature_list;
341   feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
342   auto parsed_header = ParseReportingEndpoints(kGroup_ + "=\"/path-absolute\"");
343   ASSERT_TRUE(parsed_header.has_value());
344   service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
345                                            kIsolationInfo_, *parsed_header);
346   FinishLoading(true /* load_success */);
347 
348   // Endpoint should not be part of the persistent store.
349   EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
350   // Endpoint should be associated with the reporting source.
351   ReportingEndpoint endpoint =
352       context()->cache()->GetV1EndpointForTesting(*kReportingSource_, kGroup_);
353   EXPECT_TRUE(endpoint);
354   // Endpoint should have the correct path.
355   EXPECT_EQ(kUrl_.Resolve("/path-absolute"), endpoint.info.url);
356 }
357 
TEST_P(ReportingServiceTest,ProcessReportToHeaderPathAbsolute)358 TEST_P(ReportingServiceTest, ProcessReportToHeaderPathAbsolute) {
359   service()->ProcessReportToHeader(
360       kOrigin_, kNak_,
361       "{\"endpoints\":[{\"url\":\"/path-absolute\"}],"
362       "\"group\":\"" +
363           kGroup_ +
364           "\","
365           "\"max_age\":86400}");
366   FinishLoading(true /* load_success */);
367 
368   EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
369 }
370 
TEST_P(ReportingServiceTest,ProcessReportToHeader_TooLong)371 TEST_P(ReportingServiceTest, ProcessReportToHeader_TooLong) {
372   const std::string header_too_long =
373       "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
374       "\"}],"
375       "\"group\":\"" +
376       kGroup_ +
377       "\","
378       "\"max_age\":86400," +
379       "\"junk\":\"" + std::string(32 * 1024, 'a') + "\"}";
380   // This does not trigger an attempt to load from the store because the header
381   // is immediately rejected as invalid.
382   service()->ProcessReportToHeader(kOrigin_, kNak_, header_too_long);
383 
384   EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
385 }
386 
TEST_P(ReportingServiceTest,ProcessReportToHeader_TooDeep)387 TEST_P(ReportingServiceTest, ProcessReportToHeader_TooDeep) {
388   const std::string header_too_deep = "{\"endpoints\":[{\"url\":\"" +
389                                       kEndpoint_.spec() +
390                                       "\"}],"
391                                       "\"group\":\"" +
392                                       kGroup_ +
393                                       "\","
394                                       "\"max_age\":86400," +
395                                       "\"junk\":[[[[[[[[[[]]]]]]]]]]}";
396   // This does not trigger an attempt to load from the store because the header
397   // is immediately rejected as invalid.
398   service()->ProcessReportToHeader(kOrigin_, kNak_, header_too_deep);
399 
400   EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
401 }
402 
TEST_P(ReportingServiceTest,ProcessReportToHeaderNetworkIsolationKeyDisabled)403 TEST_P(ReportingServiceTest, ProcessReportToHeaderNetworkIsolationKeyDisabled) {
404   base::test::ScopedFeatureList feature_list;
405   feature_list.InitAndDisableFeature(
406       features::kPartitionNelAndReportingByNetworkIsolationKey);
407 
408   // Re-create the store, so it reads the new feature value.
409   Init();
410 
411   service()->ProcessReportToHeader(kOrigin_, kNak_,
412                                    "{\"endpoints\":[{\"url\":\"" +
413                                        kEndpoint_.spec() +
414                                        "\"}],"
415                                        "\"group\":\"" +
416                                        kGroup_ +
417                                        "\","
418                                        "\"max_age\":86400}");
419   FinishLoading(true /* load_success */);
420 
421   EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
422   EXPECT_FALSE(context()->cache()->GetEndpointForTesting(
423       ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_), kEndpoint_));
424   EXPECT_TRUE(context()->cache()->GetEndpointForTesting(
425       ReportingEndpointGroupKey(NetworkAnonymizationKey(), kOrigin_, kGroup_),
426       kEndpoint_));
427 }
428 
TEST_P(ReportingServiceTest,WriteToStore)429 TEST_P(ReportingServiceTest, WriteToStore) {
430   if (!store()) {
431     return;
432   }
433 
434   MockPersistentReportingStore::CommandList expected_commands;
435 
436   // This first call to any public method triggers a load. The load will block
437   // until we call FinishLoading.
438   service()->ProcessReportToHeader(kOrigin_, kNak_,
439                                    "{\"endpoints\":[{\"url\":\"" +
440                                        kEndpoint_.spec() +
441                                        "\"}],"
442                                        "\"group\":\"" +
443                                        kGroup_ +
444                                        "\","
445                                        "\"max_age\":86400}");
446   expected_commands.emplace_back(CommandType::LOAD_REPORTING_CLIENTS);
447   EXPECT_THAT(store()->GetAllCommands(),
448               testing::UnorderedElementsAreArray(expected_commands));
449 
450   // Unblock the load. The will let the remaining calls to the service complete
451   // without blocking.
452   FinishLoading(true /* load_success */);
453   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
454                                  kGroupKey_, kEndpoint_);
455   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
456                                  kGroupKey_);
457   EXPECT_THAT(store()->GetAllCommands(),
458               testing::UnorderedElementsAreArray(expected_commands));
459 
460   service()->ProcessReportToHeader(kOrigin2_, kNak2_,
461                                    "{\"endpoints\":[{\"url\":\"" +
462                                        kEndpoint_.spec() +
463                                        "\"}],"
464                                        "\"group\":\"" +
465                                        kGroup_ +
466                                        "\","
467                                        "\"max_age\":86400}");
468   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
469                                  kGroupKey2_, kEndpoint_);
470   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
471                                  kGroupKey2_);
472   EXPECT_THAT(store()->GetAllCommands(),
473               testing::UnorderedElementsAreArray(expected_commands));
474 
475   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
476                          kType_, base::Value::Dict(), 0);
477   expected_commands.emplace_back(
478       CommandType::UPDATE_REPORTING_ENDPOINT_GROUP_ACCESS_TIME, kGroupKey_);
479   EXPECT_THAT(store()->GetAllCommands(),
480               testing::UnorderedElementsAreArray(expected_commands));
481 
482   service()->RemoveBrowsingData(
483       ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS,
484       base::BindRepeating(
485           [](const url::Origin& origin) { return origin.host() == "origin"; }));
486   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
487                                  kGroupKey_, kEndpoint_);
488   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
489                                  kGroupKey_);
490   expected_commands.emplace_back(CommandType::FLUSH);
491   EXPECT_THAT(store()->GetAllCommands(),
492               testing::UnorderedElementsAreArray(expected_commands));
493 
494   service()->RemoveAllBrowsingData(
495       ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS);
496   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
497                                  kGroupKey2_, kEndpoint_);
498   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
499                                  kGroupKey2_);
500   expected_commands.emplace_back(CommandType::FLUSH);
501   EXPECT_THAT(store()->GetAllCommands(),
502               testing::UnorderedElementsAreArray(expected_commands));
503 }
504 
TEST_P(ReportingServiceTest,WaitUntilLoadFinishesBeforeWritingToStore)505 TEST_P(ReportingServiceTest, WaitUntilLoadFinishesBeforeWritingToStore) {
506   if (!store()) {
507     return;
508   }
509 
510   MockPersistentReportingStore::CommandList expected_commands;
511 
512   // This first call to any public method triggers a load. The load will block
513   // until we call FinishLoading.
514   service()->ProcessReportToHeader(kOrigin_, kNak_,
515                                    "{\"endpoints\":[{\"url\":\"" +
516                                        kEndpoint_.spec() +
517                                        "\"}],"
518                                        "\"group\":\"" +
519                                        kGroup_ +
520                                        "\","
521                                        "\"max_age\":86400}");
522   expected_commands.emplace_back(CommandType::LOAD_REPORTING_CLIENTS);
523   EXPECT_THAT(store()->GetAllCommands(),
524               testing::UnorderedElementsAreArray(expected_commands));
525 
526   service()->ProcessReportToHeader(kOrigin2_, kNak2_,
527                                    "{\"endpoints\":[{\"url\":\"" +
528                                        kEndpoint_.spec() +
529                                        "\"}],"
530                                        "\"group\":\"" +
531                                        kGroup_ +
532                                        "\","
533                                        "\"max_age\":86400}");
534   EXPECT_THAT(store()->GetAllCommands(),
535               testing::UnorderedElementsAreArray(expected_commands));
536 
537   service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
538                          kType_, base::Value::Dict(), 0);
539   EXPECT_THAT(store()->GetAllCommands(),
540               testing::UnorderedElementsAreArray(expected_commands));
541 
542   service()->RemoveBrowsingData(
543       ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS,
544       base::BindRepeating(
545           [](const url::Origin& origin) { return origin.host() == "origin"; }));
546   EXPECT_THAT(store()->GetAllCommands(),
547               testing::UnorderedElementsAreArray(expected_commands));
548 
549   service()->RemoveAllBrowsingData(
550       ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS);
551   EXPECT_THAT(store()->GetAllCommands(),
552               testing::UnorderedElementsAreArray(expected_commands));
553 
554   // Unblock the load. The will let the remaining calls to the service complete
555   // without blocking.
556   FinishLoading(true /* load_success */);
557   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
558                                  kGroupKey_, kEndpoint_);
559   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
560                                  kGroupKey2_, kEndpoint_);
561   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
562                                  kGroupKey_);
563   expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
564                                  kGroupKey2_);
565   expected_commands.emplace_back(
566       CommandType::UPDATE_REPORTING_ENDPOINT_GROUP_ACCESS_TIME, kGroupKey_);
567   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
568                                  kGroupKey_, kEndpoint_);
569   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
570                                  kGroupKey_);
571   expected_commands.emplace_back(CommandType::FLUSH);
572   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
573                                  kGroupKey2_, kEndpoint_);
574   expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
575                                  kGroupKey2_);
576   expected_commands.emplace_back(CommandType::FLUSH);
577   EXPECT_THAT(store()->GetAllCommands(),
578               testing::UnorderedElementsAreArray(expected_commands));
579 }
580 
581 INSTANTIATE_TEST_SUITE_P(ReportingServiceStoreTest,
582                          ReportingServiceTest,
583                          ::testing::Bool());
584 }  // namespace
585 }  // namespace net
586