summaryrefslogtreecommitdiff
path: root/chromium/components/domain_reliability
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/components/domain_reliability
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
downloadqtwebengine-chromium-189d4fd8fad9e3c776873be51938cd31a42b6177.tar.gz
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/domain_reliability')
-rw-r--r--chromium/components/domain_reliability/BUILD.gn2
-rw-r--r--chromium/components/domain_reliability/DIR_METADATA5
-rw-r--r--chromium/components/domain_reliability/OWNERS3
-rw-r--r--chromium/components/domain_reliability/beacon.cc12
-rw-r--r--chromium/components/domain_reliability/beacon.h30
-rw-r--r--chromium/components/domain_reliability/context.cc98
-rw-r--r--chromium/components/domain_reliability/context.h35
-rw-r--r--chromium/components/domain_reliability/context_unittest.cc779
-rw-r--r--chromium/components/domain_reliability/features.cc16
-rw-r--r--chromium/components/domain_reliability/features.h21
-rw-r--r--chromium/components/domain_reliability/monitor.cc9
-rw-r--r--chromium/components/domain_reliability/monitor.h2
-rw-r--r--chromium/components/domain_reliability/monitor_unittest.cc149
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.cc21
-rw-r--r--chromium/components/domain_reliability/test_util.cc16
-rw-r--r--chromium/components/domain_reliability/test_util.h15
-rw-r--r--chromium/components/domain_reliability/uploader.cc4
-rw-r--r--chromium/components/domain_reliability/uploader.h11
-rw-r--r--chromium/components/domain_reliability/uploader_unittest.cc48
19 files changed, 1204 insertions, 72 deletions
diff --git a/chromium/components/domain_reliability/BUILD.gn b/chromium/components/domain_reliability/BUILD.gn
index 14ac5738ca9..175e908c274 100644
--- a/chromium/components/domain_reliability/BUILD.gn
+++ b/chromium/components/domain_reliability/BUILD.gn
@@ -58,6 +58,8 @@ component("domain_reliability") {
"dispatcher.cc",
"dispatcher.h",
"domain_reliability_export.h",
+ "features.cc",
+ "features.h",
"google_configs.cc",
"google_configs.h",
"monitor.cc",
diff --git a/chromium/components/domain_reliability/DIR_METADATA b/chromium/components/domain_reliability/DIR_METADATA
new file mode 100644
index 00000000000..cb1a69b404a
--- /dev/null
+++ b/chromium/components/domain_reliability/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Internals>Network>ReportingAndNEL"
+}
+
+team_email: "net-dev@chromium.org"
diff --git a/chromium/components/domain_reliability/OWNERS b/chromium/components/domain_reliability/OWNERS
index 6016d30496f..22067875472 100644
--- a/chromium/components/domain_reliability/OWNERS
+++ b/chromium/components/domain_reliability/OWNERS
@@ -1,5 +1,2 @@
file://net/OWNERS
file://net/network_error_logging/OWNERS
-
-# COMPONENT: Internals>Network>ReportingAndNEL
-# TEAM: net-dev@chromium.org
diff --git a/chromium/components/domain_reliability/beacon.cc b/chromium/components/domain_reliability/beacon.cc
index bcee54997fb..5c7db8a7408 100644
--- a/chromium/components/domain_reliability/beacon.cc
+++ b/chromium/components/domain_reliability/beacon.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/metrics/histogram_functions.h"
#include "base/values.h"
#include "components/domain_reliability/util.h"
#include "net/base/net_errors.h"
@@ -16,10 +17,17 @@ namespace domain_reliability {
using base::Value;
using base::DictionaryValue;
-DomainReliabilityBeacon::DomainReliabilityBeacon() {}
+DomainReliabilityBeacon::DomainReliabilityBeacon() = default;
+
DomainReliabilityBeacon::DomainReliabilityBeacon(
const DomainReliabilityBeacon& other) = default;
-DomainReliabilityBeacon::~DomainReliabilityBeacon() {}
+
+DomainReliabilityBeacon::~DomainReliabilityBeacon() {
+ if (outcome != Outcome::kUnknown) {
+ base::UmaHistogramEnumeration("Net.DomainReliability.BeaconOutcome",
+ outcome);
+ }
+}
std::unique_ptr<Value> DomainReliabilityBeacon::ToValue(
base::TimeTicks upload_time,
diff --git a/chromium/components/domain_reliability/beacon.h b/chromium/components/domain_reliability/beacon.h
index c27d2a1cb59..38701256c01 100644
--- a/chromium/components/domain_reliability/beacon.h
+++ b/chromium/components/domain_reliability/beacon.h
@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "components/domain_reliability/domain_reliability_export.h"
#include "net/base/net_error_details.h"
+#include "net/base/network_isolation_key.h"
#include "url/gurl.h"
namespace base {
@@ -26,6 +27,26 @@ struct DOMAIN_RELIABILITY_EXPORT DomainReliabilityBeacon {
DomainReliabilityBeacon(const DomainReliabilityBeacon& other);
~DomainReliabilityBeacon();
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class Outcome {
+ // Default value. This should not be recorded to the histogram.
+ kUnknown = 0,
+ // Successfully uploaded.
+ kUploaded = 1,
+ // Removed for being expired.
+ kExpired = 2,
+ // Evicted to make room for newer beacons.
+ kEvicted = 3,
+ // Deleted for user clearing browsing data.
+ kCleared = 5,
+ // Beacon was deleted upon context shutdown.
+ kContextShutDown = 5,
+
+ // Keep last.
+ kMaxValue = kContextShutDown,
+ };
+
// Converts the Beacon to JSON format for uploading. Calculates the age
// relative to an upload time of |upload_time|.
//
@@ -44,8 +65,10 @@ struct DOMAIN_RELIABILITY_EXPORT DomainReliabilityBeacon {
// The URL that the beacon is reporting on, if included.
// The scheme can be non-secure.
GURL url;
- // The resource name that the beacon is reporting on, if included.
- std::string resource;
+ // The NetworkIsolationKey associated with the request being reported on. Must
+ // also be used to upload any report. This field does not appear in the
+ // uploaded report.
+ net::NetworkIsolationKey network_isolation_key;
// Status string (e.g. "ok", "dns.nxdomain", "http.403").
std::string status;
// Granular QUIC error string (e.g. "quic.peer_going_away").
@@ -75,6 +98,9 @@ struct DOMAIN_RELIABILITY_EXPORT DomainReliabilityBeacon {
// The probability that this request had of being reported ("sample rate").
double sample_rate;
+ // Records the ultimate outcome of this beacon, for metrics.
+ Outcome outcome = Outcome::kUnknown;
+
// Okay to copy and assign.
};
diff --git a/chromium/components/domain_reliability/context.cc b/chromium/components/domain_reliability/context.cc
index d3084337475..0bd03c41038 100644
--- a/chromium/components/domain_reliability/context.cc
+++ b/chromium/components/domain_reliability/context.cc
@@ -5,6 +5,7 @@
#include "components/domain_reliability/context.h"
#include <algorithm>
+#include <limits>
#include <utility>
#include "base/bind.h"
@@ -54,7 +55,11 @@ DomainReliabilityContext::DomainReliabilityContext(
last_network_change_time_(last_network_change_time),
upload_allowed_callback_(upload_allowed_callback) {}
-DomainReliabilityContext::~DomainReliabilityContext() = default;
+DomainReliabilityContext::~DomainReliabilityContext() {
+ for (auto& beacon_ptr : beacons_) {
+ beacon_ptr->outcome = DomainReliabilityBeacon::Outcome::kContextShutDown;
+ }
+}
void DomainReliabilityContext::OnBeacon(
std::unique_ptr<DomainReliabilityBeacon> beacon) {
@@ -77,6 +82,9 @@ void DomainReliabilityContext::OnBeacon(
}
void DomainReliabilityContext::ClearBeacons() {
+ for (auto& beacon_ptr : beacons_) {
+ beacon_ptr->outcome = DomainReliabilityBeacon::Outcome::kCleared;
+ }
beacons_.clear();
uploading_beacons_size_ = 0;
}
@@ -131,7 +139,19 @@ void DomainReliabilityContext::StartUpload() {
if (beacons_.empty())
return;
- MarkUpload();
+ // Find the first beacon with an `upload_depth` of at most
+ // kMaxUploadDepthToSchedule, in preparation to create a report containing all
+ // beacons with matching NetworkIsolationKeys.
+ bool found_beacon_to_upload = false;
+ for (const auto& beacon : beacons_) {
+ if (beacon->upload_depth <= kMaxUploadDepthToSchedule) {
+ uploading_beacons_network_isolation_key_ = beacon->network_isolation_key;
+ found_beacon_to_upload = true;
+ break;
+ }
+ }
+ if (!found_beacon_to_upload)
+ return;
size_t collector_index = scheduler_.OnUploadStart();
const GURL& collector_url = *config().collectors[collector_index];
@@ -150,6 +170,7 @@ void DomainReliabilityContext::StartUpload() {
uploader_->UploadReport(
report_json, max_upload_depth, collector_url,
+ uploading_beacons_network_isolation_key_,
base::BindOnce(&DomainReliabilityContext::OnUploadComplete,
weak_factory_.GetWeakPtr()));
}
@@ -164,24 +185,42 @@ void DomainReliabilityContext::OnUploadComplete(
DCHECK(!upload_time_.is_null());
last_upload_time_ = upload_time_;
upload_time_ = base::TimeTicks();
+
+ // If there are pending beacons with a low enough depth, inform the scheduler
+ // - it's possible only some beacons were added because of NetworkIsolationKey
+ // mismatches, rather than due to new beacons being created.
+ if (GetMinBeaconUploadDepth() <= kMaxUploadDepthToSchedule)
+ scheduler_.OnBeaconAdded();
}
std::unique_ptr<const Value> DomainReliabilityContext::CreateReport(
base::TimeTicks upload_time,
const GURL& collector_url,
- int* max_upload_depth_out) const {
+ int* max_upload_depth_out) {
+ DCHECK_GT(beacons_.size(), 0u);
+ DCHECK_EQ(0u, uploading_beacons_size_);
+
int max_upload_depth = 0;
std::unique_ptr<ListValue> beacons_value(new ListValue());
for (const auto& beacon : beacons_) {
+ // Only include beacons with a matching NetworkIsolationKey in the report.
+ if (beacon->network_isolation_key !=
+ uploading_beacons_network_isolation_key_) {
+ continue;
+ }
+
beacons_value->Append(beacon->ToValue(upload_time,
*last_network_change_time_,
collector_url,
config().path_prefixes));
if (beacon->upload_depth > max_upload_depth)
max_upload_depth = beacon->upload_depth;
+ ++uploading_beacons_size_;
}
+ DCHECK_GT(uploading_beacons_size_, 0u);
+
std::unique_ptr<DictionaryValue> report_value(new DictionaryValue());
report_value->SetString("reporter", upload_reporter_string_);
report_value->Set("entries", std::move(beacons_value));
@@ -190,22 +229,23 @@ std::unique_ptr<const Value> DomainReliabilityContext::CreateReport(
return std::move(report_value);
}
-void DomainReliabilityContext::MarkUpload() {
- DCHECK_EQ(0u, uploading_beacons_size_);
- uploading_beacons_size_ = beacons_.size();
- DCHECK_NE(0u, uploading_beacons_size_);
-}
-
void DomainReliabilityContext::CommitUpload() {
- auto begin = beacons_.begin();
- auto end = begin + uploading_beacons_size_;
- beacons_.erase(begin, end);
- DCHECK_NE(0u, uploading_beacons_size_);
- uploading_beacons_size_ = 0;
+ auto current = beacons_.begin();
+ while (uploading_beacons_size_ > 0) {
+ DCHECK(current != beacons_.end());
+
+ auto last = current;
+ ++current;
+ if ((*last)->network_isolation_key ==
+ uploading_beacons_network_isolation_key_) {
+ (*last)->outcome = DomainReliabilityBeacon::Outcome::kUploaded;
+ beacons_.erase(last);
+ --uploading_beacons_size_;
+ }
+ }
}
void DomainReliabilityContext::RollbackUpload() {
- DCHECK_NE(0u, uploading_beacons_size_);
uploading_beacons_size_ = 0;
}
@@ -215,19 +255,35 @@ void DomainReliabilityContext::RemoveOldestBeacon() {
DVLOG(1) << "Beacon queue for " << config().origin << " full; "
<< "removing oldest beacon";
- beacons_.pop_front();
-
- // If that just removed a beacon counted in uploading_beacons_size_, decrement
- // that.
- if (uploading_beacons_size_ > 0)
+ // If the beacon being removed has a NetworkIsolationKey that matches that of
+ // the current upload, decrement |uploading_beacons_size_|.
+ if (uploading_beacons_size_ > 0 &&
+ beacons_.front()->network_isolation_key ==
+ uploading_beacons_network_isolation_key_) {
--uploading_beacons_size_;
+ }
+
+ beacons_.front()->outcome = DomainReliabilityBeacon::Outcome::kEvicted;
+ beacons_.pop_front();
}
void DomainReliabilityContext::RemoveExpiredBeacons() {
base::TimeTicks now = time_->NowTicks();
const base::TimeDelta kMaxAge = base::TimeDelta::FromHours(1);
- while (!beacons_.empty() && now - beacons_.front()->start_time >= kMaxAge)
+ while (!beacons_.empty() && now - beacons_.front()->start_time >= kMaxAge) {
+ beacons_.front()->outcome = DomainReliabilityBeacon::Outcome::kExpired;
beacons_.pop_front();
+ }
+}
+
+// Gets the minimum depth of all entries in |beacons_|.
+int DomainReliabilityContext::GetMinBeaconUploadDepth() const {
+ int min = std::numeric_limits<int>::max();
+ for (const auto& beacon : beacons_) {
+ if (beacon->upload_depth < min)
+ min = beacon->upload_depth;
+ }
+ return min;
}
} // namespace domain_reliability
diff --git a/chromium/components/domain_reliability/context.h b/chromium/components/domain_reliability/context.h
index 13da8e391a3..5f10fbf77d9 100644
--- a/chromium/components/domain_reliability/context.h
+++ b/chromium/components/domain_reliability/context.h
@@ -7,10 +7,10 @@
#include <stddef.h>
+#include <list>
#include <memory>
#include <vector>
-#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
@@ -19,6 +19,7 @@
#include "components/domain_reliability/domain_reliability_export.h"
#include "components/domain_reliability/scheduler.h"
#include "components/domain_reliability/uploader.h"
+#include "net/base/network_isolation_key.h"
class GURL;
@@ -68,7 +69,7 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
// debugging purposes.
std::unique_ptr<base::Value> GetWebUIData() const;
- // Gets the beacons queued for upload in this context. |*beacons_out| will be
+ // Gets the beacons queued for upload in this context. `*beacons_out` will be
// cleared and filled with pointers to the beacons; the pointers remain valid
// as long as no other requests are reported to the DomainReliabilityMonitor.
void GetQueuedBeaconsForTesting(
@@ -87,17 +88,14 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
void StartUpload();
void OnUploadComplete(const DomainReliabilityUploader::UploadResult& result);
- std::unique_ptr<const base::Value> CreateReport(
- base::TimeTicks upload_time,
- const GURL& collector_url,
- int* max_beacon_depth_out) const;
+ // Creates a report from all beacons associated with
+ // `uploading_beacons_network_isolation_key_`. Updates
+ // `uploading_beacons_size_`.
+ std::unique_ptr<const base::Value> CreateReport(base::TimeTicks upload_time,
+ const GURL& collector_url,
+ int* max_beacon_depth_out);
- // Remembers the current state of the context when an upload starts. Can be
- // called multiple times in a row (without |CommitUpload|) if uploads fail
- // and are retried.
- void MarkUpload();
-
- // Uses the state remembered by |MarkUpload| to remove successfully uploaded
+ // Uses the state remembered by `MarkUpload` to remove successfully uploaded
// data but keep beacons and request counts added after the upload started.
void CommitUpload();
@@ -109,6 +107,9 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
void RemoveExpiredBeacons();
+ // Gets the minimum upload depth of all entries in |beacons_|.
+ int GetMinBeaconUploadDepth() const;
+
std::unique_ptr<const DomainReliabilityConfig> config_;
const MockableTime* time_;
const std::string& upload_reporter_string_;
@@ -116,8 +117,16 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
DomainReliabilityDispatcher* dispatcher_;
DomainReliabilityUploader* uploader_;
- base::circular_deque<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
+ std::list<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
+
size_t uploading_beacons_size_;
+ // The NetworkIsolationKey associated with the beacons being uploaded. The
+ // first `uploading_beacons_size_` beacons that have NIK equal to
+ // `uploading_beacons_network_isolation_key_` are currently being uploaded.
+ // It's possible for this number to be 0 when there's still an active upload
+ // if all currently uploading beacons have been evicted.
+ net::NetworkIsolationKey uploading_beacons_network_isolation_key_;
+
base::TimeTicks upload_time_;
base::TimeTicks last_upload_time_;
// The last network change time is not tracked per-context, so this is a
diff --git a/chromium/components/domain_reliability/context_unittest.cc b/chromium/components/domain_reliability/context_unittest.cc
index 5506f286467..7a9bd45aeeb 100644
--- a/chromium/components/domain_reliability/context_unittest.cc
+++ b/chromium/components/domain_reliability/context_unittest.cc
@@ -14,6 +14,8 @@
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
#include "components/domain_reliability/beacon.h"
#include "components/domain_reliability/dispatcher.h"
#include "components/domain_reliability/scheduler.h"
@@ -32,6 +34,8 @@ using base::Value;
typedef std::vector<const DomainReliabilityBeacon*> BeaconVector;
+const char kBeaconOutcomeHistogram[] = "Net.DomainReliability.BeaconOutcome";
+
std::unique_ptr<DomainReliabilityBeacon> MakeCustomizedBeacon(
MockableTime* time,
std::string status,
@@ -53,11 +57,32 @@ std::unique_ptr<DomainReliabilityBeacon> MakeCustomizedBeacon(
beacon->start_time = time->NowTicks() - beacon->elapsed;
beacon->upload_depth = 0;
beacon->sample_rate = 1.0;
+ beacon->network_isolation_key = net::NetworkIsolationKey();
return beacon;
}
std::unique_ptr<DomainReliabilityBeacon> MakeBeacon(MockableTime* time) {
- return MakeCustomizedBeacon(time, "tcp.connection_reset", "", false);
+ return MakeCustomizedBeacon(time, "tcp.connection_reset" /* status */,
+ "" /* quic_error */,
+ false /* quic_port_migration_detected */);
+}
+
+std::unique_ptr<DomainReliabilityBeacon> MakeBeaconWithNetworkIsolationKey(
+ MockableTime* time,
+ const std::string& status,
+ const net::NetworkIsolationKey& network_isolation_key) {
+ std::unique_ptr<DomainReliabilityBeacon> beacon =
+ MakeCustomizedBeacon(time, status, "" /* quic_error */,
+ false /* quic_port_migration_detected */);
+ beacon->network_isolation_key = network_isolation_key;
+ return beacon;
+}
+
+// Create a status string from in integer. For eviction tests. Include string
+// values before and after the string representation of the integer, to make
+// sure only exact matches are found when searching a JSON string.
+std::string StatusFromInt(int i) {
+ return base::StringPrintf("status%i.test", i);
}
template <typename ValueType,
@@ -98,8 +123,9 @@ class DomainReliabilityContextTest : public testing::Test {
: last_network_change_time_(time_.NowTicks()),
dispatcher_(&time_),
params_(MakeTestSchedulerParams()),
- uploader_(base::BindOnce(&DomainReliabilityContextTest::OnUploadRequest,
- base::Unretained(this))),
+ uploader_(
+ base::BindRepeating(&DomainReliabilityContextTest::OnUploadRequest,
+ base::Unretained(this))),
upload_reporter_string_("test-reporter"),
upload_allowed_callback_(base::BindRepeating(
&DomainReliabilityContextTest::UploadAllowedCallback,
@@ -117,6 +143,8 @@ class DomainReliabilityContextTest : public testing::Test {
upload_allowed_callback_, &dispatcher_, &uploader_, std::move(config)));
}
+ void ShutDownContext() { context_.reset(); }
+
base::TimeDelta min_delay() const { return params_.minimum_upload_delay; }
base::TimeDelta max_delay() const { return params_.maximum_upload_delay; }
base::TimeDelta retry_interval() const {
@@ -147,10 +175,17 @@ class DomainReliabilityContextTest : public testing::Test {
return upload_url_;
}
+ const net::NetworkIsolationKey& upload_network_isolation_key() const {
+ EXPECT_TRUE(upload_pending_);
+ return upload_network_isolation_key_;
+ }
+
void CallUploadCallback(DomainReliabilityUploader::UploadResult result) {
ASSERT_TRUE(upload_pending_);
std::move(upload_callback_).Run(result);
upload_pending_ = false;
+ ++num_uploads_completed_;
+ EXPECT_EQ(num_uploads_completed_, num_uploads_);
}
bool CheckNoBeacons() {
@@ -179,13 +214,17 @@ class DomainReliabilityContextTest : public testing::Test {
void OnUploadRequest(const std::string& report_json,
int max_upload_depth,
const GURL& upload_url,
+ const net::NetworkIsolationKey& network_isolation_key,
DomainReliabilityUploader::UploadCallback callback) {
+ EXPECT_EQ(num_uploads_completed_, num_uploads_);
ASSERT_FALSE(upload_pending_);
upload_report_ = report_json;
upload_max_depth_ = max_upload_depth;
upload_url_ = upload_url;
+ upload_network_isolation_key_ = network_isolation_key;
upload_callback_ = std::move(callback);
upload_pending_ = true;
+ ++num_uploads_;
}
void UploadAllowedCallback(const GURL& origin,
@@ -194,10 +233,14 @@ class DomainReliabilityContextTest : public testing::Test {
upload_allowed_result_callback_ = std::move(callback);
}
+ int num_uploads_ = 0;
+ int num_uploads_completed_ = 0;
+
bool upload_pending_;
std::string upload_report_;
int upload_max_depth_;
GURL upload_url_;
+ net::NetworkIsolationKey upload_network_isolation_key_;
DomainReliabilityUploader::UploadCallback upload_callback_;
GURL upload_allowed_origin_;
@@ -209,13 +252,20 @@ TEST_F(DomainReliabilityContextTest, Create) {
EXPECT_TRUE(CheckNoBeacons());
}
-TEST_F(DomainReliabilityContextTest, Report) {
+TEST_F(DomainReliabilityContextTest, QueueBeacon) {
+ base::HistogramTester histograms;
InitContext(MakeTestConfig());
context_->OnBeacon(MakeBeacon(&time_));
BeaconVector beacons;
context_->GetQueuedBeaconsForTesting(&beacons);
EXPECT_EQ(1u, beacons.size());
+
+ ShutDownContext();
+ histograms.ExpectBucketCount(
+ kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kContextShutDown, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
}
TEST_F(DomainReliabilityContextTest, MaxNestedBeaconSchedules) {
@@ -251,6 +301,7 @@ TEST_F(DomainReliabilityContextTest, OverlyNestedBeaconDoesNotSchedule) {
TEST_F(DomainReliabilityContextTest,
MaxNestedBeaconAfterOverlyNestedBeaconSchedules) {
+ base::HistogramTester histograms;
InitContext(MakeTestConfig());
// Add a beacon for a report that's too nested to schedule a beacon.
std::unique_ptr<DomainReliabilityBeacon> beacon = MakeBeacon(&time_);
@@ -284,10 +335,17 @@ TEST_F(DomainReliabilityContextTest,
result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
CallUploadCallback(result);
+ histograms.ExpectBucketCount(kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kUploaded, 2);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 2);
+
EXPECT_TRUE(CheckNoBeacons());
+ ShutDownContext();
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 2);
}
TEST_F(DomainReliabilityContextTest, ReportUpload) {
+ base::HistogramTester histograms;
InitContext(MakeTestConfig());
context_->OnBeacon(
MakeCustomizedBeacon(&time_, "tcp.connection_reset", "", true));
@@ -326,9 +384,276 @@ TEST_F(DomainReliabilityContextTest, ReportUpload) {
result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
CallUploadCallback(result);
+ histograms.ExpectBucketCount(kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kUploaded, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
+
+ EXPECT_TRUE(CheckNoBeacons());
+ ShutDownContext();
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
+}
+
+TEST_F(DomainReliabilityContextTest, ReportUploadFails) {
+ InitContext(MakeTestConfig());
+ context_->OnBeacon(
+ MakeCustomizedBeacon(&time_, "tcp.connection_reset", "", true));
+
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ EXPECT_EQ(1u, beacons.size());
+
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(0, upload_max_depth());
+ EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
+
+ // The upload fails.
+ DomainReliabilityUploader::UploadResult result;
+ result.status = DomainReliabilityUploader::UploadResult::FAILURE;
+ CallUploadCallback(result);
+
+ // The beacon should still be pending.
+ beacons.clear();
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ EXPECT_EQ(1u, beacons.size());
+
+ // Another upload should be queued.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+}
+
+// Make sure that requests with only one NetworkIsolationKey are uploaded at a
+// time, in FIFO order.
+TEST_F(DomainReliabilityContextTest, ReportUploadNetworkIsolationKey) {
+ const net::NetworkIsolationKey kNetworkIsolationKey1 =
+ net::NetworkIsolationKey::CreateTransient();
+ const net::NetworkIsolationKey kNetworkIsolationKey2 =
+ net::NetworkIsolationKey::CreateTransient();
+ const net::NetworkIsolationKey kNetworkIsolationKey3 =
+ net::NetworkIsolationKey::CreateTransient();
+
+ InitContext(MakeTestConfig());
+
+ // Three beacons with kNetworkIsolationKey1, two with kNetworkIsolationKey2,
+ // and one with kNetworkIsolationKey3. Have beacons with the same key both
+ // adjacent to each other, and separated by beacons with other keys. Give
+ // each a unique status, so it's easy to check which beacons are included in
+ // each report.
+ const char kStatusNik11[] = "nik1.status1";
+ const char kStatusNik12[] = "nik1.status2";
+ const char kStatusNik13[] = "nik1.status3";
+ const char kStatusNik21[] = "nik2.status1";
+ const char kStatusNik22[] = "nik2.status2";
+ const char kStatusNik31[] = "nik3.status1";
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik11,
+ kNetworkIsolationKey1));
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik12,
+ kNetworkIsolationKey1));
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik21,
+ kNetworkIsolationKey2));
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik31,
+ kNetworkIsolationKey3));
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik13,
+ kNetworkIsolationKey1));
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik22,
+ kNetworkIsolationKey2));
+
+ // All the beacons should be queued, in FIFO order.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(6u, beacons.size());
+ EXPECT_EQ(kNetworkIsolationKey1, beacons[0]->network_isolation_key);
+ EXPECT_EQ(kStatusNik11, beacons[0]->status);
+ EXPECT_EQ(kNetworkIsolationKey1, beacons[1]->network_isolation_key);
+ EXPECT_EQ(kStatusNik12, beacons[1]->status);
+ EXPECT_EQ(kNetworkIsolationKey2, beacons[2]->network_isolation_key);
+ EXPECT_EQ(kStatusNik21, beacons[2]->status);
+ EXPECT_EQ(kNetworkIsolationKey3, beacons[3]->network_isolation_key);
+ EXPECT_EQ(kStatusNik31, beacons[3]->status);
+ EXPECT_EQ(kNetworkIsolationKey1, beacons[4]->network_isolation_key);
+ EXPECT_EQ(kStatusNik13, beacons[4]->status);
+ EXPECT_EQ(kNetworkIsolationKey2, beacons[5]->network_isolation_key);
+ EXPECT_EQ(kStatusNik22, beacons[5]->status);
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(0, upload_max_depth());
+ EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
+ EXPECT_EQ(kNetworkIsolationKey1, upload_network_isolation_key());
+
+ // Check that only the strings associated with the first NIK are present in
+ // the report.
+ EXPECT_NE(upload_report().find(kStatusNik11), std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik12), std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik13), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik21), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik22), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik31), std::string::npos);
+
+ // Complete upload.
+ DomainReliabilityUploader::UploadResult successful_result;
+ successful_result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(successful_result);
+
+ // There should still be 3 beacons queued, in the same order as before.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(3u, beacons.size());
+ EXPECT_EQ(kNetworkIsolationKey2, beacons[0]->network_isolation_key);
+ EXPECT_EQ(kStatusNik21, beacons[0]->status);
+ EXPECT_EQ(kNetworkIsolationKey3, beacons[1]->network_isolation_key);
+ EXPECT_EQ(kStatusNik31, beacons[1]->status);
+ EXPECT_EQ(kNetworkIsolationKey2, beacons[2]->network_isolation_key);
+ EXPECT_EQ(kStatusNik22, beacons[2]->status);
+
+ // The next upload should automatically trigger.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(0, upload_max_depth());
+ EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
+ EXPECT_EQ(kNetworkIsolationKey2, upload_network_isolation_key());
+
+ // Check that only the strings associated with the second NIK are present in
+ // the report.
+ EXPECT_EQ(upload_report().find(kStatusNik11), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik12), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik13), std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik21), std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik22), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik31), std::string::npos);
+ // Complete upload.
+ CallUploadCallback(successful_result);
+
+ // There should still be 1 beacon queued.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(1u, beacons.size());
+ EXPECT_EQ(kNetworkIsolationKey3, beacons[0]->network_isolation_key);
+ EXPECT_EQ(kStatusNik31, beacons[0]->status);
+
+ // The next upload should automatically trigger.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(0, upload_max_depth());
+ EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
+ EXPECT_EQ(kNetworkIsolationKey3, upload_network_isolation_key());
+
+ // Check that only the strings associated with the third NIK are present in
+ // the report.
+ EXPECT_EQ(upload_report().find(kStatusNik11), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik12), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik13), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik21), std::string::npos);
+ EXPECT_EQ(upload_report().find(kStatusNik22), std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik31), std::string::npos);
+ // Complete upload.
+ CallUploadCallback(successful_result);
+
EXPECT_TRUE(CheckNoBeacons());
}
+// Make sure that kMaxUploadDepthToSchedule is respected when requests have
+// different NetworkIsolationKeys.
+TEST_F(DomainReliabilityContextTest, ReportUploadDepthNetworkIsolationKey) {
+ const net::NetworkIsolationKey kNetworkIsolationKey1 =
+ net::NetworkIsolationKey::CreateTransient();
+ const net::NetworkIsolationKey kNetworkIsolationKey2 =
+ net::NetworkIsolationKey::CreateTransient();
+
+ InitContext(MakeTestConfig());
+
+ const char kStatusNik1ExceedsMaxDepth[] = "nik1.exceeds_max_depth";
+ const char kStatusNik2ExceedsMaxDepth[] = "nik2.exceeds_max_depth";
+ const char kStatusNik2MaxDepth[] = "nik2.max_depth";
+
+ // Add a beacon with kNetworkIsolationKey1 and a depth that exceeds the max
+ // depth to trigger an upload. No upload should be queued.
+ std::unique_ptr<DomainReliabilityBeacon> beacon =
+ MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik1ExceedsMaxDepth,
+ kNetworkIsolationKey1);
+ beacon->upload_depth =
+ DomainReliabilityContext::kMaxUploadDepthToSchedule + 1;
+ context_->OnBeacon(std::move(beacon));
+ time_.Advance(max_delay());
+ EXPECT_FALSE(upload_allowed_callback_pending());
+
+ // Add a beacon with kNetworkIsolationKey2 and a depth that exceeds the max
+ // depth to trigger an upload. No upload should be queued.
+ beacon = MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik2ExceedsMaxDepth,
+ kNetworkIsolationKey2);
+ beacon->upload_depth =
+ DomainReliabilityContext::kMaxUploadDepthToSchedule + 1;
+ context_->OnBeacon(std::move(beacon));
+ time_.Advance(max_delay());
+ EXPECT_FALSE(upload_allowed_callback_pending());
+
+ // Add a beacon with kNetworkIsolationKey2 and a depth that equals the max
+ // depth to trigger an upload. An upload should be queued.
+ beacon = MakeBeaconWithNetworkIsolationKey(&time_, kStatusNik2MaxDepth,
+ kNetworkIsolationKey2);
+ beacon->upload_depth = DomainReliabilityContext::kMaxUploadDepthToSchedule;
+ context_->OnBeacon(std::move(beacon));
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+
+ // All the beacons should still be queued.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(3u, beacons.size());
+ EXPECT_EQ(kNetworkIsolationKey1, beacons[0]->network_isolation_key);
+ EXPECT_EQ(kStatusNik1ExceedsMaxDepth, beacons[0]->status);
+ EXPECT_EQ(DomainReliabilityContext::kMaxUploadDepthToSchedule + 1,
+ beacons[0]->upload_depth);
+ EXPECT_EQ(kNetworkIsolationKey2, beacons[1]->network_isolation_key);
+ EXPECT_EQ(kStatusNik2ExceedsMaxDepth, beacons[1]->status);
+ EXPECT_EQ(DomainReliabilityContext::kMaxUploadDepthToSchedule + 1,
+ beacons[1]->upload_depth);
+ EXPECT_EQ(kNetworkIsolationKey2, beacons[2]->network_isolation_key);
+ EXPECT_EQ(kStatusNik2MaxDepth, beacons[2]->status);
+ EXPECT_EQ(DomainReliabilityContext::kMaxUploadDepthToSchedule,
+ beacons[2]->upload_depth);
+
+ // Start the upload.
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(DomainReliabilityContext::kMaxUploadDepthToSchedule + 1,
+ upload_max_depth());
+ EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
+ EXPECT_EQ(kNetworkIsolationKey2, upload_network_isolation_key());
+
+ // Check that only the strings associated with the second NIK are present in
+ // the report.
+ EXPECT_EQ(upload_report().find(kStatusNik1ExceedsMaxDepth),
+ std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik2ExceedsMaxDepth),
+ std::string::npos);
+ EXPECT_NE(upload_report().find(kStatusNik2MaxDepth), std::string::npos);
+
+ // Complete upload.
+ DomainReliabilityUploader::UploadResult successful_result;
+ successful_result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(successful_result);
+
+ // There should still be 1 beacon queued.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(1u, beacons.size());
+ EXPECT_EQ(kNetworkIsolationKey1, beacons[0]->network_isolation_key);
+ EXPECT_EQ(kStatusNik1ExceedsMaxDepth, beacons[0]->status);
+ EXPECT_EQ(DomainReliabilityContext::kMaxUploadDepthToSchedule + 1,
+ beacons[0]->upload_depth);
+
+ // No upload should be queued, since the depth is too high.
+ time_.Advance(max_delay());
+ EXPECT_FALSE(upload_allowed_callback_pending());
+}
+
TEST_F(DomainReliabilityContextTest, UploadForbidden) {
InitContext(MakeTestConfig());
context_->OnBeacon(
@@ -601,6 +926,7 @@ TEST_F(DomainReliabilityContextTest, SampleNoBeacons) {
}
TEST_F(DomainReliabilityContextTest, ExpiredBeaconDoesNotUpload) {
+ base::HistogramTester histograms;
InitContext(MakeTestConfig());
std::unique_ptr<DomainReliabilityBeacon> beacon = MakeBeacon(&time_);
time_.Advance(base::TimeDelta::FromHours(2));
@@ -611,6 +937,451 @@ TEST_F(DomainReliabilityContextTest, ExpiredBeaconDoesNotUpload) {
BeaconVector beacons;
context_->GetQueuedBeaconsForTesting(&beacons);
EXPECT_TRUE(beacons.empty());
+
+ histograms.ExpectBucketCount(kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kExpired, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
+
+ ShutDownContext();
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
+}
+
+TEST_F(DomainReliabilityContextTest, EvictOldestBeacon) {
+ base::HistogramTester histograms;
+ InitContext(MakeTestConfig());
+
+ std::unique_ptr<DomainReliabilityBeacon> oldest_beacon = MakeBeacon(&time_);
+ const DomainReliabilityBeacon* oldest_beacon_ptr = oldest_beacon.get();
+ time_.Advance(base::TimeDelta::FromSeconds(1));
+ context_->OnBeacon(std::move(oldest_beacon));
+
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ std::unique_ptr<DomainReliabilityBeacon> beacon = MakeBeacon(&time_);
+ time_.Advance(base::TimeDelta::FromSeconds(1));
+ context_->OnBeacon(std::move(beacon));
+ }
+
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ EXPECT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+
+ for (const DomainReliabilityBeacon* beacon : beacons) {
+ EXPECT_NE(oldest_beacon_ptr, beacon);
+ }
+
+ histograms.ExpectBucketCount(kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kEvicted, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
+
+ ShutDownContext();
+ histograms.ExpectBucketCount(
+ kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kContextShutDown,
+ DomainReliabilityContext::kMaxQueuedBeacons);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram,
+ 1 + DomainReliabilityContext::kMaxQueuedBeacons);
+}
+
+// Test eviction when there's no active upload.
+TEST_F(DomainReliabilityContextTest, Eviction) {
+ InitContext(MakeTestConfig());
+
+ // Add |DomainReliabilityContext::kMaxQueuedBeacons| beacons.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ context_->OnBeacon(
+ MakeCustomizedBeacon(&time_, StatusFromInt(i), "" /* quic_error */,
+ false /* quic_port_migration_detected */));
+ }
+
+ // No beacons should have been evicted.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i));
+ }
+
+ // Add one more beacon.
+ context_->OnBeacon(MakeCustomizedBeacon(
+ &time_, StatusFromInt(DomainReliabilityContext::kMaxQueuedBeacons),
+ "" /* quic_error */, false /* quic_port_migration_detected */));
+
+ // The first beacon should have been evicted.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i + 1));
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // All beacons but the first should be in the report.
+ EXPECT_EQ(upload_report().find(StatusFromInt(0)), std::string::npos);
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i + 1)), std::string::npos);
+ }
+
+ DomainReliabilityUploader::UploadResult result;
+ result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(result);
+
+ EXPECT_TRUE(CheckNoBeacons());
+}
+
+// Test eviction when there's an upload that eventually succeeds.
+TEST_F(DomainReliabilityContextTest, EvictionDuringSuccessfulUpload) {
+ InitContext(MakeTestConfig());
+
+ // Add |DomainReliabilityContext::kMaxQueuedBeacons| beacons.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ context_->OnBeacon(
+ MakeCustomizedBeacon(&time_, StatusFromInt(i), "" /* quic_error */,
+ false /* quic_port_migration_detected */));
+ }
+
+ // No beacons should have been evicted.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i));
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // All beacons should be in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+
+ // Add one more beacon.
+ context_->OnBeacon(MakeCustomizedBeacon(
+ &time_, StatusFromInt(DomainReliabilityContext::kMaxQueuedBeacons),
+ "" /* quic_error */, false /* quic_port_migration_detected */));
+
+ // The first beacon should have been evicted.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i + 1));
+ }
+
+ // The upload completes.
+ DomainReliabilityUploader::UploadResult successful_result;
+ successful_result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(successful_result);
+
+ // The last beacon should still be queued.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(1u, beacons.size());
+ EXPECT_EQ(beacons[0]->status,
+ StatusFromInt(DomainReliabilityContext::kMaxQueuedBeacons));
+
+ // Another upload should have still been queued, for the new report. Wait for
+ // it to start uploading.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // Only the last beacon should be in the report.
+ EXPECT_NE(upload_report().find(
+ StatusFromInt(DomainReliabilityContext::kMaxQueuedBeacons)),
+ std::string::npos);
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+
+ // The upload completes.
+ CallUploadCallback(successful_result);
+
+ EXPECT_TRUE(CheckNoBeacons());
+}
+
+// Test eviction when there's an upload that eventually fails.
+TEST_F(DomainReliabilityContextTest, EvictionDuringUnsuccessfulUpload) {
+ InitContext(MakeTestConfig());
+
+ // Add |DomainReliabilityContext::kMaxQueuedBeacons| beacons.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ context_->OnBeacon(
+ MakeCustomizedBeacon(&time_, StatusFromInt(i), "" /* quic_error */,
+ false /* quic_port_migration_detected */));
+ }
+
+ // No beacons should have been evicted.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i));
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // All beacons should be in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+
+ // Add one more beacon.
+ context_->OnBeacon(MakeCustomizedBeacon(
+ &time_, StatusFromInt(DomainReliabilityContext::kMaxQueuedBeacons),
+ "" /* quic_error */, false /* quic_port_migration_detected */));
+
+ // The first beacon should have been evicted.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i + 1));
+ }
+
+ // The upload fails.
+ DomainReliabilityUploader::UploadResult result;
+ result.status = DomainReliabilityUploader::UploadResult::FAILURE;
+ CallUploadCallback(result);
+
+ // All beacons but the first should still be queued.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i + 1));
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // All beacons but the first should be in the report.
+ EXPECT_EQ(upload_report().find(StatusFromInt(0)), std::string::npos);
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i + 1)), std::string::npos);
+ }
+
+ // The upload completes successfully.
+ result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(result);
+
+ EXPECT_TRUE(CheckNoBeacons());
+}
+
+// Test eviction of all initially pending reports when there's an upload that
+// eventually succeeds.
+TEST_F(DomainReliabilityContextTest, EvictAllDuringSuccessfulUpload) {
+ InitContext(MakeTestConfig());
+
+ // Add |DomainReliabilityContext::kMaxQueuedBeacons| beacons.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ context_->OnBeacon(
+ MakeCustomizedBeacon(&time_, StatusFromInt(i), "" /* quic_error */,
+ false /* quic_port_migration_detected */));
+ }
+
+ // No beacons should have been evicted.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i));
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // All beacons should be in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+
+ // Evict all beacons, twice. It's important to add a beacon after all beacons
+ // from the original report have already been deleted, to make sure that
+ // eviction works correctly once |uploading_beacons_size_| reaches 0.
+ for (size_t i = 0; i < 2 * DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ context_->OnBeacon(MakeCustomizedBeacon(
+ &time_, StatusFromInt(i + DomainReliabilityContext::kMaxQueuedBeacons),
+ "" /* quic_error */, false /* quic_port_migration_detected */));
+ }
+
+ // All the original beacons should have been evicted, as should the first
+ // |DomainReliabilityContext::kMaxQueuedBeacons| beacons from the above loop.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(
+ beacons[i]->status,
+ StatusFromInt(i + 2 * DomainReliabilityContext::kMaxQueuedBeacons));
+ }
+
+ // The upload succeeds, but no beacons should be removed, since all the
+ // original beacons have already been evicted.
+ DomainReliabilityUploader::UploadResult successful_result;
+ successful_result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(successful_result);
+
+ // The same beacons as before should be queued.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(
+ beacons[i]->status,
+ StatusFromInt(i + 2 * DomainReliabilityContext::kMaxQueuedBeacons));
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ // Check the expected beacons are in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons * 3; ++i) {
+ if (i < DomainReliabilityContext::kMaxQueuedBeacons * 2) {
+ EXPECT_EQ(upload_report().find(StatusFromInt(i)), std::string::npos);
+ } else {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+ }
+
+ // The upload completes successfully.
+ CallUploadCallback(successful_result);
+
+ EXPECT_TRUE(CheckNoBeacons());
+}
+
+// Make sure that evictions account for when there are different
+// NetworkIsolationKeys in use.
+TEST_F(DomainReliabilityContextTest,
+ EvictionDuringSuccessfulUploadNetworkIsolationKey) {
+ ASSERT_EQ(0u, DomainReliabilityContext::kMaxQueuedBeacons % 2)
+ << "DomainReliabilityContext::kMaxQueuedBeacons must be even.";
+
+ InitContext(MakeTestConfig());
+
+ net::NetworkIsolationKey network_isolation_keys[] = {
+ net::NetworkIsolationKey::CreateTransient(),
+ net::NetworkIsolationKey::CreateTransient(),
+ };
+
+ // Add |DomainReliabilityContext::kMaxQueuedBeacons| beacons, using a
+ // different NetworkIsolationKey for every other beacon.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(
+ &time_, StatusFromInt(i), network_isolation_keys[i % 2]));
+ }
+
+ // No beacons should have been evicted.
+ BeaconVector beacons;
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i));
+ EXPECT_EQ(beacons[i]->network_isolation_key, network_isolation_keys[i % 2]);
+ }
+
+ // Wait for the report to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(network_isolation_keys[0], upload_network_isolation_key());
+ // All even-numbered beacons should be in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ if (i % 2 == 0) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ } else {
+ EXPECT_EQ(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+ }
+
+ // Add two more beacons, using the same pattern as before
+ for (size_t i = 0; i < 2; ++i) {
+ context_->OnBeacon(MakeBeaconWithNetworkIsolationKey(
+ &time_, StatusFromInt(i + DomainReliabilityContext::kMaxQueuedBeacons),
+ network_isolation_keys[i % 2]));
+ }
+
+ // Only the first two beacons should have been evicted.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons, beacons.size());
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ EXPECT_EQ(beacons[i]->status, StatusFromInt(i + 2));
+ EXPECT_EQ(beacons[i]->network_isolation_key, network_isolation_keys[i % 2]);
+ }
+
+ // The upload succeeds. Every beacon using the first NetworkIsolationKey,
+ // except the second to last, should have been evicted.
+ DomainReliabilityUploader::UploadResult successful_result;
+ successful_result.status = DomainReliabilityUploader::UploadResult::SUCCESS;
+ CallUploadCallback(successful_result);
+
+ // Check remaining beacons.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(DomainReliabilityContext::kMaxQueuedBeacons / 2 + 1,
+ beacons.size());
+ int beacon_index = 0;
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons; ++i) {
+ if (i % 2 == 0 && i < DomainReliabilityContext::kMaxQueuedBeacons - 2)
+ continue;
+ EXPECT_EQ(beacons[beacon_index]->status, StatusFromInt(i + 2));
+ EXPECT_EQ(beacons[beacon_index]->network_isolation_key,
+ network_isolation_keys[i % 2]);
+ beacon_index++;
+ }
+
+ // Another report should be queued. Wait for it to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(network_isolation_keys[1], upload_network_isolation_key());
+ // Check the expected beacons are in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons + 2; ++i) {
+ if (i % 2 == 0 || i < 2) {
+ EXPECT_EQ(upload_report().find(StatusFromInt(i)), std::string::npos);
+ } else {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+ }
+
+ // The upload completes successfully.
+ CallUploadCallback(successful_result);
+
+ // Check remaining beacons. There should only be one left.
+ context_->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(1u, beacons.size());
+ EXPECT_EQ(beacons[0]->status,
+ StatusFromInt(DomainReliabilityContext::kMaxQueuedBeacons));
+ EXPECT_EQ(beacons[0]->network_isolation_key, network_isolation_keys[0]);
+
+ // Another report should be queued. Wait for it to start being uploaded.
+ time_.Advance(max_delay());
+ EXPECT_TRUE(upload_allowed_callback_pending());
+ CallUploadAllowedResultCallback(true);
+ EXPECT_TRUE(upload_pending());
+ EXPECT_EQ(network_isolation_keys[0], upload_network_isolation_key());
+ // Check the expected beacons are in the report.
+ for (size_t i = 0; i < DomainReliabilityContext::kMaxQueuedBeacons + 2; ++i) {
+ if (i == DomainReliabilityContext::kMaxQueuedBeacons) {
+ EXPECT_NE(upload_report().find(StatusFromInt(i)), std::string::npos);
+ } else {
+ EXPECT_EQ(upload_report().find(StatusFromInt(i)), std::string::npos);
+ }
+ }
+
+ // The upload completes successfully.
+ CallUploadCallback(successful_result);
+
+ EXPECT_TRUE(CheckNoBeacons());
}
// TODO(juliatuttle): Add beacon_unittest.cc to test serialization.
diff --git a/chromium/components/domain_reliability/features.cc b/chromium/components/domain_reliability/features.cc
new file mode 100644
index 00000000000..d216eb0d13e
--- /dev/null
+++ b/chromium/components/domain_reliability/features.cc
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/domain_reliability/features.h"
+
+namespace domain_reliability {
+namespace features {
+
+DOMAIN_RELIABILITY_EXPORT extern const base::Feature
+ kPartitionDomainReliabilityByNetworkIsolationKey{
+ "PartitionDomainReliabilityByNetworkIsolationKey",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace features
+} // namespace domain_reliability
diff --git a/chromium/components/domain_reliability/features.h b/chromium/components/domain_reliability/features.h
new file mode 100644
index 00000000000..9eda8ad9097
--- /dev/null
+++ b/chromium/components/domain_reliability/features.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOMAIN_RELIABILITY_FEATURES_H_
+#define COMPONENTS_DOMAIN_RELIABILITY_FEATURES_H_
+
+#include "base/feature_list.h"
+#include "components/domain_reliability/domain_reliability_export.h"
+
+namespace domain_reliability {
+namespace features {
+
+// Partitions Domain Reliability beacons and upload by NetworkIsolationKey.
+DOMAIN_RELIABILITY_EXPORT extern const base::Feature
+ kPartitionDomainReliabilityByNetworkIsolationKey;
+
+} // namespace features
+} // namespace domain_reliability
+
+#endif // COMPONENTS_DOMAIN_RELIABILITY_FEATURES_H_ \ No newline at end of file
diff --git a/chromium/components/domain_reliability/monitor.cc b/chromium/components/domain_reliability/monitor.cc
index 2d9125fbe35..8b6a03ad95f 100644
--- a/chromium/components/domain_reliability/monitor.cc
+++ b/chromium/components/domain_reliability/monitor.cc
@@ -10,12 +10,16 @@
#include "base/bind.h"
#include "base/check.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/notreached.h"
#include "components/domain_reliability/baked_in_configs.h"
+#include "components/domain_reliability/features.h"
#include "components/domain_reliability/google_configs.h"
#include "components/domain_reliability/quic_error_mapping.h"
+#include "net/base/isolation_info.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/base/network_isolation_key.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -186,6 +190,7 @@ DomainReliabilityMonitor::RequestInfo::RequestInfo(
const net::URLRequest& request,
int net_error)
: url(request.url()),
+ network_isolation_key(request.isolation_info().network_isolation_key()),
net_error(net_error),
response_info(request.response_info()),
// This ignores cookie blocking by the NetworkDelegate, but probably
@@ -267,6 +272,10 @@ void DomainReliabilityMonitor::OnRequestLegComplete(
beacon_template.elapsed = time_->NowTicks() - beacon_template.start_time;
beacon_template.was_proxied = request.response_info.was_fetched_via_proxy;
beacon_template.url = request.url;
+ if (base::FeatureList::IsEnabled(
+ features::kPartitionDomainReliabilityByNetworkIsolationKey)) {
+ beacon_template.network_isolation_key = request.network_isolation_key;
+ }
beacon_template.upload_depth = request.upload_depth;
beacon_template.details = request.details;
diff --git a/chromium/components/domain_reliability/monitor.h b/chromium/components/domain_reliability/monitor.h
index 9306877409e..a606a84fd65 100644
--- a/chromium/components/domain_reliability/monitor.h
+++ b/chromium/components/domain_reliability/monitor.h
@@ -28,6 +28,7 @@
#include "net/base/load_timing_info.h"
#include "net/base/net_error_details.h"
#include "net/base/network_change_notifier.h"
+#include "net/base/network_isolation_key.h"
#include "net/http/http_response_info.h"
#include "net/socket/connection_attempts.h"
@@ -58,6 +59,7 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityMonitor
static bool ShouldReportRequest(const RequestInfo& request);
GURL url;
+ net::NetworkIsolationKey network_isolation_key;
int net_error;
net::HttpResponseInfo response_info;
bool allow_credentials;
diff --git a/chromium/components/domain_reliability/monitor_unittest.cc b/chromium/components/domain_reliability/monitor_unittest.cc
index 8031bb46b86..f51f05e529f 100644
--- a/chromium/components/domain_reliability/monitor_unittest.cc
+++ b/chromium/components/domain_reliability/monitor_unittest.cc
@@ -15,15 +15,28 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/strings/string_piece.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "base/time/time.h"
#include "components/domain_reliability/baked_in_configs.h"
#include "components/domain_reliability/beacon.h"
#include "components/domain_reliability/config.h"
+#include "components/domain_reliability/features.h"
#include "components/domain_reliability/google_configs.h"
#include "components/domain_reliability/test_util.h"
+#include "net/base/isolation_info.h"
+#include "net/base/load_timing_info.h"
#include "net/base/net_errors.h"
+#include "net/base/network_isolation_key.h"
+#include "net/base/request_priority.h"
#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
#include "net/http/http_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/gtest_util.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,6 +46,8 @@ namespace {
typedef std::vector<const DomainReliabilityBeacon*> BeaconVector;
+const char kBeaconOutcomeHistogram[] = "Net.DomainReliability.BeaconOutcome";
+
scoped_refptr<net::HttpResponseHeaders> MakeHttpResponseHeaders(
base::StringPiece headers) {
return base::MakeRefCounted<net::HttpResponseHeaders>(
@@ -103,7 +118,8 @@ class DomainReliabilityMonitorTest : public testing::Test {
return monitor_.AddContextForTesting(std::move(config));
}
- base::test::SingleThreadTaskEnvironment task_environment_;
+ base::test::SingleThreadTaskEnvironment task_environment_{
+ base::test::TaskEnvironment::MainThreadType::IO};
net::TestURLRequestContext url_request_context_;
MockTime* time_;
DomainReliabilityMonitor monitor_;
@@ -267,6 +283,46 @@ TEST_F(DomainReliabilityMonitorTest, Upload) {
EXPECT_EQ(1u, CountQueuedBeacons(context));
}
+// Make sure NetworkIsolationKey is populated in the beacon, or not, depending
+// on features::kPartitionDomainReliabilityByNetworkIsolationKey.
+TEST_F(DomainReliabilityMonitorTest, NetworkIsolationKey) {
+ const net::NetworkIsolationKey kNetworkIsolationKey =
+ net::NetworkIsolationKey::CreateTransient();
+
+ const DomainReliabilityContext* context = CreateAndAddContext();
+
+ size_t index = 0;
+ for (bool partitioning_enabled : {false, true}) {
+ base::test::ScopedFeatureList feature_list;
+ if (partitioning_enabled) {
+ feature_list.InitAndEnableFeature(
+ features::kPartitionDomainReliabilityByNetworkIsolationKey);
+ } else {
+ feature_list.InitAndDisableFeature(
+ features::kPartitionDomainReliabilityByNetworkIsolationKey);
+ }
+ RequestInfo request = MakeRequestInfo();
+ request.url = GURL("http://example/");
+ request.allow_credentials = false;
+ request.net_error = net::ERR_CONNECTION_RESET;
+ request.upload_depth = 1;
+ request.network_isolation_key = kNetworkIsolationKey;
+ OnRequestLegComplete(request);
+
+ BeaconVector beacons;
+ context->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(index + 1, beacons.size());
+ if (partitioning_enabled) {
+ EXPECT_EQ(kNetworkIsolationKey, beacons[index]->network_isolation_key);
+ } else {
+ EXPECT_EQ(net::NetworkIsolationKey(),
+ beacons[index]->network_isolation_key);
+ }
+
+ ++index;
+ }
+}
+
// Will fail when baked-in configs expire, as a reminder to update them.
// (File a bug in Internals>Network>ReportingAndNEL if this starts failing.)
TEST_F(DomainReliabilityMonitorTest, BakedInAndGoogleConfigs) {
@@ -337,6 +393,7 @@ TEST_F(DomainReliabilityMonitorTest, GoogleConfigOnDemand) {
}
TEST_F(DomainReliabilityMonitorTest, ClearBeacons) {
+ base::HistogramTester histograms;
const DomainReliabilityContext* context = CreateAndAddContext();
// Initially the monitor should have just the test context, with no beacons.
@@ -357,9 +414,14 @@ TEST_F(DomainReliabilityMonitorTest, ClearBeacons) {
// Make sure the beacon was cleared, but not the contexts.
EXPECT_EQ(1u, monitor_.contexts_size_for_testing());
EXPECT_EQ(0u, CountQueuedBeacons(context));
+
+ histograms.ExpectBucketCount(kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kCleared, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
}
TEST_F(DomainReliabilityMonitorTest, ClearBeaconsWithFilter) {
+ base::HistogramTester histograms;
// Create two contexts, each with one beacon.
GURL origin1("http://example.com/");
GURL origin2("http://example.org/");
@@ -390,18 +452,35 @@ TEST_F(DomainReliabilityMonitorTest, ClearBeaconsWithFilter) {
EXPECT_EQ(2u, monitor_.contexts_size_for_testing());
EXPECT_EQ(0u, CountQueuedBeacons(context1));
EXPECT_EQ(1u, CountQueuedBeacons(context2));
+
+ histograms.ExpectBucketCount(kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kCleared, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
}
TEST_F(DomainReliabilityMonitorTest, ClearContexts) {
- CreateAndAddContext();
+ base::HistogramTester histograms;
+ const DomainReliabilityContext* context = CreateAndAddContext();
// Initially the monitor should have just the test context.
EXPECT_EQ(1u, monitor_.contexts_size_for_testing());
+ // Add a beacon so we can test histogram behavior.
+ RequestInfo request = MakeRequestInfo();
+ request.url = GURL("http://example/");
+ request.net_error = net::ERR_CONNECTION_RESET;
+ OnRequestLegComplete(request);
+ EXPECT_EQ(1u, CountQueuedBeacons(context));
+
monitor_.ClearBrowsingData(CLEAR_CONTEXTS, base::NullCallback());
// Clearing contexts should leave the monitor with none.
EXPECT_EQ(0u, monitor_.contexts_size_for_testing());
+
+ histograms.ExpectBucketCount(
+ kBeaconOutcomeHistogram,
+ DomainReliabilityBeacon::Outcome::kContextShutDown, 1);
+ histograms.ExpectTotalCount(kBeaconOutcomeHistogram, 1);
}
TEST_F(DomainReliabilityMonitorTest, ClearContextsWithFilter) {
@@ -491,6 +570,72 @@ TEST_F(DomainReliabilityMonitorTest,
EXPECT_EQ(0u, CountQueuedBeacons(context2));
}
+// Uses a real request, to make sure CreateBeaconFromAttempt() works as
+// expected.
+TEST_F(DomainReliabilityMonitorTest, RealRequest) {
+ const net::IsolationInfo kIsolationInfo =
+ net::IsolationInfo::CreateTransient();
+
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kPartitionDomainReliabilityByNetworkIsolationKey);
+
+ net::test_server::EmbeddedTestServer test_server;
+ test_server.AddDefaultHandlers();
+ ASSERT_TRUE(test_server.Start());
+
+ std::unique_ptr<DomainReliabilityConfig> config(
+ MakeTestConfigWithOrigin(test_server.base_url()));
+ const DomainReliabilityContext* context =
+ monitor_.AddContextForTesting(std::move(config));
+
+ base::TimeTicks start = base::TimeTicks::Now();
+
+ net::TestDelegate test_delegate;
+ std::unique_ptr<net::URLRequest> url_request =
+ url_request_context_.CreateRequest(test_server.GetURL("/close-socket"),
+ net::DEFAULT_PRIORITY, &test_delegate,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
+ url_request->set_isolation_info(kIsolationInfo);
+ url_request->Start();
+
+ test_delegate.RunUntilComplete();
+ EXPECT_THAT(test_delegate.request_status(),
+ net::test::IsError(net::ERR_EMPTY_RESPONSE));
+
+ net::LoadTimingInfo load_timing_info;
+ url_request->GetLoadTimingInfo(&load_timing_info);
+ base::TimeDelta expected_elapsed = base::TimeDelta::FromSeconds(1);
+ time_->Advance(load_timing_info.request_start - time_->NowTicks() +
+ expected_elapsed);
+
+ monitor_.OnCompleted(url_request.get(), true /* started */,
+ test_delegate.request_status());
+ BeaconVector beacons;
+ context->GetQueuedBeaconsForTesting(&beacons);
+ ASSERT_EQ(1u, beacons.size());
+ EXPECT_EQ(url_request->url(), beacons[0]->url);
+ EXPECT_EQ(kIsolationInfo.network_isolation_key(),
+ beacons[0]->network_isolation_key);
+ EXPECT_EQ("http.response.empty", beacons[0]->status);
+ EXPECT_EQ("", beacons[0]->quic_error);
+ EXPECT_EQ(net::ERR_EMPTY_RESPONSE, beacons[0]->chrome_error);
+ EXPECT_EQ(test_server.base_url().host() + ":" + test_server.base_url().port(),
+ beacons[0]->server_ip);
+ EXPECT_FALSE(beacons[0]->was_proxied);
+ EXPECT_EQ("HTTP", beacons[0]->protocol);
+ EXPECT_FALSE(beacons[0]->details.quic_broken);
+ EXPECT_EQ(quic::QUIC_NO_ERROR, beacons[0]->details.quic_connection_error);
+ EXPECT_EQ(net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
+ beacons[0]->details.connection_info);
+ EXPECT_FALSE(beacons[0]->details.quic_port_migration_detected);
+ EXPECT_EQ(-1, beacons[0]->http_response_code);
+ EXPECT_EQ(expected_elapsed, beacons[0]->elapsed);
+ EXPECT_LE(start, beacons[0]->start_time);
+ EXPECT_EQ(0, beacons[0]->upload_depth);
+ EXPECT_LE(0.99, beacons[0]->sample_rate);
+}
+
} // namespace
} // namespace domain_reliability
diff --git a/chromium/components/domain_reliability/quic_error_mapping.cc b/chromium/components/domain_reliability/quic_error_mapping.cc
index 70aeff4bf41..1dbd1ebc531 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.cc
+++ b/chromium/components/domain_reliability/quic_error_mapping.cc
@@ -431,6 +431,27 @@ const struct QuicErrorMapping {
"quic.invalid.application_close_data"},
{quic::QUIC_MAX_AGE_TIMEOUT, "quic.quic_max_age_timeout"},
+ {quic::QUIC_INVALID_0RTT_PACKET_NUMBER_OUT_OF_ORDER,
+ "quic.quic_invalid_0rtt_packet_number_out_of_order"},
+ {quic::QUIC_INVALID_PRIORITY_UPDATE, "quic::quic_invalid_priority_update"},
+ {quic::QUIC_PEER_PORT_CHANGE_HANDSHAKE_UNCONFIRMED,
+ "quic.peer_port_change_handshake_unconfirmed"},
+
+ {quic::QUIC_TLS_BAD_CERTIFICATE, "quic::quic_tls_bad_certificate"},
+ {quic::QUIC_TLS_UNSUPPORTED_CERTIFICATE,
+ "quic::quic_tls_unsupported_certificate"},
+ {quic::QUIC_TLS_CERTIFICATE_REVOKED, "quic::quic_tls_certificate_revoked"},
+ {quic::QUIC_TLS_CERTIFICATE_EXPIRED, "quic::quic_tls_certificate_expired"},
+ {quic::QUIC_TLS_CERTIFICATE_UNKNOWN, "quic::quic_tls_certificate_unknown"},
+ {quic::QUIC_TLS_INTERNAL_ERROR, "quic::quic_tls_internal_error"},
+ {quic::QUIC_TLS_UNRECOGNIZED_NAME, "quic::quic_tls_unrecognized_name"},
+ {quic::QUIC_TLS_CERTIFICATE_REQUIRED,
+ "quic::quic_tls_certificate_required"},
+ {quic::QUIC_CONNECTION_ID_LIMIT_ERROR,
+ "quic::quic_connection_id_limit_error"},
+ {quic::QUIC_TOO_MANY_CONNECTION_ID_WAITING_TO_RETIRE,
+ "quic::quic_too_many_connection_id_waiting_to_retire"},
+
// No error. Used as bound while iterating.
{quic::QUIC_LAST_ERROR, "quic.last_error"}};
diff --git a/chromium/components/domain_reliability/test_util.cc b/chromium/components/domain_reliability/test_util.cc
index 05db9cbec7b..6926d8a9baa 100644
--- a/chromium/components/domain_reliability/test_util.cc
+++ b/chromium/components/domain_reliability/test_util.cc
@@ -84,18 +84,20 @@ void TestCallback::OnCalled() {
}
MockUploader::MockUploader(UploadRequestCallback callback)
- : callback_(std::move(callback)), discard_uploads_(true) {}
+ : callback_(callback), discard_uploads_(true) {}
MockUploader::~MockUploader() = default;
bool MockUploader::discard_uploads() const { return discard_uploads_; }
-void MockUploader::UploadReport(const std::string& report_json,
- int max_upload_depth,
- const GURL& upload_url,
- UploadCallback callback) {
- std::move(callback_).Run(report_json, max_upload_depth, upload_url,
- std::move(callback));
+void MockUploader::UploadReport(
+ const std::string& report_json,
+ int max_upload_depth,
+ const GURL& upload_url,
+ const net::NetworkIsolationKey& network_isolation_key,
+ UploadCallback callback) {
+ callback_.Run(report_json, max_upload_depth, upload_url,
+ network_isolation_key, std::move(callback));
}
void MockUploader::Shutdown() {}
diff --git a/chromium/components/domain_reliability/test_util.h b/chromium/components/domain_reliability/test_util.h
index 11c2505ae66..211f96cb64d 100644
--- a/chromium/components/domain_reliability/test_util.h
+++ b/chromium/components/domain_reliability/test_util.h
@@ -15,6 +15,10 @@
#include "net/base/host_port_pair.h"
#include "url/gurl.h"
+namespace net {
+class NetworkIsolationKey;
+} // namespace net
+
namespace domain_reliability {
// A simple test callback that remembers whether it's been called.
@@ -37,10 +41,12 @@ class TestCallback {
class MockUploader : public DomainReliabilityUploader {
public:
- typedef base::OnceCallback<void(const std::string& report_json,
- int max_upload_depth,
- const GURL& upload_url,
- UploadCallback upload_callback)>
+ typedef base::RepeatingCallback<void(
+ const std::string& report_json,
+ int max_upload_depth,
+ const GURL& upload_url,
+ const net::NetworkIsolationKey& network_isolation_key,
+ UploadCallback upload_callback)>
UploadRequestCallback;
explicit MockUploader(UploadRequestCallback callback);
@@ -53,6 +59,7 @@ class MockUploader : public DomainReliabilityUploader {
void UploadReport(const std::string& report_json,
int max_upload_depth,
const GURL& upload_url,
+ const net::NetworkIsolationKey& network_isolation_key,
UploadCallback callback) override;
void Shutdown() override;
void SetDiscardUploads(bool discard_uploads) override;
diff --git a/chromium/components/domain_reliability/uploader.cc b/chromium/components/domain_reliability/uploader.cc
index 159526609b6..b674567c549 100644
--- a/chromium/components/domain_reliability/uploader.cc
+++ b/chromium/components/domain_reliability/uploader.cc
@@ -12,6 +12,7 @@
#include "base/supports_user_data.h"
#include "components/domain_reliability/util.h"
#include "net/base/elements_upload_data_stream.h"
+#include "net/base/isolation_info.h"
#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/http/http_response_headers.h"
@@ -70,6 +71,7 @@ class DomainReliabilityUploaderImpl : public DomainReliabilityUploader,
const std::string& report_json,
int max_upload_depth,
const GURL& upload_url,
+ const net::NetworkIsolationKey& network_isolation_key,
DomainReliabilityUploader::UploadCallback callback) override {
DVLOG(1) << "Uploading report to " << upload_url;
DVLOG(2) << "Report JSON: " << report_json;
@@ -119,6 +121,8 @@ class DomainReliabilityUploaderImpl : public DomainReliabilityUploader,
request->set_allow_credentials(false);
request->SetExtraRequestHeaderByName(net::HttpRequestHeaders::kContentType,
kJsonMimeType, true /* overwrite */);
+ request->set_isolation_info(net::IsolationInfo::CreatePartial(
+ net::IsolationInfo::RequestType::kOther, network_isolation_key));
std::vector<char> report_data(report_json.begin(), report_json.end());
auto upload_reader =
std::make_unique<net::UploadOwnedBytesElementReader>(&report_data);
diff --git a/chromium/components/domain_reliability/uploader.h b/chromium/components/domain_reliability/uploader.h
index 4e2e56ca066..9a0169e1f98 100644
--- a/chromium/components/domain_reliability/uploader.h
+++ b/chromium/components/domain_reliability/uploader.h
@@ -15,6 +15,7 @@
#include "url/gurl.h"
namespace net {
+class NetworkIsolationKey;
class URLRequest;
class URLRequestContext;
} // namespace net
@@ -55,10 +56,12 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityUploader {
// Uploads |report_json| to |upload_url| and calls |callback| when the upload
// has either completed or failed.
- virtual void UploadReport(const std::string& report_json,
- int max_beacon_depth,
- const GURL& upload_url,
- UploadCallback callback) = 0;
+ virtual void UploadReport(
+ const std::string& report_json,
+ int max_beacon_depth,
+ const GURL& upload_url,
+ const net::NetworkIsolationKey& network_isolation_key,
+ UploadCallback callback) = 0;
// Shuts down the uploader prior to destruction. Currently, terminates pending
// uploads and prevents the uploader from starting new ones to avoid hairy
diff --git a/chromium/components/domain_reliability/uploader_unittest.cc b/chromium/components/domain_reliability/uploader_unittest.cc
index 548448bbbff..c899cf41040 100644
--- a/chromium/components/domain_reliability/uploader_unittest.cc
+++ b/chromium/components/domain_reliability/uploader_unittest.cc
@@ -16,7 +16,9 @@
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/domain_reliability/test_util.h"
+#include "net/base/isolation_info.h"
#include "net/base/load_flags.h"
+#include "net/base/network_isolation_key.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/log/net_log_with_source.h"
@@ -101,12 +103,19 @@ class UploadMockURLRequestJob : public net::URLRequestJob {
class UploadInterceptor : public net::URLRequestInterceptor {
public:
- UploadInterceptor() : request_count_(0), last_upload_depth_(-1) {}
+ explicit UploadInterceptor(
+ const net::IsolationInfo& expected_network_isolation_info)
+ : expected_network_isolation_info_(expected_network_isolation_info),
+ request_count_(0),
+ last_upload_depth_(-1) {}
~UploadInterceptor() override { EXPECT_TRUE(results_.empty()); }
std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
net::URLRequest* request) const override {
+ EXPECT_TRUE(expected_network_isolation_info_.IsEqualForTesting(
+ request->isolation_info()));
+
EXPECT_FALSE(results_.empty());
MockUploadResult result = results_.front();
results_.pop_front();
@@ -137,6 +146,8 @@ class UploadInterceptor : public net::URLRequestInterceptor {
int last_upload_depth() const { return last_upload_depth_; }
private:
+ const net::IsolationInfo expected_network_isolation_info_;
+
mutable std::list<MockUploadResult> results_;
mutable int request_count_;
mutable int last_upload_depth_;
@@ -171,7 +182,8 @@ class DomainReliabilityUploaderTest : public testing::Test {
DomainReliabilityUploaderTest()
: uploader_(
DomainReliabilityUploader::Create(&time_, &url_request_context_)) {
- auto interceptor = std::make_unique<UploadInterceptor>();
+ auto interceptor =
+ std::make_unique<UploadInterceptor>(expected_isolation_info_);
interceptor_ = interceptor.get();
net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
GURL(kUploadURL), std::move(interceptor));
@@ -188,9 +200,17 @@ class DomainReliabilityUploaderTest : public testing::Test {
return &url_request_context_;
}
+ const net::NetworkIsolationKey& network_isolation_key() const {
+ return expected_isolation_info_.network_isolation_key();
+ }
+
private:
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
+
+ const net::IsolationInfo expected_isolation_info_ =
+ net::IsolationInfo::CreateTransient();
+
net::TestURLRequestContext url_request_context_;
UploadInterceptor* interceptor_;
MockTime time_;
@@ -205,7 +225,8 @@ TEST_F(DomainReliabilityUploaderTest, SuccessfulUpload) {
interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 200\r\n\r\n");
TestUploadCallback c;
- uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 0, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
EXPECT_TRUE(c.last_result().is_success());
@@ -217,7 +238,8 @@ TEST_F(DomainReliabilityUploaderTest, NetworkErrorUpload) {
interceptor()->ExpectRequestAndReturnError(net::ERR_CONNECTION_REFUSED);
TestUploadCallback c;
- uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 0, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
EXPECT_TRUE(c.last_result().is_failure());
@@ -229,7 +251,8 @@ TEST_F(DomainReliabilityUploaderTest, ServerErrorUpload) {
interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 500\r\n\r\n");
TestUploadCallback c;
- uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 0, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
EXPECT_TRUE(c.last_result().is_failure());
@@ -242,7 +265,8 @@ TEST_F(DomainReliabilityUploaderTest, RetryAfterUpload) {
"HTTP/1.1 503 Ugh\nRetry-After: 3600\n\n");
TestUploadCallback c;
- uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 0, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
EXPECT_TRUE(c.last_result().is_retry_after());
@@ -254,7 +278,8 @@ TEST_F(DomainReliabilityUploaderTest, UploadDepth1) {
interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 200\r\n\r\n");
TestUploadCallback c;
- uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 0, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
@@ -267,7 +292,8 @@ TEST_F(DomainReliabilityUploaderTest, UploadDepth2) {
interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 200\r\n\r\n");
TestUploadCallback c;
- uploader()->UploadReport("{}", 1, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 1, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
@@ -280,7 +306,8 @@ TEST_F(DomainReliabilityUploaderTest, UploadCanceledAtShutdown) {
interceptor()->ExpectRequestAndReturnError(net::ERR_IO_PENDING);
TestUploadCallback c;
- uploader()->UploadReport("{}", 1, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 1, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, interceptor()->request_count());
EXPECT_EQ(0u, c.called_count());
@@ -296,7 +323,8 @@ TEST_F(DomainReliabilityUploaderTest, NoUploadAfterShutdown) {
uploader()->Shutdown();
TestUploadCallback c;
- uploader()->UploadReport("{}", 1, GURL(kUploadURL), c.callback());
+ uploader()->UploadReport("{}", 1, GURL(kUploadURL), network_isolation_key(),
+ c.callback());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, c.called_count());
EXPECT_EQ(0, interceptor()->request_count());