httpssvc_metrics_unittest.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/dns/httpssvc_metrics.h"
  5. #include <string>
  6. #include <tuple>
  7. #include "base/feature_list.h"
  8. #include "base/strings/strcat.h"
  9. #include "base/strings/string_number_conversions.h"
  10. #include "base/strings/string_piece.h"
  11. #include "base/strings/string_util.h"
  12. #include "base/test/metrics/histogram_tester.h"
  13. #include "base/test/scoped_feature_list.h"
  14. #include "net/base/features.h"
  15. #include "testing/gtest/include/gtest/gtest.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. namespace net {
  18. // int: number of domains
  19. // bool: extra leading comma
  20. // bool: extra trailing comma
  21. using DomainListQuirksTuple = std::tuple<int, bool, bool>;
  22. // bool: DnsHttpssvc feature is enabled
  23. // bool: DnsHttpssvcUseIntegrity feature param
  24. // bool: DnsHttpssvcUseHttpssvc feature param
  25. // bool: DnsHttpssvcControlDomainWildcard feature param
  26. using HttpssvcFeatureTuple = std::tuple<bool, bool, bool, bool>;
  27. // DomainListQuirksTuple: quirks for the experimental domain list.
  28. // DomainListQuirksTuple: quirks for the control domain list.
  29. // HttpssvcFeatureTuple: config for the whole DnsHttpssvc feature.
  30. using ParsingTestParamTuple = std::
  31. tuple<DomainListQuirksTuple, DomainListQuirksTuple, HttpssvcFeatureTuple>;
  32. // bool: whether we are querying for an experimental domain or a control domain
  33. // HttpssvcFeatureTuple: config for the whole DnsHttpssvc feature.
  34. using MetricsTestParamTuple = std::tuple<bool, HttpssvcFeatureTuple>;
  35. // Create a comma-separated list of |domains| with the given |quirks|.
  36. std::string FlattenDomainList(const std::vector<std::string>& domains,
  37. DomainListQuirksTuple quirks) {
  38. auto [num_domains, leading_comma, trailing_comma] = quirks;
  39. CHECK_EQ(static_cast<size_t>(num_domains), domains.size());
  40. std::string flattened = base::JoinString(domains, ",");
  41. if (leading_comma)
  42. flattened.insert(flattened.begin(), ',');
  43. if (trailing_comma)
  44. flattened.push_back(',');
  45. return flattened;
  46. }
  47. // Intermediate representation constructed from test parameters.
  48. struct HttpssvcFeatureConfig {
  49. HttpssvcFeatureConfig() = default;
  50. explicit HttpssvcFeatureConfig(const HttpssvcFeatureTuple& feature_tuple,
  51. base::StringPiece experiment_domains,
  52. base::StringPiece control_domains)
  53. : experiment_domains(experiment_domains),
  54. control_domains(control_domains) {
  55. std::tie(enabled, use_integrity, use_httpssvc, control_domain_wildcard) =
  56. feature_tuple;
  57. }
  58. void Apply(base::test::ScopedFeatureList* scoped_feature_list) const {
  59. if (!enabled) {
  60. scoped_feature_list->InitAndDisableFeature(features::kDnsHttpssvc);
  61. return;
  62. }
  63. auto stringify = [](bool b) -> std::string { return b ? "true" : "false"; };
  64. scoped_feature_list->InitAndEnableFeatureWithParameters(
  65. features::kDnsHttpssvc,
  66. {
  67. {"DnsHttpssvcUseHttpssvc", stringify(use_httpssvc)},
  68. {"DnsHttpssvcUseIntegrity", stringify(use_integrity)},
  69. {"DnsHttpssvcEnableQueryOverInsecure", "false"},
  70. {"DnsHttpssvcExperimentDomains", experiment_domains},
  71. {"DnsHttpssvcControlDomains", control_domains},
  72. {"DnsHttpssvcControlDomainWildcard",
  73. stringify(control_domain_wildcard)},
  74. });
  75. }
  76. bool enabled = false;
  77. bool use_integrity = false;
  78. bool use_httpssvc = false;
  79. bool control_domain_wildcard = false;
  80. std::string experiment_domains;
  81. std::string control_domains;
  82. };
  83. std::vector<std::string> GenerateDomainList(base::StringPiece label, int n) {
  84. std::vector<std::string> domains;
  85. for (int i = 0; i < n; i++) {
  86. domains.push_back(base::StrCat(
  87. {"domain", base::NumberToString(i), ".", label, ".example"}));
  88. }
  89. return domains;
  90. }
  91. // Base for testing domain list parsing functions in
  92. // net::features::dns_httpssvc_experiment.
  93. class HttpssvcDomainParsingTest
  94. : public ::testing::TestWithParam<ParsingTestParamTuple> {
  95. public:
  96. void SetUp() override {
  97. auto [domain_quirks_experimental, domain_quirks_control, httpssvc_feature] =
  98. GetParam();
  99. expected_experiment_domains_ = GenerateDomainList(
  100. "experiment", std::get<0>(domain_quirks_experimental));
  101. expected_control_domains_ =
  102. GenerateDomainList("control", std::get<0>(domain_quirks_control));
  103. config_ = HttpssvcFeatureConfig(
  104. httpssvc_feature,
  105. FlattenDomainList(expected_experiment_domains_,
  106. domain_quirks_experimental),
  107. FlattenDomainList(expected_control_domains_, domain_quirks_control));
  108. config_.Apply(&scoped_feature_list_);
  109. }
  110. const HttpssvcFeatureConfig& config() { return config_; }
  111. protected:
  112. // The expected results of parsing the comma-separated domain lists in
  113. // |experiment_domains| and |control_domains|, respectively.
  114. std::vector<std::string> expected_experiment_domains_;
  115. std::vector<std::string> expected_control_domains_;
  116. private:
  117. HttpssvcFeatureConfig config_;
  118. base::test::ScopedFeatureList scoped_feature_list_;
  119. };
  120. // This instantiation tests the domain list parser against various quirks,
  121. // e.g. leading comma.
  122. INSTANTIATE_TEST_SUITE_P(
  123. HttpssvcMetricsTestDomainParsing,
  124. HttpssvcDomainParsingTest,
  125. testing::Combine(
  126. // DomainListQuirksTuple for experimental domains. To fight back
  127. // combinatorial explosion of tests, this tuple is pared down more than
  128. // the one for control domains. This should not significantly hurt test
  129. // coverage because |IsExperimentDomain| and |IsControlDomain| rely on a
  130. // shared helper function.
  131. testing::Combine(testing::Values(0, 1),
  132. testing::Values(false),
  133. testing::Values(false)),
  134. // DomainListQuirksTuple for control domains.
  135. testing::Combine(testing::Range(0, 3),
  136. testing::Bool(),
  137. testing::Bool()),
  138. // HttpssvcFeatureTuple
  139. testing::Combine(
  140. testing::Bool() /* DnsHttpssvc feature enabled? */,
  141. testing::Bool() /* DnsHttpssvcUseIntegrity */,
  142. testing::Bool() /* DnsHttpssvcUseHttpssvc */,
  143. testing::Values(false) /* DnsHttpssvcControlDomainWildcard */)));
  144. // Base for testing the metrics collection code in |HttpssvcMetrics|.
  145. class HttpssvcMetricsTest
  146. : public ::testing::TestWithParam<std::tuple<bool, bool>> {
  147. public:
  148. void SetUp() override {
  149. std::tie(secure_, querying_experimental_) = GetParam();
  150. config_ = HttpssvcFeatureConfig(
  151. {true /* enabled */, true /* use_integrity */, true /* use_httpssvc */,
  152. false /* control_domain_wildcard */},
  153. "", "");
  154. config_.Apply(&scoped_feature_list_);
  155. }
  156. std::string BuildMetricNamePrefix(base::StringPiece record_type_str,
  157. base::StringPiece expect_str) const {
  158. return base::StrCat({"Net.DNS.HTTPSSVC.", record_type_str, ".",
  159. secure_ ? "Secure." : "Insecure.", expect_str, "."});
  160. }
  161. template <typename T>
  162. void ExpectSample(base::StringPiece name, absl::optional<T> sample) const {
  163. if (sample)
  164. histo().ExpectUniqueSample(name, *sample, 1);
  165. else
  166. histo().ExpectTotalCount(name, 0);
  167. }
  168. void ExpectSample(base::StringPiece name,
  169. absl::optional<base::TimeDelta> sample) const {
  170. absl::optional<int64_t> sample_ms;
  171. if (sample)
  172. sample_ms = {sample->InMilliseconds()};
  173. ExpectSample<int64_t>(name, sample_ms);
  174. }
  175. void VerifyAddressResolveTimeMetric(
  176. absl::optional<base::TimeDelta> expect_intact_time = absl::nullopt,
  177. absl::optional<base::TimeDelta> expect_noerror_time = absl::nullopt) {
  178. const std::string kExpectIntact =
  179. base::StrCat({BuildMetricNamePrefix("RecordHttps", "ExpectIntact"),
  180. "ResolveTimeAddress"});
  181. const std::string kExpectNoerror =
  182. base::StrCat({BuildMetricNamePrefix("RecordHttps", "ExpectNoerror"),
  183. "ResolveTimeAddress"});
  184. ExpectSample(kExpectIntact, expect_intact_time);
  185. ExpectSample(kExpectNoerror, expect_noerror_time);
  186. }
  187. void VerifyIntegrityMetricsForExpectIntact(
  188. absl::optional<HttpssvcDnsRcode> rcode,
  189. absl::optional<bool> integrity,
  190. absl::optional<bool> record_with_error,
  191. absl::optional<base::TimeDelta> resolve_time_integrity,
  192. absl::optional<int> resolve_time_ratio) const {
  193. const std::string kPrefix =
  194. BuildMetricNamePrefix("RecordIntegrity", "ExpectIntact");
  195. const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"});
  196. const std::string kMetricIntegrity = base::StrCat({kPrefix, "Integrity"});
  197. const std::string kMetricRecordWithError =
  198. base::StrCat({kPrefix, "RecordWithError"});
  199. const std::string kMetricResolveTimeExperimental =
  200. base::StrCat({kPrefix, "ResolveTimeExperimental"});
  201. const std::string kMetricResolveTimeRatio =
  202. base::StrCat({kPrefix, "ResolveTimeRatio"});
  203. ExpectSample(kMetricDnsRcode, rcode);
  204. ExpectSample(kMetricIntegrity, integrity);
  205. ExpectSample(kMetricRecordWithError, record_with_error);
  206. ExpectSample(kMetricResolveTimeExperimental, resolve_time_integrity);
  207. ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio);
  208. }
  209. void VerifyHttpsMetricsForExpectIntact(
  210. absl::optional<HttpssvcDnsRcode> rcode = absl::nullopt,
  211. absl::optional<bool> parsable = absl::nullopt,
  212. absl::optional<bool> record_with_error = absl::nullopt,
  213. absl::optional<base::TimeDelta> resolve_time_https = absl::nullopt,
  214. absl::optional<int> resolve_time_ratio = absl::nullopt) const {
  215. const std::string kPrefix =
  216. BuildMetricNamePrefix("RecordHttps", "ExpectIntact");
  217. const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"});
  218. const std::string kMetricParsable = base::StrCat({kPrefix, "Parsable"});
  219. const std::string kMetricRecordWithError =
  220. base::StrCat({kPrefix, "RecordWithError"});
  221. const std::string kMetricResolveTimeExperimental =
  222. base::StrCat({kPrefix, "ResolveTimeExperimental"});
  223. const std::string kMetricResolveTimeRatio =
  224. base::StrCat({kPrefix, "ResolveTimeRatio"});
  225. ExpectSample(kMetricDnsRcode, rcode);
  226. ExpectSample(kMetricParsable, parsable);
  227. ExpectSample(kMetricRecordWithError, record_with_error);
  228. ExpectSample(kMetricResolveTimeExperimental, resolve_time_https);
  229. ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio);
  230. }
  231. void VerifyIntegrityMetricsForExpectNoerror(
  232. absl::optional<HttpssvcDnsRcode> rcode,
  233. absl::optional<int> record_received,
  234. absl::optional<base::TimeDelta> resolve_time_integrity,
  235. absl::optional<int> resolve_time_ratio) const {
  236. const std::string kPrefix =
  237. BuildMetricNamePrefix("RecordIntegrity", "ExpectNoerror");
  238. const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"});
  239. const std::string kMetricRecordReceived =
  240. base::StrCat({kPrefix, "RecordReceived"});
  241. const std::string kMetricResolveTimeExperimental =
  242. base::StrCat({kPrefix, "ResolveTimeExperimental"});
  243. const std::string kMetricResolveTimeRatio =
  244. base::StrCat({kPrefix, "ResolveTimeRatio"});
  245. ExpectSample(kMetricDnsRcode, rcode);
  246. ExpectSample(kMetricRecordReceived, record_received);
  247. ExpectSample(kMetricResolveTimeExperimental, resolve_time_integrity);
  248. ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio);
  249. }
  250. void VerifyHttpsMetricsForExpectNoerror(
  251. absl::optional<HttpssvcDnsRcode> rcode = absl::nullopt,
  252. absl::optional<bool> parsable = absl::nullopt,
  253. absl::optional<bool> record_with_error = absl::nullopt,
  254. absl::optional<base::TimeDelta> resolve_time_https = absl::nullopt,
  255. absl::optional<int> resolve_time_ratio = absl::nullopt) const {
  256. const std::string kPrefix =
  257. BuildMetricNamePrefix("RecordHttps", "ExpectNoerror");
  258. const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"});
  259. const std::string kMetricParsable = base::StrCat({kPrefix, "Parsable"});
  260. const std::string kMetricRecordWithError =
  261. base::StrCat({kPrefix, "RecordWithError"});
  262. const std::string kMetricResolveTimeExperimental =
  263. base::StrCat({kPrefix, "ResolveTimeExperimental"});
  264. const std::string kMetricResolveTimeRatio =
  265. base::StrCat({kPrefix, "ResolveTimeRatio"});
  266. ExpectSample(kMetricDnsRcode, rcode);
  267. ExpectSample(kMetricParsable, parsable);
  268. ExpectSample(kMetricRecordWithError, record_with_error);
  269. ExpectSample(kMetricResolveTimeExperimental, resolve_time_https);
  270. ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio);
  271. }
  272. void VerifyIntegrityMetricsForExpectIntact() {
  273. VerifyIntegrityMetricsForExpectIntact(absl::nullopt, absl::nullopt,
  274. absl::nullopt, absl::nullopt,
  275. absl::nullopt);
  276. }
  277. void VerifyIntegrityMetricsForExpectNoerror() {
  278. VerifyIntegrityMetricsForExpectNoerror(absl::nullopt, absl::nullopt,
  279. absl::nullopt, absl::nullopt);
  280. }
  281. const base::HistogramTester& histo() const { return histogram_; }
  282. const HttpssvcFeatureConfig& config() const { return config_; }
  283. protected:
  284. bool secure_;
  285. bool querying_experimental_;
  286. private:
  287. HttpssvcFeatureConfig config_;
  288. base::test::ScopedFeatureList scoped_feature_list_;
  289. base::HistogramTester histogram_;
  290. };
  291. // This instantiation focuses on whether the correct metrics are recorded. The
  292. // domain list parser is already tested against encoding quirks in
  293. // |HttpssvcMetricsTestDomainParsing|, so we fix the quirks at false.
  294. INSTANTIATE_TEST_SUITE_P(
  295. HttpssvcMetricsTestSimple,
  296. HttpssvcMetricsTest,
  297. testing::Combine(
  298. testing::Bool(), // Querying over DoH or Do53.
  299. testing::Bool() // Whether we are querying an experimental domain.
  300. ));
  301. TEST_P(HttpssvcDomainParsingTest, ParseFeatureParamIntegrityDomains) {
  302. HttpssvcExperimentDomainCache domain_cache;
  303. const std::string kReservedDomain = "neither.example";
  304. EXPECT_FALSE(domain_cache.IsExperimental(kReservedDomain));
  305. EXPECT_EQ(domain_cache.IsControl(kReservedDomain),
  306. config().enabled && config().control_domain_wildcard);
  307. // If |config().use_integrity| is true, then we expect all domains in
  308. // |expected_experiment_domains_| to be experimental (same goes for
  309. // control domains). Otherwise, no domain should be considered experimental or
  310. // control.
  311. if (!config().enabled) {
  312. // When the HTTPSSVC feature is disabled, no domain should be considered
  313. // experimental or control.
  314. for (const std::string& experiment_domain : expected_experiment_domains_) {
  315. EXPECT_FALSE(domain_cache.IsExperimental(experiment_domain));
  316. EXPECT_FALSE(domain_cache.IsControl(experiment_domain));
  317. }
  318. for (const std::string& control_domain : expected_control_domains_) {
  319. EXPECT_FALSE(domain_cache.IsExperimental(control_domain));
  320. EXPECT_FALSE(domain_cache.IsControl(control_domain));
  321. }
  322. } else if (config().use_integrity || config().use_httpssvc) {
  323. for (const std::string& experiment_domain : expected_experiment_domains_) {
  324. EXPECT_TRUE(domain_cache.IsExperimental(experiment_domain));
  325. EXPECT_FALSE(domain_cache.IsControl(experiment_domain));
  326. }
  327. for (const std::string& control_domain : expected_control_domains_) {
  328. EXPECT_FALSE(domain_cache.IsExperimental(control_domain));
  329. EXPECT_TRUE(domain_cache.IsControl(control_domain));
  330. }
  331. return;
  332. }
  333. }
  334. // Only record metrics for a non-integrity query.
  335. TEST_P(HttpssvcMetricsTest, AddressAndExperimentalMissing) {
  336. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  337. auto metrics =
  338. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  339. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  340. metrics.reset(); // Record the metrics to UMA.
  341. VerifyAddressResolveTimeMetric();
  342. VerifyIntegrityMetricsForExpectIntact();
  343. VerifyHttpsMetricsForExpectIntact();
  344. VerifyIntegrityMetricsForExpectNoerror();
  345. VerifyHttpsMetricsForExpectNoerror();
  346. }
  347. TEST_P(HttpssvcMetricsTest, AddressAndIntegrityIntact) {
  348. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  349. const base::TimeDelta kResolveTimeIntegrity = base::Milliseconds(15);
  350. auto metrics =
  351. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  352. metrics->SaveForIntegrity(HttpssvcDnsRcode::kNoError, {true},
  353. kResolveTimeIntegrity);
  354. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  355. metrics.reset(); // Record the metrics to UMA.
  356. VerifyHttpsMetricsForExpectIntact();
  357. VerifyHttpsMetricsForExpectNoerror();
  358. if (querying_experimental_) {
  359. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  360. VerifyIntegrityMetricsForExpectIntact(
  361. absl::nullopt /* rcode */, {true} /* integrity */,
  362. absl::nullopt /* record_with_error */,
  363. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  364. {15} /* resolve_time_ratio */);
  365. VerifyIntegrityMetricsForExpectNoerror();
  366. return;
  367. }
  368. VerifyIntegrityMetricsForExpectIntact();
  369. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  370. {kResolveTime} /* expect_noerror_time */);
  371. VerifyIntegrityMetricsForExpectNoerror(
  372. {HttpssvcDnsRcode::kNoError} /* rcode */, {1} /* record_received */,
  373. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  374. {15} /* resolve_time_ratio */);
  375. }
  376. TEST_P(HttpssvcMetricsTest, AddressAndHttpsParsable) {
  377. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  378. const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
  379. auto metrics =
  380. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  381. metrics->SaveForHttps(HttpssvcDnsRcode::kNoError, {true}, kResolveTimeHttps);
  382. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  383. metrics.reset(); // Record the metrics to UMA.
  384. VerifyIntegrityMetricsForExpectIntact();
  385. VerifyIntegrityMetricsForExpectNoerror();
  386. if (querying_experimental_) {
  387. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  388. VerifyHttpsMetricsForExpectIntact(
  389. absl::nullopt /* rcode */, {true} /* parsable */,
  390. absl::nullopt /* record_with_error */,
  391. {kResolveTimeHttps} /* resolve_time_https */,
  392. {15} /* resolve_time_ratio */);
  393. VerifyHttpsMetricsForExpectNoerror();
  394. return;
  395. }
  396. VerifyHttpsMetricsForExpectIntact();
  397. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  398. {kResolveTime} /* expect_noerror_time */);
  399. VerifyHttpsMetricsForExpectNoerror(
  400. {HttpssvcDnsRcode::kNoError} /* rcode */, {true} /* parsable */,
  401. absl::nullopt /* record_with_error */,
  402. {kResolveTimeHttps} /* resolve_time_https */,
  403. {15} /* resolve_time_ratio */);
  404. }
  405. TEST_P(HttpssvcMetricsTest, AddressAndIntegrityIntactAndHttpsParsable) {
  406. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  407. const base::TimeDelta kResolveTimeIntegrity = base::Milliseconds(15);
  408. const base::TimeDelta kResolveTimeHttps = base::Milliseconds(20);
  409. auto metrics =
  410. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  411. metrics->SaveForIntegrity(HttpssvcDnsRcode::kNoError, {true},
  412. kResolveTimeIntegrity);
  413. metrics->SaveForHttps(HttpssvcDnsRcode::kNoError, {true}, kResolveTimeHttps);
  414. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  415. metrics.reset(); // Record the metrics to UMA.
  416. if (querying_experimental_) {
  417. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  418. VerifyIntegrityMetricsForExpectIntact(
  419. absl::nullopt /* rcode */, {true} /* integrity */,
  420. absl::nullopt /* record_with_error */,
  421. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  422. {15} /* resolve_time_ratio */);
  423. VerifyHttpsMetricsForExpectIntact(
  424. absl::nullopt /* rcode */, {true} /* parsable */,
  425. absl::nullopt /* record_with_error */,
  426. {kResolveTimeHttps} /* resolve_time_https */,
  427. {20} /* resolve_time_ratio */);
  428. VerifyIntegrityMetricsForExpectNoerror();
  429. VerifyHttpsMetricsForExpectNoerror();
  430. return;
  431. }
  432. VerifyIntegrityMetricsForExpectIntact();
  433. VerifyHttpsMetricsForExpectIntact();
  434. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  435. {kResolveTime} /* expect_noerror_time */);
  436. VerifyIntegrityMetricsForExpectNoerror(
  437. {HttpssvcDnsRcode::kNoError} /* rcode */, {1} /* record_received */,
  438. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  439. {15} /* resolve_time_ratio */);
  440. VerifyHttpsMetricsForExpectNoerror(
  441. {HttpssvcDnsRcode::kNoError} /* rcode */, {true} /* parsable */,
  442. absl::nullopt /* record_with_error */,
  443. {kResolveTimeHttps} /* resolve_time_https */,
  444. {20} /* resolve_time_ratio */);
  445. }
  446. // This test simulates an INTEGRITY response that includes no INTEGRITY records,
  447. // but does have an error value for the RCODE.
  448. TEST_P(HttpssvcMetricsTest, AddressAndIntegrityMissingWithRcode) {
  449. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  450. const base::TimeDelta kResolveTimeIntegrity = base::Milliseconds(15);
  451. auto metrics =
  452. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  453. metrics->SaveForIntegrity(HttpssvcDnsRcode::kNxDomain, {},
  454. kResolveTimeIntegrity);
  455. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  456. metrics.reset(); // Record the metrics to UMA.
  457. VerifyHttpsMetricsForExpectIntact();
  458. VerifyHttpsMetricsForExpectNoerror();
  459. if (querying_experimental_) {
  460. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  461. VerifyIntegrityMetricsForExpectIntact(
  462. {HttpssvcDnsRcode::kNxDomain} /* rcode */,
  463. absl::nullopt /* integrity */, absl::nullopt /* record_with_error */,
  464. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  465. {15} /* resolve_time_ratio */);
  466. VerifyIntegrityMetricsForExpectNoerror();
  467. return;
  468. }
  469. VerifyIntegrityMetricsForExpectIntact();
  470. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  471. {kResolveTime} /* expect_noerror_time */);
  472. VerifyIntegrityMetricsForExpectNoerror(
  473. {HttpssvcDnsRcode::kNxDomain} /* rcode */,
  474. absl::nullopt /* record_received */,
  475. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  476. {15} /* resolve_time_ratio */);
  477. }
  478. // This test simulates an HTTPS response that includes no HTTPS records,
  479. // but does have an error value for the RCODE.
  480. TEST_P(HttpssvcMetricsTest, AddressAndHttpsMissingWithRcode) {
  481. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  482. const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
  483. auto metrics =
  484. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  485. metrics->SaveForHttps(HttpssvcDnsRcode::kNxDomain, {}, kResolveTimeHttps);
  486. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  487. metrics.reset(); // Record the metrics to UMA.
  488. VerifyIntegrityMetricsForExpectIntact();
  489. VerifyIntegrityMetricsForExpectNoerror();
  490. if (querying_experimental_) {
  491. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  492. VerifyHttpsMetricsForExpectIntact(
  493. {HttpssvcDnsRcode::kNxDomain} /* rcode */, absl::nullopt /* parsable */,
  494. absl::nullopt /* record_with_error */,
  495. {kResolveTimeHttps} /* resolve_time_https */,
  496. {15} /* resolve_time_ratio */);
  497. VerifyHttpsMetricsForExpectNoerror();
  498. return;
  499. }
  500. VerifyHttpsMetricsForExpectIntact();
  501. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  502. {kResolveTime} /* expect_noerror_time */);
  503. VerifyHttpsMetricsForExpectNoerror(
  504. {HttpssvcDnsRcode::kNxDomain} /* rcode */, absl::nullopt /* parsable */,
  505. absl::nullopt /* record_with_error */,
  506. {kResolveTimeHttps} /* resolve_time_https */,
  507. {15} /* resolve_time_ratio */);
  508. }
  509. // This test simulates an INTEGRITY response that includes an intact INTEGRITY
  510. // record, but also has an error RCODE.
  511. TEST_P(HttpssvcMetricsTest, AddressAndIntegrityIntactWithRcode) {
  512. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  513. const base::TimeDelta kResolveTimeIntegrity = base::Milliseconds(15);
  514. auto metrics =
  515. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  516. metrics->SaveForIntegrity(HttpssvcDnsRcode::kNxDomain, {true},
  517. kResolveTimeIntegrity);
  518. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  519. metrics.reset(); // Record the metrics to UMA.
  520. VerifyHttpsMetricsForExpectIntact();
  521. VerifyHttpsMetricsForExpectNoerror();
  522. if (querying_experimental_) {
  523. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  524. VerifyIntegrityMetricsForExpectIntact(
  525. // "DnsRcode" metric is omitted because we received an INTEGRITY record.
  526. absl::nullopt /* rcode */,
  527. // "Integrity" metric is omitted because the RCODE is not NOERROR.
  528. absl::nullopt /* integrity */, {true} /* record_with_error */,
  529. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  530. {15} /* resolve_time_ratio */);
  531. VerifyIntegrityMetricsForExpectNoerror();
  532. return;
  533. }
  534. VerifyIntegrityMetricsForExpectIntact();
  535. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  536. {kResolveTime} /* expect_noerror_time */);
  537. VerifyIntegrityMetricsForExpectNoerror(
  538. {HttpssvcDnsRcode::kNxDomain} /* rcode */, {true} /* record_received */,
  539. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  540. {15} /* resolve_time_ratio */);
  541. }
  542. // This test simulates an HTTPS response that includes a parsable HTTPS
  543. // record, but also has an error RCODE.
  544. TEST_P(HttpssvcMetricsTest, AddressAndHttpsParsableWithRcode) {
  545. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  546. const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
  547. auto metrics =
  548. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  549. metrics->SaveForHttps(HttpssvcDnsRcode::kNxDomain, {true}, kResolveTimeHttps);
  550. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  551. metrics.reset(); // Record the metrics to UMA.
  552. VerifyIntegrityMetricsForExpectIntact();
  553. VerifyIntegrityMetricsForExpectNoerror();
  554. if (querying_experimental_) {
  555. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  556. VerifyHttpsMetricsForExpectIntact(
  557. // "DnsRcode" metric is omitted because we received an HTTPS record.
  558. absl::nullopt /* rcode */,
  559. // "parsable" metric is omitted because the RCODE is not NOERROR.
  560. absl::nullopt /* parsable */, {true} /* record_with_error */,
  561. {kResolveTimeHttps} /* resolve_time_https */,
  562. {15} /* resolve_time_ratio */);
  563. VerifyHttpsMetricsForExpectNoerror();
  564. return;
  565. }
  566. VerifyHttpsMetricsForExpectIntact();
  567. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  568. {kResolveTime} /* expect_noerror_time */);
  569. VerifyHttpsMetricsForExpectNoerror(
  570. {HttpssvcDnsRcode::kNxDomain} /* rcode */,
  571. // "parsable" metric is omitted because the RCODE is not NOERROR.
  572. absl::nullopt /* parsable */, {true} /* record_with_error */,
  573. {kResolveTimeHttps} /* resolve_time_https */,
  574. {15} /* resolve_time_ratio */);
  575. }
  576. // This test simulates an INTEGRITY response that includes a mangled INTEGRITY
  577. // record *and* has an error RCODE.
  578. TEST_P(HttpssvcMetricsTest, AddressAndIntegrityMangledWithRcode) {
  579. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  580. const base::TimeDelta kResolveTimeIntegrity = base::Milliseconds(15);
  581. auto metrics =
  582. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  583. metrics->SaveForIntegrity(HttpssvcDnsRcode::kNxDomain, {false},
  584. kResolveTimeIntegrity);
  585. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  586. metrics.reset(); // Record the metrics to UMA.
  587. VerifyHttpsMetricsForExpectIntact();
  588. VerifyHttpsMetricsForExpectNoerror();
  589. if (querying_experimental_) {
  590. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  591. VerifyIntegrityMetricsForExpectIntact(
  592. // "DnsRcode" metric is omitted because we received an INTEGRITY record.
  593. absl::nullopt /* rcode */,
  594. // "Integrity" metric is omitted because the RCODE is not NOERROR.
  595. absl::nullopt /* integrity */, {true} /* record_with_error */,
  596. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  597. {15} /* resolve_time_ratio */);
  598. VerifyIntegrityMetricsForExpectNoerror();
  599. return;
  600. }
  601. VerifyIntegrityMetricsForExpectIntact();
  602. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  603. {kResolveTime} /* expect_noerror_time */);
  604. VerifyIntegrityMetricsForExpectNoerror(
  605. {HttpssvcDnsRcode::kNxDomain} /* rcode */, {true} /* record_received */,
  606. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  607. {15} /* resolve_time_ratio */);
  608. }
  609. // This test simulates an HTTPS response that includes a mangled HTTPS
  610. // record *and* has an error RCODE.
  611. TEST_P(HttpssvcMetricsTest, AddressAndHttpsMangledWithRcode) {
  612. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  613. const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
  614. auto metrics =
  615. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  616. metrics->SaveForHttps(HttpssvcDnsRcode::kNxDomain, {false},
  617. kResolveTimeHttps);
  618. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  619. metrics.reset(); // Record the metrics to UMA.
  620. VerifyIntegrityMetricsForExpectIntact();
  621. VerifyIntegrityMetricsForExpectNoerror();
  622. if (querying_experimental_) {
  623. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  624. VerifyHttpsMetricsForExpectIntact(
  625. // "DnsRcode" metric is omitted because we received an HTTPS record.
  626. absl::nullopt /* rcode */,
  627. // "parsable" metric is omitted because the RCODE is not NOERROR.
  628. absl::nullopt /* parsable */, {true} /* record_with_error */,
  629. {kResolveTimeHttps} /* resolve_time_https */,
  630. {15} /* resolve_time_ratio */);
  631. VerifyHttpsMetricsForExpectNoerror();
  632. return;
  633. }
  634. VerifyHttpsMetricsForExpectIntact();
  635. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  636. {kResolveTime} /* expect_noerror_time */);
  637. VerifyHttpsMetricsForExpectNoerror(
  638. {HttpssvcDnsRcode::kNxDomain} /* rcode */,
  639. // "parsable" metric is omitted because the RCODE is not NOERROR.
  640. absl::nullopt /* parsable */, {true} /* record_with_error */,
  641. {kResolveTimeHttps} /* resolve_time_https */,
  642. {15} /* resolve_time_ratio */);
  643. }
  644. // This test simulates successful address queries and an INTEGRITY query that
  645. // timed out.
  646. TEST_P(HttpssvcMetricsTest, AddressAndIntegrityTimedOut) {
  647. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  648. const base::TimeDelta kResolveTimeIntegrity = base::Milliseconds(15);
  649. auto metrics =
  650. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  651. metrics->SaveForIntegrity(HttpssvcDnsRcode::kTimedOut, {},
  652. kResolveTimeIntegrity);
  653. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  654. metrics.reset(); // Record the metrics to UMA.
  655. VerifyHttpsMetricsForExpectIntact();
  656. VerifyHttpsMetricsForExpectNoerror();
  657. if (querying_experimental_) {
  658. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  659. VerifyIntegrityMetricsForExpectIntact(
  660. {HttpssvcDnsRcode::kTimedOut} /* rcode */,
  661. // "Integrity" metric is omitted because the RCODE is not NOERROR.
  662. absl::nullopt /* integrity */, absl::nullopt /* record_with_error */,
  663. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  664. {15} /* resolve_time_ratio */);
  665. VerifyIntegrityMetricsForExpectNoerror();
  666. return;
  667. }
  668. VerifyIntegrityMetricsForExpectIntact();
  669. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  670. {kResolveTime} /* expect_noerror_time */);
  671. VerifyIntegrityMetricsForExpectNoerror(
  672. {HttpssvcDnsRcode::kTimedOut} /* rcode */,
  673. absl::nullopt /* record_received */,
  674. {kResolveTimeIntegrity} /* resolve_time_integrity */,
  675. {15} /* resolve_time_ratio */);
  676. }
  677. // This test simulates successful address queries and an HTTPS query that
  678. // timed out.
  679. TEST_P(HttpssvcMetricsTest, AddressAndHttpsTimedOut) {
  680. const base::TimeDelta kResolveTime = base::Milliseconds(10);
  681. const base::TimeDelta kResolveTimeHttps = base::Milliseconds(15);
  682. auto metrics =
  683. absl::make_optional<HttpssvcMetrics>(secure_, querying_experimental_);
  684. metrics->SaveForHttps(HttpssvcDnsRcode::kTimedOut, {}, kResolveTimeHttps);
  685. metrics->SaveForAddressQuery(kResolveTime, HttpssvcDnsRcode::kNoError);
  686. metrics.reset(); // Record the metrics to UMA.
  687. VerifyIntegrityMetricsForExpectIntact();
  688. VerifyIntegrityMetricsForExpectNoerror();
  689. if (querying_experimental_) {
  690. VerifyAddressResolveTimeMetric({kResolveTime} /* expect_intact_time */);
  691. VerifyHttpsMetricsForExpectIntact(
  692. {HttpssvcDnsRcode::kTimedOut} /* rcode */,
  693. // "parsable" metric is omitted because the RCODE is not NOERROR.
  694. absl::nullopt /* parsable */, absl::nullopt /* record_with_error */,
  695. {kResolveTimeHttps} /* resolve_time_https */,
  696. {15} /* resolve_time_ratio */);
  697. VerifyIntegrityMetricsForExpectNoerror();
  698. return;
  699. }
  700. VerifyHttpsMetricsForExpectIntact();
  701. VerifyAddressResolveTimeMetric(absl::nullopt /* expect_intact_time */,
  702. {kResolveTime} /* expect_noerror_time */);
  703. VerifyHttpsMetricsForExpectNoerror(
  704. {HttpssvcDnsRcode::kTimedOut} /* rcode */,
  705. // "parsable" metric is omitted because the RCODE is not NOERROR.
  706. absl::nullopt /* parsable */, absl::nullopt /* record_with_error */,
  707. {kResolveTimeHttps} /* resolve_time_https */,
  708. {15} /* resolve_time_ratio */);
  709. }
  710. } // namespace net