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_delivery_agent.h"
6
7 #include <optional>
8 #include <vector>
9
10 #include "base/json/json_reader.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/test/metrics/histogram_tester.h"
13 #include "base/test/scoped_feature_list.h"
14 #include "base/test/simple_test_tick_clock.h"
15 #include "base/test/values_test_util.h"
16 #include "base/time/time.h"
17 #include "base/timer/mock_timer.h"
18 #include "base/unguessable_token.h"
19 #include "base/values.h"
20 #include "net/base/backoff_entry.h"
21 #include "net/base/features.h"
22 #include "net/base/isolation_info.h"
23 #include "net/base/network_anonymization_key.h"
24 #include "net/base/schemeful_site.h"
25 #include "net/reporting/reporting_cache.h"
26 #include "net/reporting/reporting_report.h"
27 #include "net/reporting/reporting_test_util.h"
28 #include "net/reporting/reporting_uploader.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "url/gurl.h"
31 #include "url/origin.h"
32
33 namespace net {
34 namespace {
35
36 constexpr char kReportingUploadHeaderTypeHistogram[] =
37 "Net.Reporting.UploadHeaderType";
38
39 class ReportingDeliveryAgentTest : public ReportingTestBase {
40 protected:
ReportingDeliveryAgentTest()41 ReportingDeliveryAgentTest() {
42 // This is a private API of the reporting service, so no need to test the
43 // case kPartitionNelAndReportingByNetworkIsolationKey is disabled - the
44 // feature is only applied at the entry points of the service.
45 feature_list_.InitAndEnableFeature(
46 features::kPartitionNelAndReportingByNetworkIsolationKey);
47
48 ReportingPolicy policy;
49 policy.endpoint_backoff_policy.num_errors_to_ignore = 0;
50 policy.endpoint_backoff_policy.initial_delay_ms = 60000;
51 policy.endpoint_backoff_policy.multiply_factor = 2.0;
52 policy.endpoint_backoff_policy.jitter_factor = 0.0;
53 policy.endpoint_backoff_policy.maximum_backoff_ms = -1;
54 policy.endpoint_backoff_policy.entry_lifetime_ms = 0;
55 policy.endpoint_backoff_policy.always_use_initial_delay = false;
56 UsePolicy(policy);
57 }
58
AddReport(const std::optional<base::UnguessableToken> & reporting_source,const NetworkAnonymizationKey & network_anonymization_key,const GURL & url,const std::string & group)59 void AddReport(const std::optional<base::UnguessableToken>& reporting_source,
60 const NetworkAnonymizationKey& network_anonymization_key,
61 const GURL& url,
62 const std::string& group) {
63 base::Value::Dict report_body;
64 report_body.Set("key", "value");
65 cache()->AddReport(reporting_source, network_anonymization_key, url,
66 kUserAgent_, group, kType_, std::move(report_body),
67 0 /* depth */, tick_clock()->NowTicks() /* queued */,
68 0 /* attempts */);
69 }
70
71 // The first report added to the cache is uploaded immediately, and a timer is
72 // started for all subsequent reports (which may then be batched). To test
73 // behavior involving batching multiple reports, we need to add, upload, and
74 // immediately resolve a dummy report to prime the delivery timer.
UploadFirstReportAndStartTimer()75 void UploadFirstReportAndStartTimer() {
76 ReportingEndpointGroupKey dummy_group(
77 NetworkAnonymizationKey(),
78 url::Origin::Create(GURL("https://dummy.test")), "dummy");
79 ASSERT_TRUE(SetEndpointInCache(
80 dummy_group, GURL("https://dummy.test/upload"), kExpires_));
81 AddReport(std::nullopt, dummy_group.network_anonymization_key,
82 dummy_group.origin.GetURL(), dummy_group.group_name);
83
84 ASSERT_EQ(1u, pending_uploads().size());
85 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
86 EXPECT_EQ(0u, pending_uploads().size());
87 EXPECT_TRUE(delivery_timer()->IsRunning());
88 }
89
90 // Prime delivery timer with a document report with a endpoint group that
91 // has matching reporting_source.
UploadFirstDocumentReportAndStartTimer()92 void UploadFirstDocumentReportAndStartTimer() {
93 ReportingEndpointGroupKey dummy_group(
94 kNak_, kDocumentReportingSource_,
95 url::Origin::Create(GURL("https://dummy.test")), "dummy");
96 SetV1EndpointInCache(dummy_group, kDocumentReportingSource_,
97 kIsolationInfo_, GURL("https://dummy.test/upload"));
98 AddReport(kDocumentReportingSource_, dummy_group.network_anonymization_key,
99 dummy_group.origin.GetURL(), dummy_group.group_name);
100
101 ASSERT_EQ(1u, pending_uploads().size());
102 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
103 EXPECT_EQ(0u, pending_uploads().size());
104 EXPECT_TRUE(delivery_timer()->IsRunning());
105 }
106
SendReportsForSource(base::UnguessableToken reporting_source)107 void SendReportsForSource(base::UnguessableToken reporting_source) {
108 delivery_agent()->SendReportsForSource(reporting_source);
109 }
110
111 base::test::ScopedFeatureList feature_list_;
112
113 const GURL kUrl_ = GURL("https://origin/path");
114 const GURL kOtherUrl_ = GURL("https://other-origin/path");
115 const GURL kSubdomainUrl_ = GURL("https://sub.origin/path");
116 const url::Origin kOrigin_ = url::Origin::Create(GURL("https://origin/"));
117 const url::Origin kOtherOrigin_ =
118 url::Origin::Create(GURL("https://other-origin/"));
119 const std::optional<base::UnguessableToken> kEmptyReportingSource_ =
120 std::nullopt;
121 const base::UnguessableToken kDocumentReportingSource_ =
122 base::UnguessableToken::Create();
123 const NetworkAnonymizationKey kNak_ =
124 NetworkAnonymizationKey::CreateSameSite(SchemefulSite(kOrigin_));
125 const NetworkAnonymizationKey kOtherNak_ =
126 NetworkAnonymizationKey::CreateSameSite(SchemefulSite(kOtherOrigin_));
127 const IsolationInfo kIsolationInfo_ =
128 IsolationInfo::Create(IsolationInfo::RequestType::kOther,
129 kOrigin_,
130 kOrigin_,
131 SiteForCookies::FromOrigin(kOrigin_));
132 const IsolationInfo kOtherIsolationInfo_ =
133 IsolationInfo::Create(IsolationInfo::RequestType::kOther,
134 kOtherOrigin_,
135 kOtherOrigin_,
136 SiteForCookies::FromOrigin(kOtherOrigin_));
137 const GURL kEndpoint_ = GURL("https://endpoint/");
138 const std::string kUserAgent_ = "Mozilla/1.0";
139 const std::string kGroup_ = "group";
140 const std::string kType_ = "type";
141 const base::Time kExpires_ = base::Time::Now() + base::Days(7);
142 const ReportingEndpointGroupKey kGroupKey_ =
143 ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_);
144 const ReportingEndpointGroupKey kDocumentGroupKey_ =
145 ReportingEndpointGroupKey(kGroupKey_, kDocumentReportingSource_);
146 };
147
TEST_F(ReportingDeliveryAgentTest,SuccessfulImmediateUpload)148 TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateUpload) {
149 base::HistogramTester histograms;
150 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
151 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
152
153 // Upload is automatically started when cache is modified.
154
155 ASSERT_EQ(1u, pending_uploads().size());
156 EXPECT_EQ(kEndpoint_, pending_uploads()[0]->url());
157 {
158 auto value = pending_uploads()[0]->GetValue();
159
160 ASSERT_TRUE(value->is_list());
161 ASSERT_EQ(1u, value->GetList().size());
162
163 const base::Value& report = value->GetList()[0];
164 ASSERT_TRUE(report.is_dict());
165 const base::Value::Dict& report_dict = report.GetDict();
166 EXPECT_EQ(5u, report_dict.size());
167
168 ExpectDictIntegerValue(0, report_dict, "age");
169 ExpectDictStringValue(kType_, report_dict, "type");
170 ExpectDictStringValue(kUrl_.spec(), report_dict, "url");
171 ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
172 const base::Value::Dict* body = report_dict.FindDict("body");
173 EXPECT_EQ("value", *body->FindString("key"));
174 }
175 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
176
177 // Successful upload should remove delivered reports.
178 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
179 cache()->GetReports(&reports);
180 EXPECT_TRUE(reports.empty());
181 histograms.ExpectBucketCount(
182 kReportingUploadHeaderTypeHistogram,
183 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportTo, 1);
184 histograms.ExpectBucketCount(
185 kReportingUploadHeaderTypeHistogram,
186 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportingEndpoints,
187 0);
188
189 {
190 ReportingEndpoint::Statistics stats =
191 GetEndpointStatistics(kGroupKey_, kEndpoint_);
192 EXPECT_EQ(1, stats.attempted_uploads);
193 EXPECT_EQ(1, stats.successful_uploads);
194 EXPECT_EQ(1, stats.attempted_reports);
195 EXPECT_EQ(1, stats.successful_reports);
196 }
197
198 // TODO(dcreager): Check that BackoffEntry was informed of success.
199 }
200
TEST_F(ReportingDeliveryAgentTest,ReportToHeaderCountedCorrectly)201 TEST_F(ReportingDeliveryAgentTest, ReportToHeaderCountedCorrectly) {
202 base::HistogramTester histograms;
203
204 // Set an endpoint with no reporting source (as if configured with the
205 // Report-To header).
206 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
207
208 // Add and upload a report with an associated source.
209 AddReport(kDocumentReportingSource_, kNak_, kUrl_, kGroup_);
210 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
211
212 // Successful upload should count this as a Report-To delivery, even though
213 // the report itself had a reporting source.
214 histograms.ExpectBucketCount(
215 kReportingUploadHeaderTypeHistogram,
216 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportTo, 1);
217 histograms.ExpectBucketCount(
218 kReportingUploadHeaderTypeHistogram,
219 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportingEndpoints,
220 0);
221 }
222
TEST_F(ReportingDeliveryAgentTest,SuccessfulImmediateUploadDocumentReport)223 TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateUploadDocumentReport) {
224 base::HistogramTester histograms;
225
226 SetV1EndpointInCache(kDocumentGroupKey_, kDocumentReportingSource_,
227 kIsolationInfo_, kEndpoint_);
228 AddReport(kDocumentReportingSource_, kNak_, kUrl_, kGroup_);
229
230 // Upload is automatically started when cache is modified.
231
232 ASSERT_EQ(1u, pending_uploads().size());
233 EXPECT_EQ(kEndpoint_, pending_uploads()[0]->url());
234 {
235 const auto value = pending_uploads()[0]->GetValue();
236
237 ASSERT_TRUE(value->is_list());
238 ASSERT_EQ(1u, value->GetList().size());
239
240 const base::Value& report = value->GetList()[0];
241 ASSERT_TRUE(report.is_dict());
242 const base::Value::Dict& report_dict = report.GetDict();
243
244 ExpectDictIntegerValue(0, report_dict, "age");
245 ExpectDictStringValue(kType_, report_dict, "type");
246 ExpectDictStringValue(kUrl_.spec(), report_dict, "url");
247 ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
248 const base::Value::Dict* body = report_dict.FindDict("body");
249 EXPECT_EQ("value", *body->FindString("key"));
250 }
251 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
252
253 // Successful upload should remove delivered reports.
254 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
255 cache()->GetReports(&reports);
256 EXPECT_TRUE(reports.empty());
257 histograms.ExpectBucketCount(
258 kReportingUploadHeaderTypeHistogram,
259 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportingEndpoints,
260 1);
261 histograms.ExpectBucketCount(
262 kReportingUploadHeaderTypeHistogram,
263 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportTo, 0);
264
265 {
266 ReportingEndpoint::Statistics stats =
267 GetEndpointStatistics(kDocumentGroupKey_, kEndpoint_);
268 EXPECT_EQ(1, stats.attempted_uploads);
269 EXPECT_EQ(1, stats.successful_uploads);
270 EXPECT_EQ(1, stats.attempted_reports);
271 EXPECT_EQ(1, stats.successful_reports);
272 }
273 }
274
TEST_F(ReportingDeliveryAgentTest,UploadHeaderTypeEnumCountPerReport)275 TEST_F(ReportingDeliveryAgentTest, UploadHeaderTypeEnumCountPerReport) {
276 UploadFirstDocumentReportAndStartTimer();
277 base::HistogramTester histograms;
278
279 SetV1EndpointInCache(kDocumentGroupKey_, kDocumentReportingSource_,
280 kIsolationInfo_, kEndpoint_);
281 AddReport(kDocumentReportingSource_, kNak_, kUrl_, kGroup_);
282 AddReport(kDocumentReportingSource_, kNak_, kUrl_, kGroup_);
283
284 // There should be one upload per (NAK, origin, reporting source).
285 EXPECT_TRUE(delivery_timer()->IsRunning());
286 delivery_timer()->Fire();
287
288 ASSERT_EQ(1u, pending_uploads().size());
289 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
290
291 // Successful upload should remove delivered reports.
292 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
293 cache()->GetReports(&reports);
294 EXPECT_TRUE(reports.empty());
295 histograms.ExpectBucketCount(
296 kReportingUploadHeaderTypeHistogram,
297 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportingEndpoints,
298 2);
299 histograms.ExpectBucketCount(
300 kReportingUploadHeaderTypeHistogram,
301 ReportingDeliveryAgent::ReportingUploadHeaderType::kReportTo, 0);
302 }
303
TEST_F(ReportingDeliveryAgentTest,SuccessfulImmediateSubdomainUpload)304 TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateSubdomainUpload) {
305 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_,
306 OriginSubdomains::INCLUDE));
307 AddReport(kEmptyReportingSource_, kNak_, kSubdomainUrl_, kGroup_);
308
309 // Upload is automatically started when cache is modified.
310
311 ASSERT_EQ(1u, pending_uploads().size());
312 EXPECT_EQ(kEndpoint_, pending_uploads()[0]->url());
313 {
314 auto value = pending_uploads()[0]->GetValue();
315
316 ASSERT_TRUE(value->is_list());
317 ASSERT_EQ(1u, value->GetList().size());
318
319 const base::Value& report = value->GetList()[0];
320 ASSERT_TRUE(report.is_dict());
321 const base::Value::Dict& report_dict = report.GetDict();
322 EXPECT_EQ(5u, report_dict.size());
323
324 ExpectDictIntegerValue(0, report_dict, "age");
325 ExpectDictStringValue(kType_, report_dict, "type");
326 ExpectDictStringValue(kSubdomainUrl_.spec(), report_dict, "url");
327 ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
328 const base::Value::Dict* body = report_dict.FindDict("body");
329 EXPECT_EQ("value", *body->FindString("key"));
330 }
331 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
332
333 // Successful upload should remove delivered reports.
334 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
335 cache()->GetReports(&reports);
336 EXPECT_TRUE(reports.empty());
337
338 {
339 ReportingEndpoint::Statistics stats =
340 GetEndpointStatistics(kGroupKey_, kEndpoint_);
341 EXPECT_EQ(1, stats.attempted_uploads);
342 EXPECT_EQ(1, stats.successful_uploads);
343 EXPECT_EQ(1, stats.attempted_reports);
344 EXPECT_EQ(1, stats.successful_reports);
345 }
346
347 // TODO(dcreager): Check that BackoffEntry was informed of success.
348 }
349
TEST_F(ReportingDeliveryAgentTest,SuccessfulImmediateSubdomainUploadWithOverwrittenEndpoint)350 TEST_F(ReportingDeliveryAgentTest,
351 SuccessfulImmediateSubdomainUploadWithOverwrittenEndpoint) {
352 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_,
353 OriginSubdomains::INCLUDE));
354 AddReport(kEmptyReportingSource_, kNak_, kSubdomainUrl_, kGroup_);
355
356 // Upload is automatically started when cache is modified.
357
358 ASSERT_EQ(1u, pending_uploads().size());
359 // Change the endpoint group to exclude subdomains.
360 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_,
361 OriginSubdomains::EXCLUDE));
362 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
363
364 {
365 ReportingEndpoint::Statistics stats =
366 GetEndpointStatistics(kGroupKey_, kEndpoint_);
367 EXPECT_EQ(1, stats.attempted_uploads);
368 EXPECT_EQ(1, stats.successful_uploads);
369 EXPECT_EQ(1, stats.attempted_reports);
370 EXPECT_EQ(1, stats.successful_reports);
371 }
372
373 // Successful upload should remove delivered reports.
374 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
375 cache()->GetReports(&reports);
376 EXPECT_TRUE(reports.empty());
377 }
378
TEST_F(ReportingDeliveryAgentTest,SuccessfulDelayedUpload)379 TEST_F(ReportingDeliveryAgentTest, SuccessfulDelayedUpload) {
380 // Trigger and complete an upload to start the delivery timer.
381 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
382 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
383 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
384
385 // Add another report to upload after a delay.
386 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
387
388 EXPECT_TRUE(delivery_timer()->IsRunning());
389 delivery_timer()->Fire();
390
391 ASSERT_EQ(1u, pending_uploads().size());
392 EXPECT_EQ(kEndpoint_, pending_uploads()[0]->url());
393 {
394 auto value = pending_uploads()[0]->GetValue();
395
396 ASSERT_TRUE(value->is_list());
397 ASSERT_EQ(1u, value->GetList().size());
398
399 const base::Value& report = value->GetList()[0];
400 ASSERT_TRUE(report.is_dict());
401 const base::Value::Dict& report_dict = report.GetDict();
402 EXPECT_EQ(5u, report_dict.size());
403
404 ExpectDictIntegerValue(0, report_dict, "age");
405 ExpectDictStringValue(kType_, report_dict, "type");
406 ExpectDictStringValue(kUrl_.spec(), report_dict, "url");
407 ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
408 const base::Value::Dict* body = report_dict.FindDict("body");
409 EXPECT_EQ("value", *body->FindString("key"));
410 }
411 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
412
413 {
414 ReportingEndpoint::Statistics stats =
415 GetEndpointStatistics(kGroupKey_, kEndpoint_);
416 EXPECT_EQ(2, stats.attempted_uploads);
417 EXPECT_EQ(2, stats.successful_uploads);
418 EXPECT_EQ(2, stats.attempted_reports);
419 EXPECT_EQ(2, stats.successful_reports);
420 }
421
422 // Successful upload should remove delivered reports.
423 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
424 cache()->GetReports(&reports);
425 EXPECT_TRUE(reports.empty());
426
427 // TODO(juliatuttle): Check that BackoffEntry was informed of success.
428 }
429
TEST_F(ReportingDeliveryAgentTest,FailedUpload)430 TEST_F(ReportingDeliveryAgentTest, FailedUpload) {
431 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
432 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
433
434 EXPECT_TRUE(delivery_timer()->IsRunning());
435 delivery_timer()->Fire();
436
437 ASSERT_EQ(1u, pending_uploads().size());
438 pending_uploads()[0]->Complete(ReportingUploader::Outcome::FAILURE);
439
440 {
441 ReportingEndpoint::Statistics stats =
442 GetEndpointStatistics(kGroupKey_, kEndpoint_);
443 EXPECT_EQ(1, stats.attempted_uploads);
444 EXPECT_EQ(0, stats.successful_uploads);
445 EXPECT_EQ(1, stats.attempted_reports);
446 EXPECT_EQ(0, stats.successful_reports);
447 }
448
449 // Failed upload should increment reports' attempts.
450 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
451 cache()->GetReports(&reports);
452 ASSERT_EQ(1u, reports.size());
453 EXPECT_EQ(1, reports[0]->attempts);
454
455 // Since endpoint is now failing, an upload won't be started despite a pending
456 // report.
457 ASSERT_TRUE(pending_uploads().empty());
458 EXPECT_TRUE(delivery_timer()->IsRunning());
459 delivery_timer()->Fire();
460 EXPECT_TRUE(pending_uploads().empty());
461
462 {
463 ReportingEndpoint::Statistics stats =
464 GetEndpointStatistics(kGroupKey_, kEndpoint_);
465 EXPECT_EQ(1, stats.attempted_uploads);
466 EXPECT_EQ(0, stats.successful_uploads);
467 EXPECT_EQ(1, stats.attempted_reports);
468 EXPECT_EQ(0, stats.successful_reports);
469 }
470 }
471
TEST_F(ReportingDeliveryAgentTest,DisallowedUpload)472 TEST_F(ReportingDeliveryAgentTest, DisallowedUpload) {
473 // This mimics the check that is controlled by the BACKGROUND_SYNC permission
474 // in a real browser profile.
475 context()->test_delegate()->set_disallow_report_uploads(true);
476
477 static const int kAgeMillis = 12345;
478
479 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
480 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
481
482 tick_clock()->Advance(base::Milliseconds(kAgeMillis));
483
484 EXPECT_TRUE(delivery_timer()->IsRunning());
485 delivery_timer()->Fire();
486
487 // We should not try to upload the report, since we weren't given permission
488 // for this origin.
489 EXPECT_TRUE(pending_uploads().empty());
490
491 {
492 ReportingEndpoint::Statistics stats =
493 GetEndpointStatistics(kGroupKey_, kEndpoint_);
494 EXPECT_EQ(0, stats.attempted_uploads);
495 EXPECT_EQ(0, stats.successful_uploads);
496 EXPECT_EQ(0, stats.attempted_reports);
497 EXPECT_EQ(0, stats.successful_reports);
498 }
499
500 // Disallowed reports should NOT have been removed from the cache.
501 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
502 cache()->GetReports(&reports);
503 EXPECT_EQ(1u, reports.size());
504 }
505
TEST_F(ReportingDeliveryAgentTest,RemoveEndpointUpload)506 TEST_F(ReportingDeliveryAgentTest, RemoveEndpointUpload) {
507 static const ReportingEndpointGroupKey kOtherGroupKey(kNak_, kOtherOrigin_,
508 kGroup_);
509
510 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
511 ASSERT_TRUE(SetEndpointInCache(kOtherGroupKey, kEndpoint_, kExpires_));
512
513 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
514
515 EXPECT_TRUE(delivery_timer()->IsRunning());
516 delivery_timer()->Fire();
517
518 ASSERT_EQ(1u, pending_uploads().size());
519 pending_uploads()[0]->Complete(ReportingUploader::Outcome::REMOVE_ENDPOINT);
520
521 // "Remove endpoint" upload should remove endpoint from *all* origins and
522 // increment reports' attempts.
523 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
524 cache()->GetReports(&reports);
525 ASSERT_EQ(1u, reports.size());
526 EXPECT_EQ(1, reports[0]->attempts);
527
528 EXPECT_FALSE(FindEndpointInCache(kGroupKey_, kEndpoint_));
529 EXPECT_FALSE(FindEndpointInCache(kOtherGroupKey, kEndpoint_));
530
531 // Since endpoint is now failing, an upload won't be started despite a pending
532 // report.
533 EXPECT_TRUE(delivery_timer()->IsRunning());
534 delivery_timer()->Fire();
535 EXPECT_TRUE(pending_uploads().empty());
536 }
537
TEST_F(ReportingDeliveryAgentTest,ConcurrentRemove)538 TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) {
539 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
540 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
541
542 EXPECT_TRUE(delivery_timer()->IsRunning());
543 delivery_timer()->Fire();
544 ASSERT_EQ(1u, pending_uploads().size());
545
546 // Remove the report while the upload is running.
547 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
548 cache()->GetReports(&reports);
549 EXPECT_EQ(1u, reports.size());
550
551 const ReportingReport* report = reports[0];
552 EXPECT_FALSE(cache()->IsReportDoomedForTesting(report));
553
554 // Report should appear removed, even though the cache has doomed it.
555 cache()->RemoveReports(reports);
556 cache()->GetReports(&reports);
557 EXPECT_TRUE(reports.empty());
558 EXPECT_TRUE(cache()->IsReportDoomedForTesting(report));
559
560 // Completing upload shouldn't crash, and report should still be gone.
561 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
562 cache()->GetReports(&reports);
563 EXPECT_TRUE(reports.empty());
564 }
565
TEST_F(ReportingDeliveryAgentTest,ConcurrentRemoveDuringPermissionsCheck)566 TEST_F(ReportingDeliveryAgentTest, ConcurrentRemoveDuringPermissionsCheck) {
567 // Pause the permissions check, so that we can try to remove some reports
568 // while we're in the middle of verifying that we can upload them. (This is
569 // similar to the previous test, but removes the reports during a different
570 // part of the upload process.)
571 context()->test_delegate()->set_pause_permissions_check(true);
572
573 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
574 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
575
576 ASSERT_TRUE(context()->test_delegate()->PermissionsCheckPaused());
577
578 // Remove the report while the upload is running.
579 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> reports;
580 cache()->GetReports(&reports);
581 EXPECT_EQ(1u, reports.size());
582
583 const ReportingReport* report = reports[0];
584 EXPECT_FALSE(cache()->IsReportDoomedForTesting(report));
585
586 // Report should appear removed, even though the cache has doomed it.
587 cache()->RemoveReports(reports);
588 cache()->GetReports(&reports);
589 EXPECT_TRUE(reports.empty());
590 EXPECT_TRUE(cache()->IsReportDoomedForTesting(report));
591
592 // Completing upload shouldn't crash, and report should still be gone.
593 context()->test_delegate()->ResumePermissionsCheck();
594 ASSERT_EQ(1u, pending_uploads().size());
595 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
596 cache()->GetReports(&reports);
597 EXPECT_TRUE(reports.empty());
598 }
599
600 // Reports uploaded together must share a NAK and origin.
601 // Test that the agent will not combine reports destined for the same endpoint
602 // if the reports are from different origins or NAKs, but does combine all
603 // reports for the same (NAK, origin).
TEST_F(ReportingDeliveryAgentTest,OnlyBatchSameNakAndOrigin)604 TEST_F(ReportingDeliveryAgentTest, OnlyBatchSameNakAndOrigin) {
605 const ReportingEndpointGroupKey kGroupKeys[] = {
606 ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_),
607 ReportingEndpointGroupKey(kNak_, kOtherOrigin_, kGroup_),
608 ReportingEndpointGroupKey(kOtherNak_, kOrigin_, kGroup_),
609 ReportingEndpointGroupKey(kOtherNak_, kOtherOrigin_, kGroup_),
610 };
611 for (const ReportingEndpointGroupKey& group_key : kGroupKeys) {
612 ASSERT_TRUE(SetEndpointInCache(group_key, kEndpoint_, kExpires_));
613 }
614
615 // Trigger and complete an upload to start the delivery timer.
616 UploadFirstReportAndStartTimer();
617
618 // Now that the delivery timer is running, these reports won't be immediately
619 // uploaded.
620 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
621 AddReport(kEmptyReportingSource_, kNak_, kOtherUrl_, kGroup_);
622 AddReport(kEmptyReportingSource_, kNak_, kOtherUrl_, kGroup_);
623 AddReport(kEmptyReportingSource_, kOtherNak_, kUrl_, kGroup_);
624 AddReport(kEmptyReportingSource_, kOtherNak_, kUrl_, kGroup_);
625 AddReport(kEmptyReportingSource_, kOtherNak_, kUrl_, kGroup_);
626 AddReport(kEmptyReportingSource_, kOtherNak_, kOtherUrl_, kGroup_);
627 AddReport(kEmptyReportingSource_, kOtherNak_, kOtherUrl_, kGroup_);
628 AddReport(kEmptyReportingSource_, kOtherNak_, kOtherUrl_, kGroup_);
629 AddReport(kEmptyReportingSource_, kOtherNak_, kOtherUrl_, kGroup_);
630 EXPECT_EQ(0u, pending_uploads().size());
631
632 // There should be one upload per (NAK, origin).
633 EXPECT_TRUE(delivery_timer()->IsRunning());
634 delivery_timer()->Fire();
635 ASSERT_EQ(4u, pending_uploads().size());
636
637 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
638 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
639 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
640 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
641 EXPECT_EQ(0u, pending_uploads().size());
642
643 for (int i = 0; i < 4; ++i) {
644 ReportingEndpoint::Statistics stats =
645 GetEndpointStatistics(kGroupKeys[i], kEndpoint_);
646 EXPECT_EQ(1, stats.attempted_uploads);
647 EXPECT_EQ(1, stats.successful_uploads);
648 EXPECT_EQ(i + 1, stats.attempted_reports);
649 EXPECT_EQ(i + 1, stats.successful_reports);
650 }
651 }
652
653 // Test that the agent won't start a second upload for a (NAK, origin, group)
654 // while one is pending, even if a different endpoint is available, but will
655 // once the original delivery is complete and the (NAK, origin, group) is no
656 // longer pending.
TEST_F(ReportingDeliveryAgentTest,SerializeUploadsToGroup)657 TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToGroup) {
658 static const GURL kDifferentEndpoint("https://endpoint2/");
659
660 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
661 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kDifferentEndpoint, kExpires_));
662
663 // Trigger and complete an upload to start the delivery timer.
664 UploadFirstReportAndStartTimer();
665
666 // First upload causes this group key to become pending.
667 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
668 EXPECT_EQ(0u, pending_uploads().size());
669 EXPECT_TRUE(delivery_timer()->IsRunning());
670 delivery_timer()->Fire();
671 EXPECT_EQ(1u, pending_uploads().size());
672
673 // Second upload isn't started because the group is pending.
674 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
675 EXPECT_TRUE(delivery_timer()->IsRunning());
676 delivery_timer()->Fire();
677 ASSERT_EQ(1u, pending_uploads().size());
678
679 // Resolve the first upload.
680 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
681 EXPECT_EQ(0u, pending_uploads().size());
682
683 // Now the other upload can happen.
684 EXPECT_TRUE(delivery_timer()->IsRunning());
685 delivery_timer()->Fire();
686 ASSERT_EQ(1u, pending_uploads().size());
687 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
688 EXPECT_EQ(0u, pending_uploads().size());
689
690 // A total of 2 reports were uploaded.
691 {
692 ReportingEndpoint::Statistics stats =
693 GetEndpointStatistics(kGroupKey_, kEndpoint_);
694 ReportingEndpoint::Statistics different_stats =
695 GetEndpointStatistics(kGroupKey_, kDifferentEndpoint);
696 EXPECT_EQ(2, stats.attempted_uploads + different_stats.attempted_uploads);
697 EXPECT_EQ(2, stats.successful_uploads + different_stats.successful_uploads);
698 EXPECT_EQ(2, stats.attempted_reports + different_stats.attempted_reports);
699 EXPECT_EQ(2, stats.successful_reports + different_stats.successful_reports);
700 }
701 }
702
703 // Tests that the agent will start parallel uploads to different groups within
704 // the same (NAK, origin) to endpoints with different URLs.
TEST_F(ReportingDeliveryAgentTest,ParallelizeUploadsAcrossGroups)705 TEST_F(ReportingDeliveryAgentTest, ParallelizeUploadsAcrossGroups) {
706 static const GURL kDifferentEndpoint("https://endpoint2/");
707 static const std::string kDifferentGroup("group2");
708 const ReportingEndpointGroupKey kDifferentGroupKey(kNak_, kOrigin_,
709 kDifferentGroup);
710
711 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
712 ASSERT_TRUE(
713 SetEndpointInCache(kDifferentGroupKey, kDifferentEndpoint, kExpires_));
714
715 // Trigger and complete an upload to start the delivery timer.
716 UploadFirstReportAndStartTimer();
717
718 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
719 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kDifferentGroup);
720
721 EXPECT_TRUE(delivery_timer()->IsRunning());
722 delivery_timer()->Fire();
723 ASSERT_EQ(2u, pending_uploads().size());
724
725 pending_uploads()[1]->Complete(ReportingUploader::Outcome::SUCCESS);
726 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
727 EXPECT_EQ(0u, pending_uploads().size());
728
729 {
730 ReportingEndpoint::Statistics stats =
731 GetEndpointStatistics(kGroupKey_, kEndpoint_);
732 EXPECT_EQ(1, stats.attempted_uploads);
733 EXPECT_EQ(1, stats.successful_uploads);
734 EXPECT_EQ(1, stats.attempted_reports);
735 EXPECT_EQ(1, stats.successful_reports);
736 }
737 {
738 ReportingEndpoint::Statistics stats =
739 GetEndpointStatistics(kDifferentGroupKey, kDifferentEndpoint);
740 EXPECT_EQ(1, stats.attempted_uploads);
741 EXPECT_EQ(1, stats.successful_uploads);
742 EXPECT_EQ(1, stats.attempted_reports);
743 EXPECT_EQ(1, stats.successful_reports);
744 }
745 }
746
747 // Tests that the agent will include reports for different groups for the same
748 // (NAK, origin) in the same upload if they are destined for the same endpoint
749 // URL.
TEST_F(ReportingDeliveryAgentTest,BatchReportsAcrossGroups)750 TEST_F(ReportingDeliveryAgentTest, BatchReportsAcrossGroups) {
751 static const std::string kDifferentGroup("group2");
752 const ReportingEndpointGroupKey kDifferentGroupKey(kNak_, kOrigin_,
753 kDifferentGroup);
754
755 ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_));
756 ASSERT_TRUE(SetEndpointInCache(kDifferentGroupKey, kEndpoint_, kExpires_));
757
758 UploadFirstReportAndStartTimer();
759
760 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kGroup_);
761 AddReport(kEmptyReportingSource_, kNak_, kUrl_, kDifferentGroup);
762
763 EXPECT_TRUE(delivery_timer()->IsRunning());
764 delivery_timer()->Fire();
765 ASSERT_EQ(1u, pending_uploads().size());
766 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
767 EXPECT_EQ(0u, pending_uploads().size());
768
769 {
770 ReportingEndpoint::Statistics stats =
771 GetEndpointStatistics(kGroupKey_, kEndpoint_);
772 EXPECT_EQ(1, stats.attempted_uploads);
773 EXPECT_EQ(1, stats.successful_uploads);
774 EXPECT_EQ(1, stats.attempted_reports);
775 EXPECT_EQ(1, stats.successful_reports);
776 }
777 {
778 ReportingEndpoint::Statistics stats =
779 GetEndpointStatistics(kDifferentGroupKey, kEndpoint_);
780 EXPECT_EQ(1, stats.attempted_uploads);
781 EXPECT_EQ(1, stats.successful_uploads);
782 EXPECT_EQ(1, stats.attempted_reports);
783 EXPECT_EQ(1, stats.successful_reports);
784 }
785 }
786
787 // Tests that the agent can send all outstanding reports for a single source
788 // when necessary. This test queues two reports for the same reporting source,
789 // for different endpoints, another for a different source at the same URL, and
790 // another for a different source on a different origin.
TEST_F(ReportingDeliveryAgentTest,SendReportsForSource)791 TEST_F(ReportingDeliveryAgentTest, SendReportsForSource) {
792 static const std::string kGroup2("group2");
793
794 // Two other reporting sources; kReportingSource2 will enqueue reports for the
795 // same URL as kReportingSource_, while kReportingSource3 will be a separate
796 // origin.
797 const base::UnguessableToken kReportingSource1 =
798 base::UnguessableToken::Create();
799 const base::UnguessableToken kReportingSource2 =
800 base::UnguessableToken::Create();
801 const base::UnguessableToken kReportingSource3 =
802 base::UnguessableToken::Create();
803
804 const IsolationInfo kIsolationInfo1 =
805 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin_,
806 kOrigin_, SiteForCookies::FromOrigin(kOrigin_));
807 const IsolationInfo kIsolationInfo2 =
808 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin_,
809 kOrigin_, SiteForCookies::FromOrigin(kOrigin_));
810 const IsolationInfo kIsolationInfo3 = IsolationInfo::Create(
811 IsolationInfo::RequestType::kOther, kOtherOrigin_, kOtherOrigin_,
812 SiteForCookies::FromOrigin(kOtherOrigin_));
813
814 // Set up identical endpoint configuration for kReportingSource1 and
815 // kReportingSource2. kReportingSource3 is independent.
816 const ReportingEndpointGroupKey kGroup1Key1(kNak_, kReportingSource1,
817 kOrigin_, kGroup_);
818 const ReportingEndpointGroupKey kGroup2Key1(kNak_, kReportingSource1,
819 kOrigin_, kGroup2);
820 const ReportingEndpointGroupKey kGroup1Key2(kNak_, kReportingSource2,
821 kOrigin_, kGroup_);
822 const ReportingEndpointGroupKey kGroup2Key2(kNak_, kReportingSource2,
823 kOrigin_, kGroup2);
824 const ReportingEndpointGroupKey kOtherGroupKey(kOtherNak_, kReportingSource3,
825 kOtherOrigin_, kGroup_);
826
827 SetV1EndpointInCache(kGroup1Key1, kReportingSource1, kIsolationInfo1, kUrl_);
828 SetV1EndpointInCache(kGroup2Key1, kReportingSource1, kIsolationInfo1, kUrl_);
829 SetV1EndpointInCache(kGroup1Key2, kReportingSource2, kIsolationInfo2, kUrl_);
830 SetV1EndpointInCache(kGroup2Key2, kReportingSource2, kIsolationInfo2, kUrl_);
831 SetV1EndpointInCache(kOtherGroupKey, kReportingSource3, kIsolationInfo3,
832 kOtherUrl_);
833
834 UploadFirstReportAndStartTimer();
835
836 AddReport(kReportingSource1, kNak_, kUrl_, kGroup_);
837 AddReport(kReportingSource1, kNak_, kUrl_, kGroup2);
838 AddReport(kReportingSource2, kNak_, kUrl_, kGroup_);
839 AddReport(kReportingSource3, kOtherNak_, kUrl_, kGroup_);
840
841 // There should be four queued reports at this point.
842 EXPECT_EQ(4u, cache()->GetReportCountWithStatusForTesting(
843 ReportingReport::Status::QUEUED));
844 EXPECT_EQ(0u, pending_uploads().size());
845 SendReportsForSource(kReportingSource1);
846 // Sending all reports for the source should only queue two, despite the fact
847 // that there are other reports queued for the same origin and endpoint.
848 EXPECT_EQ(2u, cache()->GetReportCountWithStatusForTesting(
849 ReportingReport::Status::QUEUED));
850 EXPECT_EQ(2u, cache()->GetReportCountWithStatusForTesting(
851 ReportingReport::Status::PENDING));
852 // All pending reports for the same source should be batched into a single
853 // upload.
854 ASSERT_EQ(1u, pending_uploads().size());
855 pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
856 EXPECT_EQ(0u, pending_uploads().size());
857 }
858
859 // Tests that the agent can send all outstanding V1 reports for multiple sources
860 // and that these are not batched together.
TEST_F(ReportingDeliveryAgentTest,SendReportsForMultipleSources)861 TEST_F(ReportingDeliveryAgentTest, SendReportsForMultipleSources) {
862 static const std::string kGroup2("group2");
863
864 // Two other reporting sources; kReportingSource2 will enqueue reports for the
865 // same URL as kReportingSource_, while kReportingSource3 will be a separate
866 // origin.
867 const base::UnguessableToken kReportingSource1 =
868 base::UnguessableToken::Create();
869 const base::UnguessableToken kReportingSource2 =
870 base::UnguessableToken::Create();
871 const base::UnguessableToken kReportingSource3 =
872 base::UnguessableToken::Create();
873
874 const IsolationInfo kIsolationInfo1 =
875 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin_,
876 kOrigin_, SiteForCookies::FromOrigin(kOrigin_));
877 const IsolationInfo kIsolationInfo2 =
878 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin_,
879 kOrigin_, SiteForCookies::FromOrigin(kOrigin_));
880 const IsolationInfo kIsolationInfo3 = IsolationInfo::Create(
881 IsolationInfo::RequestType::kOther, kOtherOrigin_, kOtherOrigin_,
882 SiteForCookies::FromOrigin(kOtherOrigin_));
883
884 // Set up identical endpoint configuration for kReportingSource1 and
885 // kReportingSource2. kReportingSource3 is independent.
886 const ReportingEndpointGroupKey kGroup1Key1(kNak_, kReportingSource1,
887 kOrigin_, kGroup_);
888 const ReportingEndpointGroupKey kGroup2Key1(kNak_, kReportingSource1,
889 kOrigin_, kGroup2);
890 const ReportingEndpointGroupKey kGroup1Key2(kNak_, kReportingSource2,
891 kOrigin_, kGroup_);
892 const ReportingEndpointGroupKey kGroup2Key2(kNak_, kReportingSource2,
893 kOrigin_, kGroup2);
894 const ReportingEndpointGroupKey kOtherGroupKey(kOtherNak_, kReportingSource3,
895 kOtherOrigin_, kGroup_);
896
897 SetV1EndpointInCache(kGroup1Key1, kReportingSource1, kIsolationInfo1, kUrl_);
898 SetV1EndpointInCache(kGroup2Key1, kReportingSource1, kIsolationInfo1, kUrl_);
899 SetV1EndpointInCache(kGroup1Key2, kReportingSource2, kIsolationInfo2, kUrl_);
900 SetV1EndpointInCache(kGroup2Key2, kReportingSource2, kIsolationInfo2, kUrl_);
901 SetV1EndpointInCache(kOtherGroupKey, kReportingSource3, kIsolationInfo3,
902 kOtherUrl_);
903
904 UploadFirstReportAndStartTimer();
905
906 AddReport(kReportingSource1, kNak_, kUrl_, kGroup_);
907 AddReport(kReportingSource1, kNak_, kUrl_, kGroup2);
908 AddReport(kReportingSource2, kNak_, kUrl_, kGroup_);
909 AddReport(kReportingSource3, kOtherNak_, kUrl_, kGroup_);
910
911 // There should be four queued reports at this point.
912 EXPECT_EQ(4u, cache()->GetReportCountWithStatusForTesting(
913 ReportingReport::Status::QUEUED));
914 EXPECT_EQ(0u, pending_uploads().size());
915
916 // Send reports for both ReportingSource 1 and 2 at the same time. These
917 // should be sent to the same endpoint, but should still not be batched
918 // together.
919 SendReportsForSource(kReportingSource1);
920 SendReportsForSource(kReportingSource2);
921
922 // We expect to see three pending reports, and one still queued. The pending
923 // reports should be divided into two uploads.
924 EXPECT_EQ(1u, cache()->GetReportCountWithStatusForTesting(
925 ReportingReport::Status::QUEUED));
926 EXPECT_EQ(3u, cache()->GetReportCountWithStatusForTesting(
927 ReportingReport::Status::PENDING));
928 ASSERT_EQ(2u, pending_uploads().size());
929 }
930
931 } // namespace
932 } // namespace net
933