xref: /aosp_15_r20/external/cronet/net/dns/httpssvc_metrics_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/dns/httpssvc_metrics.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <optional>
8*6777b538SAndroid Build Coastguard Worker #include <string>
9*6777b538SAndroid Build Coastguard Worker #include <string_view>
10*6777b538SAndroid Build Coastguard Worker #include <tuple>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/test/metrics/histogram_tester.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/test/scoped_feature_list.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
19*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace net {
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker // Base for testing the metrics collection code in |HttpssvcMetrics|.
24*6777b538SAndroid Build Coastguard Worker class HttpssvcMetricsTest : public ::testing::TestWithParam<bool> {
25*6777b538SAndroid Build Coastguard Worker  public:
SetUp()26*6777b538SAndroid Build Coastguard Worker   void SetUp() override { secure_ = GetParam(); }
27*6777b538SAndroid Build Coastguard Worker 
BuildMetricNamePrefix() const28*6777b538SAndroid Build Coastguard Worker   std::string BuildMetricNamePrefix() const {
29*6777b538SAndroid Build Coastguard Worker     return base::StrCat({"Net.DNS.HTTPSSVC.RecordHttps.",
30*6777b538SAndroid Build Coastguard Worker                          secure_ ? "Secure." : "Insecure.", "ExpectNoerror."});
31*6777b538SAndroid Build Coastguard Worker   }
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker   template <typename T>
ExpectSample(std::string_view name,std::optional<T> sample) const34*6777b538SAndroid Build Coastguard Worker   void ExpectSample(std::string_view name, std::optional<T> sample) const {
35*6777b538SAndroid Build Coastguard Worker     if (sample)
36*6777b538SAndroid Build Coastguard Worker       histo().ExpectUniqueSample(name, *sample, 1);
37*6777b538SAndroid Build Coastguard Worker     else
38*6777b538SAndroid Build Coastguard Worker       histo().ExpectTotalCount(name, 0);
39*6777b538SAndroid Build Coastguard Worker   }
40*6777b538SAndroid Build Coastguard Worker 
ExpectSample(std::string_view name,std::optional<base::TimeDelta> sample) const41*6777b538SAndroid Build Coastguard Worker   void ExpectSample(std::string_view name,
42*6777b538SAndroid Build Coastguard Worker                     std::optional<base::TimeDelta> sample) const {
43*6777b538SAndroid Build Coastguard Worker     std::optional<int64_t> sample_ms;
44*6777b538SAndroid Build Coastguard Worker     if (sample)
45*6777b538SAndroid Build Coastguard Worker       sample_ms = {sample->InMilliseconds()};
46*6777b538SAndroid Build Coastguard Worker     ExpectSample<int64_t>(name, sample_ms);
47*6777b538SAndroid Build Coastguard Worker   }
48*6777b538SAndroid Build Coastguard Worker 
VerifyAddressResolveTimeMetric(std::optional<base::TimeDelta> expect_noerror_time=std::nullopt)49*6777b538SAndroid Build Coastguard Worker   void VerifyAddressResolveTimeMetric(
50*6777b538SAndroid Build Coastguard Worker       std::optional<base::TimeDelta> expect_noerror_time = std::nullopt) {
51*6777b538SAndroid Build Coastguard Worker     const std::string kExpectNoerror =
52*6777b538SAndroid Build Coastguard Worker         base::StrCat({BuildMetricNamePrefix(), "ResolveTimeAddress"});
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker     ExpectSample(kExpectNoerror, expect_noerror_time);
55*6777b538SAndroid Build Coastguard Worker   }
56*6777b538SAndroid Build Coastguard Worker 
VerifyHttpsMetricsForExpectNoerror(std::optional<HttpssvcDnsRcode> rcode=std::nullopt,std::optional<bool> parsable=std::nullopt,std::optional<bool> record_with_error=std::nullopt,std::optional<base::TimeDelta> resolve_time_https=std::nullopt,std::optional<int> resolve_time_ratio=std::nullopt) const57*6777b538SAndroid Build Coastguard Worker   void VerifyHttpsMetricsForExpectNoerror(
58*6777b538SAndroid Build Coastguard Worker       std::optional<HttpssvcDnsRcode> rcode = std::nullopt,
59*6777b538SAndroid Build Coastguard Worker       std::optional<bool> parsable = std::nullopt,
60*6777b538SAndroid Build Coastguard Worker       std::optional<bool> record_with_error = std::nullopt,
61*6777b538SAndroid Build Coastguard Worker       std::optional<base::TimeDelta> resolve_time_https = std::nullopt,
62*6777b538SAndroid Build Coastguard Worker       std::optional<int> resolve_time_ratio = std::nullopt) const {
63*6777b538SAndroid Build Coastguard Worker     const std::string kPrefix = BuildMetricNamePrefix();
64*6777b538SAndroid Build Coastguard Worker     const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"});
65*6777b538SAndroid Build Coastguard Worker     const std::string kMetricParsable = base::StrCat({kPrefix, "Parsable"});
66*6777b538SAndroid Build Coastguard Worker     const std::string kMetricRecordWithError =
67*6777b538SAndroid Build Coastguard Worker         base::StrCat({kPrefix, "RecordWithError"});
68*6777b538SAndroid Build Coastguard Worker     const std::string kMetricResolveTimeExperimental =
69*6777b538SAndroid Build Coastguard Worker         base::StrCat({kPrefix, "ResolveTimeExperimental"});
70*6777b538SAndroid Build Coastguard Worker     const std::string kMetricResolveTimeRatio =
71*6777b538SAndroid Build Coastguard Worker         base::StrCat({kPrefix, "ResolveTimeRatio"});
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker     ExpectSample(kMetricDnsRcode, rcode);
74*6777b538SAndroid Build Coastguard Worker     ExpectSample(kMetricParsable, parsable);
75*6777b538SAndroid Build Coastguard Worker     ExpectSample(kMetricRecordWithError, record_with_error);
76*6777b538SAndroid Build Coastguard Worker     ExpectSample(kMetricResolveTimeExperimental, resolve_time_https);
77*6777b538SAndroid Build Coastguard Worker     ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio);
78*6777b538SAndroid Build Coastguard Worker   }
79*6777b538SAndroid Build Coastguard Worker 
histo() const80*6777b538SAndroid Build Coastguard Worker   const base::HistogramTester& histo() const { return histogram_; }
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker  protected:
83*6777b538SAndroid Build Coastguard Worker   bool secure_;
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker  private:
86*6777b538SAndroid Build Coastguard Worker   base::HistogramTester histogram_;
87*6777b538SAndroid Build Coastguard Worker };
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(HttpssvcMetricsTestSimple,
90*6777b538SAndroid Build Coastguard Worker                          HttpssvcMetricsTest,
91*6777b538SAndroid Build Coastguard Worker                          testing::Bool()  // Querying over DoH or Do53.
92*6777b538SAndroid Build Coastguard Worker );
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker // Only record metrics for a non-HTTPS query.
TEST_P(HttpssvcMetricsTest,AddressAndExperimentalMissing)95*6777b538SAndroid Build Coastguard Worker TEST_P(HttpssvcMetricsTest, AddressAndExperimentalMissing) {
96*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTime = base::Milliseconds(10);
97*6777b538SAndroid Build Coastguard Worker   auto metrics = std::make_optional<HttpssvcMetrics>(secure_);
98*6777b538SAndroid Build Coastguard Worker   metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
99*6777b538SAndroid Build Coastguard Worker   metrics.reset();  // Record the metrics to UMA.
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   VerifyAddressResolveTimeMetric();
102*6777b538SAndroid Build Coastguard Worker   VerifyHttpsMetricsForExpectNoerror();
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker 
TEST_P(HttpssvcMetricsTest,AddressAndHttpsParsable)105*6777b538SAndroid Build Coastguard Worker TEST_P(HttpssvcMetricsTest, AddressAndHttpsParsable) {
106*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTime = base::Milliseconds(10);
107*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
108*6777b538SAndroid Build Coastguard Worker   auto metrics = std::make_optional<HttpssvcMetrics>(secure_);
109*6777b538SAndroid Build Coastguard Worker   metrics->SaveForHttps(HttpssvcDnsRcode::kNoError, {true}, kResolveTimeHttps);
110*6777b538SAndroid Build Coastguard Worker   metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
111*6777b538SAndroid Build Coastguard Worker   metrics.reset();  // Record the metrics to UMA.
112*6777b538SAndroid Build Coastguard Worker 
113*6777b538SAndroid Build Coastguard Worker   VerifyAddressResolveTimeMetric({kResolveTime} /* expect_noerror_time */);
114*6777b538SAndroid Build Coastguard Worker   VerifyHttpsMetricsForExpectNoerror(
115*6777b538SAndroid Build Coastguard Worker       {HttpssvcDnsRcode::kNoError} /* rcode */, {true} /* parsable */,
116*6777b538SAndroid Build Coastguard Worker       std::nullopt /* record_with_error */,
117*6777b538SAndroid Build Coastguard Worker       {kResolveTimeHttps} /* resolve_time_https */,
118*6777b538SAndroid Build Coastguard Worker       {15} /* resolve_time_ratio */);
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker // This test simulates an HTTPS response that includes no HTTPS records,
122*6777b538SAndroid Build Coastguard Worker // but does have an error value for the RCODE.
TEST_P(HttpssvcMetricsTest,AddressAndHttpsMissingWithRcode)123*6777b538SAndroid Build Coastguard Worker TEST_P(HttpssvcMetricsTest, AddressAndHttpsMissingWithRcode) {
124*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTime = base::Milliseconds(10);
125*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker   auto metrics = std::make_optional<HttpssvcMetrics>(secure_);
128*6777b538SAndroid Build Coastguard Worker   metrics->SaveForHttps(HttpssvcDnsRcode::kNxDomain, {}, kResolveTimeHttps);
129*6777b538SAndroid Build Coastguard Worker   metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
130*6777b538SAndroid Build Coastguard Worker   metrics.reset();  // Record the metrics to UMA.
131*6777b538SAndroid Build Coastguard Worker 
132*6777b538SAndroid Build Coastguard Worker   VerifyAddressResolveTimeMetric({kResolveTime} /* expect_noerror_time */);
133*6777b538SAndroid Build Coastguard Worker   VerifyHttpsMetricsForExpectNoerror(
134*6777b538SAndroid Build Coastguard Worker       {HttpssvcDnsRcode::kNxDomain} /* rcode */, std::nullopt /* parsable */,
135*6777b538SAndroid Build Coastguard Worker       std::nullopt /* record_with_error */,
136*6777b538SAndroid Build Coastguard Worker       {kResolveTimeHttps} /* resolve_time_https */,
137*6777b538SAndroid Build Coastguard Worker       {15} /* resolve_time_ratio */);
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker // This test simulates an HTTPS response that includes a parsable HTTPS
141*6777b538SAndroid Build Coastguard Worker // record, but also has an error RCODE.
TEST_P(HttpssvcMetricsTest,AddressAndHttpsParsableWithRcode)142*6777b538SAndroid Build Coastguard Worker TEST_P(HttpssvcMetricsTest, AddressAndHttpsParsableWithRcode) {
143*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTime = base::Milliseconds(10);
144*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker   auto metrics = std::make_optional<HttpssvcMetrics>(secure_);
147*6777b538SAndroid Build Coastguard Worker   metrics->SaveForHttps(HttpssvcDnsRcode::kNxDomain, {true}, kResolveTimeHttps);
148*6777b538SAndroid Build Coastguard Worker   metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
149*6777b538SAndroid Build Coastguard Worker   metrics.reset();  // Record the metrics to UMA.
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker   VerifyAddressResolveTimeMetric({kResolveTime} /* expect_noerror_time */);
152*6777b538SAndroid Build Coastguard Worker   VerifyHttpsMetricsForExpectNoerror(
153*6777b538SAndroid Build Coastguard Worker       {HttpssvcDnsRcode::kNxDomain} /* rcode */,
154*6777b538SAndroid Build Coastguard Worker       // "parsable" metric is omitted because the RCODE is not NOERROR.
155*6777b538SAndroid Build Coastguard Worker       std::nullopt /* parsable */, {true} /* record_with_error */,
156*6777b538SAndroid Build Coastguard Worker       {kResolveTimeHttps} /* resolve_time_https */,
157*6777b538SAndroid Build Coastguard Worker       {15} /* resolve_time_ratio */);
158*6777b538SAndroid Build Coastguard Worker }
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker // This test simulates an HTTPS response that includes a mangled HTTPS
161*6777b538SAndroid Build Coastguard Worker // record *and* has an error RCODE.
TEST_P(HttpssvcMetricsTest,AddressAndHttpsMangledWithRcode)162*6777b538SAndroid Build Coastguard Worker TEST_P(HttpssvcMetricsTest, AddressAndHttpsMangledWithRcode) {
163*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTime = base::Milliseconds(10);
164*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
165*6777b538SAndroid Build Coastguard Worker   auto metrics = std::make_optional<HttpssvcMetrics>(secure_);
166*6777b538SAndroid Build Coastguard Worker   metrics->SaveForHttps(HttpssvcDnsRcode::kNxDomain, {false},
167*6777b538SAndroid Build Coastguard Worker                         kResolveTimeHttps);
168*6777b538SAndroid Build Coastguard Worker   metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
169*6777b538SAndroid Build Coastguard Worker   metrics.reset();  // Record the metrics to UMA.
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker   VerifyAddressResolveTimeMetric({kResolveTime} /* expect_noerror_time */);
172*6777b538SAndroid Build Coastguard Worker   VerifyHttpsMetricsForExpectNoerror(
173*6777b538SAndroid Build Coastguard Worker       {HttpssvcDnsRcode::kNxDomain} /* rcode */,
174*6777b538SAndroid Build Coastguard Worker       // "parsable" metric is omitted because the RCODE is not NOERROR.
175*6777b538SAndroid Build Coastguard Worker       std::nullopt /* parsable */, {true} /* record_with_error */,
176*6777b538SAndroid Build Coastguard Worker       {kResolveTimeHttps} /* resolve_time_https */,
177*6777b538SAndroid Build Coastguard Worker       {15} /* resolve_time_ratio */);
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker // This test simulates successful address queries and an HTTPS query that
181*6777b538SAndroid Build Coastguard Worker // timed out.
TEST_P(HttpssvcMetricsTest,AddressAndHttpsTimedOut)182*6777b538SAndroid Build Coastguard Worker TEST_P(HttpssvcMetricsTest, AddressAndHttpsTimedOut) {
183*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTime = base::Milliseconds(10);
184*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
185*6777b538SAndroid Build Coastguard Worker   auto metrics = std::make_optional<HttpssvcMetrics>(secure_);
186*6777b538SAndroid Build Coastguard Worker   metrics->SaveForHttps(HttpssvcDnsRcode::kTimedOut, {}, kResolveTimeHttps);
187*6777b538SAndroid Build Coastguard Worker   metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
188*6777b538SAndroid Build Coastguard Worker   metrics.reset();  // Record the metrics to UMA.
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker   VerifyAddressResolveTimeMetric({kResolveTime} /* expect_noerror_time */);
191*6777b538SAndroid Build Coastguard Worker   VerifyHttpsMetricsForExpectNoerror(
192*6777b538SAndroid Build Coastguard Worker       {HttpssvcDnsRcode::kTimedOut} /* rcode */,
193*6777b538SAndroid Build Coastguard Worker       // "parsable" metric is omitted because the RCODE is not NOERROR.
194*6777b538SAndroid Build Coastguard Worker       std::nullopt /* parsable */, std::nullopt /* record_with_error */,
195*6777b538SAndroid Build Coastguard Worker       {kResolveTimeHttps} /* resolve_time_https */,
196*6777b538SAndroid Build Coastguard Worker       {15} /* resolve_time_ratio */);
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker 
199*6777b538SAndroid Build Coastguard Worker }  // namespace net
200