xref: /aosp_15_r20/external/cronet/net/dns/resolve_context_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/dns/resolve_context.h"
6 
7 #include <stdint.h>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 
12 #include "base/functional/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/run_loop.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/test/metrics/histogram_tester.h"
17 #include "base/time/time.h"
18 #include "net/base/address_list.h"
19 #include "net/base/features.h"
20 #include "net/base/ip_address.h"
21 #include "net/base/ip_endpoint.h"
22 #include "net/base/mock_network_change_notifier.h"
23 #include "net/base/network_change_notifier.h"
24 #include "net/base/network_isolation_key.h"
25 #include "net/dns/dns_config.h"
26 #include "net/dns/dns_server_iterator.h"
27 #include "net/dns/dns_session.h"
28 #include "net/dns/dns_util.h"
29 #include "net/dns/host_cache.h"
30 #include "net/dns/public/dns_over_https_config.h"
31 #include "net/dns/public/dns_over_https_server_config.h"
32 #include "net/dns/public/dns_protocol.h"
33 #include "net/dns/public/dns_query_type.h"
34 #include "net/dns/public/host_resolver_source.h"
35 #include "net/dns/public/secure_dns_mode.h"
36 #include "net/socket/socket_test_util.h"
37 #include "net/test/test_with_task_environment.h"
38 #include "net/url_request/url_request_context.h"
39 #include "net/url_request/url_request_context_builder.h"
40 #include "net/url_request/url_request_test_util.h"
41 #include "testing/gmock/include/gmock/gmock.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 
44 namespace net {
45 
46 namespace {
47 
48 class ResolveContextTest : public ::testing::Test, public WithTaskEnvironment {
49  protected:
ResolveContextTest()50   ResolveContextTest()
51       : WithTaskEnvironment(
52             base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
53 
CreateDnsSession(const DnsConfig & config)54   scoped_refptr<DnsSession> CreateDnsSession(const DnsConfig& config) {
55     auto null_random_callback =
56         base::BindRepeating([](int, int) -> int { base::ImmediateCrash(); });
57     return base::MakeRefCounted<DnsSession>(config, null_random_callback,
58                                             nullptr /* netlog */);
59   }
60 
61  protected:
62   test::ScopedMockNetworkChangeNotifier mock_notifier_;
63 
64  private:
65   std::unique_ptr<MockClientSocketFactory> socket_factory_ =
66       std::make_unique<MockClientSocketFactory>();
67 };
68 
CreateDnsConfig(int num_servers,int num_doh_servers)69 DnsConfig CreateDnsConfig(int num_servers, int num_doh_servers) {
70   DnsConfig config;
71   for (int i = 0; i < num_servers; ++i) {
72     IPEndPoint dns_endpoint(IPAddress(192, 168, 1, static_cast<uint8_t>(i)),
73                             dns_protocol::kDefaultPort);
74     config.nameservers.push_back(dns_endpoint);
75   }
76   std::vector<std::string> templates;
77   templates.reserve(num_doh_servers);
78   for (int i = 0; i < num_doh_servers; ++i) {
79     templates.push_back(
80         base::StringPrintf("https://mock.http/doh_test_%d{?dns}", i));
81   }
82   config.doh_config =
83       *DnsOverHttpsConfig::FromTemplatesForTesting(std::move(templates));
84   config.secure_dns_mode = SecureDnsMode::kAutomatic;
85 
86   return config;
87 }
88 
CreateDnsConfigWithKnownDohProviderConfig()89 DnsConfig CreateDnsConfigWithKnownDohProviderConfig() {
90   DnsConfig config;
91 
92   // TODO(https://crbug.com/1306495): Refactor this to not rely on an entry
93   // for 8.8.8.8 existing in the DoH provider list.
94   IPEndPoint dns_endpoint(IPAddress(8, 8, 8, 8), dns_protocol::kDefaultPort);
95   config.nameservers.push_back(dns_endpoint);
96 
97   config.doh_config = DnsOverHttpsConfig(
98       GetDohUpgradeServersFromNameservers(config.nameservers));
99   EXPECT_FALSE(config.doh_config.servers().empty());
100 
101   config.secure_dns_mode = SecureDnsMode::kAutomatic;
102 
103   return config;
104 }
105 
106 // Simulate a new session with the same pointer as an old deleted session by
107 // invalidating WeakPtrs.
TEST_F(ResolveContextTest,ReusedSessionPointer)108 TEST_F(ResolveContextTest, ReusedSessionPointer) {
109   DnsConfig config =
110       CreateDnsConfig(1 /* num_servers */, 3 /* num_doh_servers */);
111   scoped_refptr<DnsSession> session = CreateDnsSession(config);
112 
113   auto request_context = CreateTestURLRequestContextBuilder()->Build();
114   ResolveContext context(request_context.get(), true /* enable_caching */);
115   context.InvalidateCachesAndPerSessionData(session.get(),
116                                             false /* network_change */);
117 
118   // Mark probe success for the "original" (pre-invalidation) session.
119   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
120                               session.get());
121   ASSERT_TRUE(context.GetDohServerAvailability(1u, session.get()));
122 
123   // Simulate session destruction and recreation on the same pointer.
124   session->InvalidateWeakPtrsForTesting();
125 
126   // Expect |session| should now be treated as a new session, not matching
127   // |context|'s "current" session. Expect availability from the "old" session
128   // should not be read and RecordServerSuccess() should have no effect because
129   // the "new" session has not yet been marked as "current" through
130   // InvalidateCaches().
131   EXPECT_FALSE(context.GetDohServerAvailability(1u, session.get()));
132   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
133                               session.get());
134   EXPECT_FALSE(context.GetDohServerAvailability(1u, session.get()));
135 }
136 
TEST_F(ResolveContextTest,DohServerAvailability_InitialAvailability)137 TEST_F(ResolveContextTest, DohServerAvailability_InitialAvailability) {
138   DnsConfig config =
139       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
140   scoped_refptr<DnsSession> session = CreateDnsSession(config);
141 
142   auto request_context = CreateTestURLRequestContextBuilder()->Build();
143   ResolveContext context(request_context.get(), true /* enable_caching */);
144   context.InvalidateCachesAndPerSessionData(session.get(),
145                                             false /* network_change */);
146 
147   EXPECT_EQ(context.NumAvailableDohServers(session.get()), 0u);
148   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
149       session->config(), SecureDnsMode::kAutomatic, session.get());
150 
151   EXPECT_FALSE(doh_itr->AttemptAvailable());
152 
153   base::HistogramTester histogram_tester;
154   context.StartDohAutoupgradeSuccessTimer(session.get());
155   // Fast-forward by enough time for the timer to trigger. Add one millisecond
156   // just to make it clear that afterwards the timeout should definitely have
157   // occurred (although this may not be strictly necessary).
158   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
159                 base::Milliseconds(1));
160   histogram_tester.ExpectTotalCount(
161       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status", 0);
162 }
163 
TEST_F(ResolveContextTest,DohServerAvailability_RecordedSuccess)164 TEST_F(ResolveContextTest, DohServerAvailability_RecordedSuccess) {
165   DnsConfig config =
166       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
167   scoped_refptr<DnsSession> session = CreateDnsSession(config);
168 
169   auto request_context = CreateTestURLRequestContextBuilder()->Build();
170   ResolveContext context(request_context.get(), true /* enable_caching */);
171   context.InvalidateCachesAndPerSessionData(session.get(),
172                                             false /* network_change */);
173 
174   ASSERT_EQ(context.NumAvailableDohServers(session.get()), 0u);
175 
176   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
177                               session.get());
178   EXPECT_EQ(context.NumAvailableDohServers(session.get()), 1u);
179   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
180       session->config(), SecureDnsMode::kAutomatic, session.get());
181 
182   ASSERT_TRUE(doh_itr->AttemptAvailable());
183   EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
184 
185   base::HistogramTester histogram_tester;
186   context.StartDohAutoupgradeSuccessTimer(session.get());
187   // Fast-forward by enough time for the timer to trigger. Add one millisecond
188   // just to make it clear that afterwards the timeout should definitely have
189   // occurred (although this may not be strictly necessary).
190   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
191                 base::Milliseconds(1));
192   histogram_tester.ExpectTotalCount(
193       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status", 1);
194   histogram_tester.ExpectBucketCount(
195       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
196       DohServerAutoupgradeStatus::kSuccessWithNoPriorFailures, 1);
197 }
198 
TEST_F(ResolveContextTest,DohServerAvailability_NoCurrentSession)199 TEST_F(ResolveContextTest, DohServerAvailability_NoCurrentSession) {
200   DnsConfig config =
201       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
202   scoped_refptr<DnsSession> session = CreateDnsSession(config);
203 
204   auto request_context = CreateTestURLRequestContextBuilder()->Build();
205   ResolveContext context(request_context.get(), true /* enable_caching */);
206 
207   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
208                               session.get());
209 
210   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
211       session->config(), SecureDnsMode::kAutomatic, session.get());
212 
213   EXPECT_FALSE(doh_itr->AttemptAvailable());
214   EXPECT_EQ(0u, context.NumAvailableDohServers(session.get()));
215   EXPECT_FALSE(context.GetDohServerAvailability(1, session.get()));
216 }
217 
TEST_F(ResolveContextTest,DohServerAvailability_DifferentSession)218 TEST_F(ResolveContextTest, DohServerAvailability_DifferentSession) {
219   DnsConfig config1 =
220       CreateDnsConfig(1 /* num_servers */, 3 /* num_doh_servers */);
221   scoped_refptr<DnsSession> session1 = CreateDnsSession(config1);
222 
223   DnsConfig config2 =
224       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
225   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
226 
227   auto request_context = CreateTestURLRequestContextBuilder()->Build();
228   ResolveContext context(request_context.get(), true /* enable_caching */);
229   context.InvalidateCachesAndPerSessionData(session2.get(),
230                                             true /* network_change */);
231 
232   // Use current session to set a probe result.
233   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
234                               session2.get());
235 
236   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
237       session1->config(), SecureDnsMode::kAutomatic, session1.get());
238 
239   EXPECT_FALSE(doh_itr->AttemptAvailable());
240   EXPECT_EQ(0u, context.NumAvailableDohServers(session1.get()));
241   EXPECT_FALSE(context.GetDohServerAvailability(1u, session1.get()));
242 
243   // Different session for RecordServerFailure() should have no effect.
244   ASSERT_TRUE(context.GetDohServerAvailability(1u, session2.get()));
245   for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
246     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
247                                 ERR_FAILED, session1.get());
248   }
249   EXPECT_TRUE(context.GetDohServerAvailability(1u, session2.get()));
250 }
251 
TEST_F(ResolveContextTest,DohServerIndexToUse)252 TEST_F(ResolveContextTest, DohServerIndexToUse) {
253   DnsConfig config =
254       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
255   scoped_refptr<DnsSession> session = CreateDnsSession(config);
256 
257   auto request_context = CreateTestURLRequestContextBuilder()->Build();
258   ResolveContext context(request_context.get(), true /* enable_caching */);
259   context.InvalidateCachesAndPerSessionData(session.get(),
260                                             false /* network_change */);
261 
262   context.RecordServerSuccess(0u /* server_index */, true /* is_doh_server */,
263                               session.get());
264   EXPECT_EQ(context.NumAvailableDohServers(session.get()), 1u);
265   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
266       session->config(), SecureDnsMode::kAutomatic, session.get());
267 
268   ASSERT_TRUE(doh_itr->AttemptAvailable());
269   EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
270   EXPECT_FALSE(doh_itr->AttemptAvailable());
271 }
272 
TEST_F(ResolveContextTest,DohServerIndexToUse_NoneEligible)273 TEST_F(ResolveContextTest, DohServerIndexToUse_NoneEligible) {
274   DnsConfig config =
275       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
276   scoped_refptr<DnsSession> session = CreateDnsSession(config);
277 
278   auto request_context = CreateTestURLRequestContextBuilder()->Build();
279   ResolveContext context(request_context.get(), true /* enable_caching */);
280   context.InvalidateCachesAndPerSessionData(session.get(),
281                                             false /* network_change */);
282 
283   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
284       session->config(), SecureDnsMode::kAutomatic, session.get());
285 
286   EXPECT_FALSE(doh_itr->AttemptAvailable());
287 }
288 
TEST_F(ResolveContextTest,DohServerIndexToUse_SecureMode)289 TEST_F(ResolveContextTest, DohServerIndexToUse_SecureMode) {
290   DnsConfig config =
291       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
292   scoped_refptr<DnsSession> session = CreateDnsSession(config);
293 
294   auto request_context = CreateTestURLRequestContextBuilder()->Build();
295   ResolveContext context(request_context.get(), true /* enable_caching */);
296   context.InvalidateCachesAndPerSessionData(session.get(),
297                                             false /* network_change */);
298 
299   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
300       session->config(), SecureDnsMode::kSecure, session.get());
301 
302   ASSERT_TRUE(doh_itr->AttemptAvailable());
303   EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
304   ASSERT_TRUE(doh_itr->AttemptAvailable());
305   EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
306 }
307 
TEST_F(ResolveContextTest,StartDohAutoupgradeSuccessTimer)308 TEST_F(ResolveContextTest, StartDohAutoupgradeSuccessTimer) {
309   DnsConfig config = CreateDnsConfig(/*num_servers=*/2, /*num_doh_servers=*/2);
310   scoped_refptr<DnsSession> session = CreateDnsSession(config);
311 
312   auto request_context = CreateTestURLRequestContextBuilder()->Build();
313   ResolveContext context(request_context.get(), /*enable_caching=*/true);
314   context.InvalidateCachesAndPerSessionData(session.get(),
315                                             /*network_change=*/false);
316 
317   EXPECT_FALSE(context.doh_autoupgrade_metrics_timer_is_running_for_testing());
318 
319   // Calling with a valid session should start the timer.
320   context.StartDohAutoupgradeSuccessTimer(session.get());
321   EXPECT_TRUE(context.doh_autoupgrade_metrics_timer_is_running_for_testing());
322 
323   // Making a second call should have no effect.
324   context.StartDohAutoupgradeSuccessTimer(session.get());
325   EXPECT_TRUE(context.doh_autoupgrade_metrics_timer_is_running_for_testing());
326 
327   // Fast-forward by enough time for the timer to trigger. Add one millisecond
328   // just to make it clear that afterwards the timeout should definitely have
329   // occurred (although this may not be strictly necessary).
330   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
331                 base::Milliseconds(1));
332   EXPECT_FALSE(context.doh_autoupgrade_metrics_timer_is_running_for_testing());
333 }
334 
335 class TestDnsObserver : public NetworkChangeNotifier::DNSObserver {
336  public:
OnDNSChanged()337   void OnDNSChanged() override { ++dns_changed_calls_; }
338 
dns_changed_calls() const339   int dns_changed_calls() const { return dns_changed_calls_; }
340 
341  private:
342   int dns_changed_calls_ = 0;
343 };
344 
TEST_F(ResolveContextTest,DohServerAvailabilityNotification)345 TEST_F(ResolveContextTest, DohServerAvailabilityNotification) {
346   TestDnsObserver config_observer;
347   NetworkChangeNotifier::AddDNSObserver(&config_observer);
348 
349   DnsConfig config =
350       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
351   scoped_refptr<DnsSession> session = CreateDnsSession(config);
352 
353   auto request_context = CreateTestURLRequestContextBuilder()->Build();
354   ResolveContext context(request_context.get(), true /* enable_caching */);
355   context.InvalidateCachesAndPerSessionData(session.get(),
356                                             false /* network_change */);
357 
358   base::RunLoop().RunUntilIdle();  // Notifications are async.
359   EXPECT_EQ(0, config_observer.dns_changed_calls());
360 
361   // Expect notification on first available DoH server.
362   ASSERT_EQ(0u, context.NumAvailableDohServers(session.get()));
363   context.RecordServerSuccess(0u /* server_index */, true /* is_doh_server */,
364                               session.get());
365   ASSERT_EQ(1u, context.NumAvailableDohServers(session.get()));
366   base::RunLoop().RunUntilIdle();  // Notifications are async.
367   EXPECT_EQ(1, config_observer.dns_changed_calls());
368 
369   // No notifications as additional servers are available or unavailable.
370   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
371                               session.get());
372   base::RunLoop().RunUntilIdle();  // Notifications are async.
373   EXPECT_EQ(1, config_observer.dns_changed_calls());
374   for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
375     ASSERT_EQ(2u, context.NumAvailableDohServers(session.get()));
376     context.RecordServerFailure(0u /* server_index */, true /* is_doh_server */,
377                                 ERR_FAILED, session.get());
378     base::RunLoop().RunUntilIdle();  // Notifications are async.
379     EXPECT_EQ(1, config_observer.dns_changed_calls());
380   }
381   ASSERT_EQ(1u, context.NumAvailableDohServers(session.get()));
382 
383   // Expect notification on last server unavailable.
384   for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
385     ASSERT_EQ(1u, context.NumAvailableDohServers(session.get()));
386     base::RunLoop().RunUntilIdle();  // Notifications are async.
387     EXPECT_EQ(1, config_observer.dns_changed_calls());
388 
389     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
390                                 ERR_FAILED, session.get());
391   }
392   ASSERT_EQ(0u, context.NumAvailableDohServers(session.get()));
393   base::RunLoop().RunUntilIdle();  // Notifications are async.
394   EXPECT_EQ(2, config_observer.dns_changed_calls());
395 
396   NetworkChangeNotifier::RemoveDNSObserver(&config_observer);
397 }
398 
TEST_F(ResolveContextTest,HostCacheInvalidation)399 TEST_F(ResolveContextTest, HostCacheInvalidation) {
400   ResolveContext context(nullptr /* url_request_context */,
401                          true /* enable_caching */);
402 
403   base::TimeTicks now;
404   HostCache::Key key("example.com", DnsQueryType::UNSPECIFIED, 0,
405                      HostResolverSource::ANY, NetworkAnonymizationKey());
406   context.host_cache()->Set(
407       key,
408       HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
409                        HostCache::Entry::SOURCE_UNKNOWN),
410       now, base::Seconds(10));
411   ASSERT_TRUE(context.host_cache()->Lookup(key, now));
412 
413   DnsConfig config =
414       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
415   scoped_refptr<DnsSession> session = CreateDnsSession(config);
416   context.InvalidateCachesAndPerSessionData(session.get(),
417                                             false /* network_change */);
418 
419   EXPECT_FALSE(context.host_cache()->Lookup(key, now));
420 
421   // Re-add to the host cache and now add some DoH server status.
422   context.host_cache()->Set(
423       key,
424       HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
425                        HostCache::Entry::SOURCE_UNKNOWN),
426       now, base::Seconds(10));
427   context.RecordServerSuccess(0u /* server_index */, true /* is_doh_server */,
428                               session.get());
429   ASSERT_TRUE(context.host_cache()->Lookup(key, now));
430   ASSERT_TRUE(context.GetDohServerAvailability(0u, session.get()));
431 
432   // Invalidate again.
433   DnsConfig config2 =
434       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
435   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
436   context.InvalidateCachesAndPerSessionData(session2.get(),
437                                             true /* network_change */);
438 
439   EXPECT_FALSE(context.host_cache()->Lookup(key, now));
440   EXPECT_FALSE(context.GetDohServerAvailability(0u, session.get()));
441   EXPECT_FALSE(context.GetDohServerAvailability(0u, session2.get()));
442 }
443 
TEST_F(ResolveContextTest,HostCacheInvalidation_SameSession)444 TEST_F(ResolveContextTest, HostCacheInvalidation_SameSession) {
445   ResolveContext context(nullptr /* url_request_context */,
446                          true /* enable_caching */);
447   DnsConfig config =
448       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
449   scoped_refptr<DnsSession> session = CreateDnsSession(config);
450 
451   // Initial invalidation just to set the session.
452   context.InvalidateCachesAndPerSessionData(session.get(),
453                                             false /* network_change */);
454 
455   // Add to the host cache and add some DoH server status.
456   base::TimeTicks now;
457   HostCache::Key key("example.com", DnsQueryType::UNSPECIFIED, 0,
458                      HostResolverSource::ANY, NetworkAnonymizationKey());
459   context.host_cache()->Set(
460       key,
461       HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{"example.com"},
462                        HostCache::Entry::SOURCE_UNKNOWN),
463       now, base::Seconds(10));
464   context.RecordServerSuccess(0u /* server_index */, true /* is_doh_server */,
465                               session.get());
466   ASSERT_TRUE(context.host_cache()->Lookup(key, now));
467   ASSERT_TRUE(context.GetDohServerAvailability(0u, session.get()));
468 
469   // Invalidate again with the same session.
470   context.InvalidateCachesAndPerSessionData(session.get(),
471                                             false /* network_change */);
472 
473   // Expect host cache to be invalidated but not the per-session data.
474   EXPECT_FALSE(context.host_cache()->Lookup(key, now));
475   EXPECT_TRUE(context.GetDohServerAvailability(0u, session.get()));
476 }
477 
TEST_F(ResolveContextTest,Failures_Consecutive)478 TEST_F(ResolveContextTest, Failures_Consecutive) {
479   ResolveContext context(nullptr /* url_request_context */,
480                          false /* enable_caching */);
481   DnsConfig config =
482       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
483   scoped_refptr<DnsSession> session = CreateDnsSession(config);
484   context.InvalidateCachesAndPerSessionData(session.get(),
485                                             false /* network_change */);
486 
487   // Expect server preference to change after |config.attempts| failures.
488   for (int i = 0; i < config.attempts; i++) {
489     std::unique_ptr<DnsServerIterator> classic_itr =
490         context.GetClassicDnsIterator(session->config(), session.get());
491 
492     ASSERT_TRUE(classic_itr->AttemptAvailable());
493     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
494     ASSERT_TRUE(classic_itr->AttemptAvailable());
495     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
496 
497     context.RecordServerFailure(1u /* server_index */,
498                                 false /* is_doh_server */, ERR_FAILED,
499                                 session.get());
500   }
501 
502   {
503     std::unique_ptr<DnsServerIterator> classic_itr =
504         context.GetClassicDnsIterator(session->config(), session.get());
505 
506     ASSERT_TRUE(classic_itr->AttemptAvailable());
507     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
508     ASSERT_TRUE(classic_itr->AttemptAvailable());
509     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
510   }
511 
512   // Expect failures to be reset on successful request.
513   context.RecordServerSuccess(1u /* server_index */, false /* is_doh_server */,
514                               session.get());
515   {
516     std::unique_ptr<DnsServerIterator> classic_itr =
517         context.GetClassicDnsIterator(session->config(), session.get());
518 
519     ASSERT_TRUE(classic_itr->AttemptAvailable());
520     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
521     ASSERT_TRUE(classic_itr->AttemptAvailable());
522     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
523   }
524 }
525 
TEST_F(ResolveContextTest,Failures_NonConsecutive)526 TEST_F(ResolveContextTest, Failures_NonConsecutive) {
527   ResolveContext context(nullptr /* url_request_context */,
528                          false /* enable_caching */);
529   DnsConfig config =
530       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
531   scoped_refptr<DnsSession> session = CreateDnsSession(config);
532   context.InvalidateCachesAndPerSessionData(session.get(),
533                                             false /* network_change */);
534 
535   for (int i = 0; i < config.attempts - 1; i++) {
536     std::unique_ptr<DnsServerIterator> classic_itr =
537         context.GetClassicDnsIterator(session->config(), session.get());
538 
539     ASSERT_TRUE(classic_itr->AttemptAvailable());
540     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
541     ASSERT_TRUE(classic_itr->AttemptAvailable());
542     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
543 
544     context.RecordServerFailure(1u /* server_index */,
545                                 false /* is_doh_server */, ERR_FAILED,
546                                 session.get());
547   }
548 
549   {
550     std::unique_ptr<DnsServerIterator> classic_itr =
551         context.GetClassicDnsIterator(session->config(), session.get());
552 
553     ASSERT_TRUE(classic_itr->AttemptAvailable());
554     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
555     ASSERT_TRUE(classic_itr->AttemptAvailable());
556     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
557   }
558 
559   context.RecordServerSuccess(1u /* server_index */, false /* is_doh_server */,
560                               session.get());
561   {
562     std::unique_ptr<DnsServerIterator> classic_itr =
563         context.GetClassicDnsIterator(session->config(), session.get());
564 
565     ASSERT_TRUE(classic_itr->AttemptAvailable());
566     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
567     ASSERT_TRUE(classic_itr->AttemptAvailable());
568     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
569   }
570 
571   // Expect server stay preferred through non-consecutive failures.
572   context.RecordServerFailure(1u /* server_index */, false /* is_doh_server */,
573                               ERR_FAILED, session.get());
574   {
575     std::unique_ptr<DnsServerIterator> classic_itr =
576         context.GetClassicDnsIterator(session->config(), session.get());
577 
578     ASSERT_TRUE(classic_itr->AttemptAvailable());
579     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
580     ASSERT_TRUE(classic_itr->AttemptAvailable());
581     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
582   }
583 }
584 
TEST_F(ResolveContextTest,Failures_NoSession)585 TEST_F(ResolveContextTest, Failures_NoSession) {
586   ResolveContext context(nullptr /* url_request_context */,
587                          false /* enable_caching */);
588   DnsConfig config =
589       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
590   scoped_refptr<DnsSession> session = CreateDnsSession(config);
591 
592   // No expected change from recording failures.
593   for (int i = 0; i < config.attempts; i++) {
594     std::unique_ptr<DnsServerIterator> classic_itr =
595         context.GetClassicDnsIterator(session->config(), session.get());
596 
597     EXPECT_FALSE(classic_itr->AttemptAvailable());
598 
599     context.RecordServerFailure(1u /* server_index */,
600                                 false /* is_doh_server */, ERR_FAILED,
601                                 session.get());
602   }
603   std::unique_ptr<DnsServerIterator> classic_itr =
604       context.GetClassicDnsIterator(session->config(), session.get());
605 
606   EXPECT_FALSE(classic_itr->AttemptAvailable());
607 }
608 
TEST_F(ResolveContextTest,Failures_DifferentSession)609 TEST_F(ResolveContextTest, Failures_DifferentSession) {
610   DnsConfig config1 =
611       CreateDnsConfig(1 /* num_servers */, 3 /* num_doh_servers */);
612   scoped_refptr<DnsSession> session1 = CreateDnsSession(config1);
613 
614   DnsConfig config2 =
615       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
616   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
617 
618   ResolveContext context(nullptr /* url_request_context */,
619                          false /* enable_caching */);
620   context.InvalidateCachesAndPerSessionData(session2.get(),
621                                             true /* network_change */);
622 
623   // No change from recording failures to wrong session.
624   for (int i = 0; i < config1.attempts; i++) {
625     std::unique_ptr<DnsServerIterator> classic_itr =
626         context.GetClassicDnsIterator(session2->config(), session2.get());
627 
628     ASSERT_TRUE(classic_itr->AttemptAvailable());
629     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
630     ASSERT_TRUE(classic_itr->AttemptAvailable());
631     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
632 
633     context.RecordServerFailure(1u /* server_index */,
634                                 false /* is_doh_server */, ERR_FAILED,
635                                 session1.get());
636   }
637   std::unique_ptr<DnsServerIterator> classic_itr =
638       context.GetClassicDnsIterator(session2->config(), session2.get());
639 
640   ASSERT_TRUE(classic_itr->AttemptAvailable());
641   EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
642   ASSERT_TRUE(classic_itr->AttemptAvailable());
643   EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
644 }
645 
646 // Test 2 of 3 servers failing.
TEST_F(ResolveContextTest,TwoFailures)647 TEST_F(ResolveContextTest, TwoFailures) {
648   ResolveContext context(nullptr /* url_request_context */,
649                          false /* enable_caching */);
650   DnsConfig config =
651       CreateDnsConfig(3 /* num_servers */, 2 /* num_doh_servers */);
652   config.attempts = 1;
653   scoped_refptr<DnsSession> session = CreateDnsSession(config);
654   context.InvalidateCachesAndPerSessionData(session.get(),
655                                             false /* network_change */);
656 
657   // Expect server preference to change after |config.attempts| failures.
658   for (int i = 0; i < config.attempts; i++) {
659     std::unique_ptr<DnsServerIterator> classic_itr =
660         context.GetClassicDnsIterator(session->config(), session.get());
661 
662     ASSERT_TRUE(classic_itr->AttemptAvailable());
663     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
664     ASSERT_TRUE(classic_itr->AttemptAvailable());
665     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
666     ASSERT_TRUE(classic_itr->AttemptAvailable());
667     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 2u);
668 
669     context.RecordServerFailure(0u /* server_index */,
670                                 false /* is_doh_server */, ERR_FAILED,
671                                 session.get());
672     context.RecordServerFailure(1u /* server_index */,
673                                 false /* is_doh_server */, ERR_FAILED,
674                                 session.get());
675   }
676   {
677     std::unique_ptr<DnsServerIterator> classic_itr =
678         context.GetClassicDnsIterator(session->config(), session.get());
679 
680     ASSERT_TRUE(classic_itr->AttemptAvailable());
681     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 2u);
682     ASSERT_TRUE(classic_itr->AttemptAvailable());
683     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
684     ASSERT_TRUE(classic_itr->AttemptAvailable());
685     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
686   }
687 
688   // Expect failures to be reset on successful request.
689   context.RecordServerSuccess(0u /* server_index */, false /* is_doh_server */,
690                               session.get());
691   context.RecordServerSuccess(1u /* server_index */, false /* is_doh_server */,
692                               session.get());
693   {
694     std::unique_ptr<DnsServerIterator> classic_itr =
695         context.GetClassicDnsIterator(session->config(), session.get());
696 
697     ASSERT_TRUE(classic_itr->AttemptAvailable());
698     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
699     ASSERT_TRUE(classic_itr->AttemptAvailable());
700     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u);
701     ASSERT_TRUE(classic_itr->AttemptAvailable());
702     EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 2u);
703   }
704 }
705 
706 class TestDohStatusObserver : public ResolveContext::DohStatusObserver {
707  public:
OnSessionChanged()708   void OnSessionChanged() override { ++session_changes_; }
OnDohServerUnavailable(bool network_change)709   void OnDohServerUnavailable(bool network_change) override {
710     ++server_unavailable_notifications_;
711   }
712 
session_changes() const713   int session_changes() const { return session_changes_; }
server_unavailable_notifications() const714   int server_unavailable_notifications() const {
715     return server_unavailable_notifications_;
716   }
717 
718  private:
719   int session_changes_ = 0;
720   int server_unavailable_notifications_ = 0;
721 };
722 
TEST_F(ResolveContextTest,DohFailures_Consecutive)723 TEST_F(ResolveContextTest, DohFailures_Consecutive) {
724   ResolveContext context(nullptr /* url_request_context */,
725                          false /* enable_caching */);
726   DnsConfig config =
727       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
728   scoped_refptr<DnsSession> session = CreateDnsSession(config);
729   context.InvalidateCachesAndPerSessionData(session.get(),
730                                             false /* network_change */);
731 
732   TestDohStatusObserver observer;
733   context.RegisterDohStatusObserver(&observer);
734 
735   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
736                               session.get());
737 
738   for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
739     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
740         session->config(), SecureDnsMode::kAutomatic, session.get());
741 
742     ASSERT_TRUE(doh_itr->AttemptAvailable());
743     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
744     EXPECT_EQ(1u, context.NumAvailableDohServers(session.get()));
745     EXPECT_EQ(0, observer.server_unavailable_notifications());
746     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
747                                 ERR_FAILED, session.get());
748   }
749   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
750       session->config(), SecureDnsMode::kAutomatic, session.get());
751 
752   EXPECT_FALSE(doh_itr->AttemptAvailable());
753   EXPECT_EQ(0u, context.NumAvailableDohServers(session.get()));
754   EXPECT_EQ(1, observer.server_unavailable_notifications());
755 
756   base::HistogramTester histogram_tester;
757   context.StartDohAutoupgradeSuccessTimer(session.get());
758   // Fast-forward by enough time for the timer to trigger. Add one millisecond
759   // just to make it clear that afterwards the timeout should definitely have
760   // occurred (although this may not be strictly necessary).
761   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
762                 base::Milliseconds(1));
763   histogram_tester.ExpectTotalCount(
764       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
765       /*expected_count=*/1);
766   histogram_tester.ExpectBucketCount(
767       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
768       DohServerAutoupgradeStatus::kFailureWithSomePriorSuccesses,
769       /*expected_count=*/1);
770 
771   context.UnregisterDohStatusObserver(&observer);
772 }
773 
TEST_F(ResolveContextTest,DohFailures_NonConsecutive)774 TEST_F(ResolveContextTest, DohFailures_NonConsecutive) {
775   ResolveContext context(nullptr /* url_request_context */,
776                          false /* enable_caching */);
777   DnsConfig config =
778       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
779   scoped_refptr<DnsSession> session = CreateDnsSession(config);
780   context.InvalidateCachesAndPerSessionData(session.get(),
781                                             false /* network_change */);
782 
783   TestDohStatusObserver observer;
784   context.RegisterDohStatusObserver(&observer);
785 
786   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
787                               session.get());
788 
789   for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
790     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
791         session->config(), SecureDnsMode::kAutomatic, session.get());
792 
793     ASSERT_TRUE(doh_itr->AttemptAvailable());
794     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
795     EXPECT_EQ(1u, context.NumAvailableDohServers(session.get()));
796     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
797                                 ERR_FAILED, session.get());
798   }
799   {
800     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
801         session->config(), SecureDnsMode::kAutomatic, session.get());
802 
803     ASSERT_TRUE(doh_itr->AttemptAvailable());
804     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
805   }
806   EXPECT_EQ(1u, context.NumAvailableDohServers(session.get()));
807 
808   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
809                               session.get());
810   {
811     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
812         session->config(), SecureDnsMode::kAutomatic, session.get());
813 
814     ASSERT_TRUE(doh_itr->AttemptAvailable());
815     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
816   }
817   EXPECT_EQ(1u, context.NumAvailableDohServers(session.get()));
818 
819   // Expect a single additional failure should not make a DoH server unavailable
820   // because the success resets failure tracking.
821   context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
822                               ERR_FAILED, session.get());
823   {
824     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
825         session->config(), SecureDnsMode::kAutomatic, session.get());
826 
827     ASSERT_TRUE(doh_itr->AttemptAvailable());
828     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
829   }
830   EXPECT_EQ(1u, context.NumAvailableDohServers(session.get()));
831 
832   EXPECT_EQ(0, observer.server_unavailable_notifications());
833 
834   base::HistogramTester histogram_tester;
835   context.StartDohAutoupgradeSuccessTimer(session.get());
836   // Fast-forward by enough time for the timer to trigger. Add one millisecond
837   // just to make it clear that afterwards the timeout should definitely have
838   // occurred (although this may not be strictly necessary).
839   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
840                 base::Milliseconds(1));
841   histogram_tester.ExpectTotalCount(
842       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
843       /*expected_count=*/1);
844   histogram_tester.ExpectBucketCount(
845       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
846       DohServerAutoupgradeStatus::kSuccessWithSomePriorFailures,
847       /*expected_count=*/1);
848 
849   context.UnregisterDohStatusObserver(&observer);
850 }
851 
TEST_F(ResolveContextTest,DohFailures_SuccessAfterFailures)852 TEST_F(ResolveContextTest, DohFailures_SuccessAfterFailures) {
853   ResolveContext context(nullptr /* url_request_context */,
854                          false /* enable_caching */);
855   DnsConfig config =
856       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
857   scoped_refptr<DnsSession> session = CreateDnsSession(config);
858   context.InvalidateCachesAndPerSessionData(session.get(),
859                                             false /* network_change */);
860 
861   TestDohStatusObserver observer;
862   context.RegisterDohStatusObserver(&observer);
863 
864   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
865                               session.get());
866 
867   for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
868     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
869                                 ERR_FAILED, session.get());
870   }
871   ASSERT_EQ(0u, context.NumAvailableDohServers(session.get()));
872   EXPECT_EQ(1, observer.server_unavailable_notifications());
873 
874   // Expect a single success to make an unavailable DoH server available again.
875   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
876                               session.get());
877   {
878     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
879         session->config(), SecureDnsMode::kAutomatic, session.get());
880 
881     ASSERT_TRUE(doh_itr->AttemptAvailable());
882     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
883   }
884   EXPECT_EQ(1u, context.NumAvailableDohServers(session.get()));
885 
886   EXPECT_EQ(1, observer.server_unavailable_notifications());
887 
888   base::HistogramTester histogram_tester;
889   context.StartDohAutoupgradeSuccessTimer(session.get());
890   // Fast-forward by enough time for the timer to trigger. Add one millisecond
891   // just to make it clear that afterwards the timeout should definitely have
892   // occurred (although this may not be strictly necessary).
893   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
894                 base::Milliseconds(1));
895   histogram_tester.ExpectTotalCount(
896       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
897       /*expected_count=*/1);
898   histogram_tester.ExpectBucketCount(
899       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
900       DohServerAutoupgradeStatus::kSuccessWithSomePriorFailures,
901       /*expected_count=*/1);
902 
903   context.UnregisterDohStatusObserver(&observer);
904 }
905 
TEST_F(ResolveContextTest,DohFailures_NoSession)906 TEST_F(ResolveContextTest, DohFailures_NoSession) {
907   ResolveContext context(nullptr /* url_request_context */,
908                          false /* enable_caching */);
909   DnsConfig config =
910       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
911   scoped_refptr<DnsSession> session = CreateDnsSession(config);
912 
913   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
914                               session.get());
915 
916   // No expected change from recording failures.
917   for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
918     EXPECT_EQ(0u, context.NumAvailableDohServers(session.get()));
919     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
920                                 ERR_FAILED, session.get());
921   }
922   EXPECT_EQ(0u, context.NumAvailableDohServers(session.get()));
923 }
924 
TEST_F(ResolveContextTest,DohFailures_DifferentSession)925 TEST_F(ResolveContextTest, DohFailures_DifferentSession) {
926   DnsConfig config1 =
927       CreateDnsConfig(1 /* num_servers */, 3 /* num_doh_servers */);
928   scoped_refptr<DnsSession> session1 = CreateDnsSession(config1);
929 
930   DnsConfig config2 =
931       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
932   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
933 
934   ResolveContext context(nullptr /* url_request_context */,
935                          false /* enable_caching */);
936   context.InvalidateCachesAndPerSessionData(session2.get(),
937                                             true /* network_change */);
938 
939   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
940                               session2.get());
941   ASSERT_EQ(1u, context.NumAvailableDohServers(session2.get()));
942 
943   // No change from recording failures to wrong session.
944   for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
945     EXPECT_EQ(1u, context.NumAvailableDohServers(session2.get()));
946     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
947                                 ERR_FAILED, session1.get());
948   }
949   EXPECT_EQ(1u, context.NumAvailableDohServers(session2.get()));
950 }
951 
TEST_F(ResolveContextTest,DohFailures_NeverSuccessful)952 TEST_F(ResolveContextTest, DohFailures_NeverSuccessful) {
953   DnsConfig config = CreateDnsConfig(/*num_servers=*/2, /*num_doh_servers=*/2);
954   scoped_refptr<DnsSession> session = CreateDnsSession(config);
955   ResolveContext context(/*url_request_context=*/nullptr,
956                          /*enable_caching=*/false);
957   context.InvalidateCachesAndPerSessionData(session.get(),
958                                             /*network_change=*/false);
959 
960   context.RecordServerFailure(/*server_index=*/0u, /*is_doh_server=*/true,
961                               ERR_FAILED, session.get());
962 
963   base::HistogramTester histogram_tester;
964   context.StartDohAutoupgradeSuccessTimer(session.get());
965   // Fast-forward by enough time for the timer to trigger. Add one millisecond
966   // just to make it clear that afterwards the timeout should definitely have
967   // occurred (although this may not be strictly necessary).
968   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
969                 base::Milliseconds(1));
970   histogram_tester.ExpectTotalCount(
971       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
972       /*expected_count=*/1);
973   histogram_tester.ExpectBucketCount(
974       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
975       DohServerAutoupgradeStatus::kFailureWithNoPriorSuccesses,
976       /*expected_count=*/1);
977 }
978 
979 // Test that metrics are recorded properly when auto-upgrade is never successful
980 // for a provider that is in the list of providers where we can auto-upgrade
981 // insecure DNS queries to secure DNS queries.
TEST_F(ResolveContextTest,DohFailures_NeverSuccessfulKnownProviderConfig)982 TEST_F(ResolveContextTest, DohFailures_NeverSuccessfulKnownProviderConfig) {
983   ResolveContext context(/*url_request_context=*/nullptr,
984                          /*enable_caching=*/false);
985   DnsConfig config = CreateDnsConfigWithKnownDohProviderConfig();
986   scoped_refptr<DnsSession> session = CreateDnsSession(config);
987   context.InvalidateCachesAndPerSessionData(session.get(),
988                                             /*network_change=*/false);
989 
990   context.RecordServerFailure(/*server_index=*/0u, /*is_doh_server=*/true,
991                               ERR_FAILED, session.get());
992 
993   base::HistogramTester histogram_tester;
994   context.StartDohAutoupgradeSuccessTimer(session.get());
995   // Fast-forward by enough time for the timer to trigger. Add one millisecond
996   // just to make it clear that afterwards the timeout should definitely have
997   // occurred (although this may not be strictly necessary).
998   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
999                 base::Milliseconds(1));
1000   histogram_tester.ExpectTotalCount(
1001       "Net.DNS.ResolveContext.DohAutoupgrade.Google.Status",
1002       /*expected_count=*/1);
1003   histogram_tester.ExpectBucketCount(
1004       "Net.DNS.ResolveContext.DohAutoupgrade.Google.Status",
1005       DohServerAutoupgradeStatus::kFailureWithNoPriorSuccesses,
1006       /*expected_count=*/1);
1007 }
1008 
1009 // Test 2 of 3 DoH servers failing.
TEST_F(ResolveContextTest,TwoDohFailures)1010 TEST_F(ResolveContextTest, TwoDohFailures) {
1011   ResolveContext context(nullptr /* url_request_context */,
1012                          false /* enable_caching */);
1013   DnsConfig config =
1014       CreateDnsConfig(2 /* num_servers */, 3 /* num_doh_servers */);
1015   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1016   context.InvalidateCachesAndPerSessionData(session.get(),
1017                                             false /* network_change */);
1018 
1019   context.RecordServerSuccess(0u /* server_index */, true /* is_doh_server */,
1020                               session.get());
1021   context.RecordServerSuccess(1u /* server_index */, true /* is_doh_server */,
1022                               session.get());
1023   context.RecordServerSuccess(2u /* server_index */, true /* is_doh_server */,
1024                               session.get());
1025 
1026   // Expect server preference to change after |config.attempts| failures.
1027   for (int i = 0; i < config.attempts; i++) {
1028     std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
1029         session->config(), SecureDnsMode::kAutomatic, session.get());
1030 
1031     ASSERT_TRUE(doh_itr->AttemptAvailable());
1032     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
1033     ASSERT_TRUE(doh_itr->AttemptAvailable());
1034     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
1035     ASSERT_TRUE(doh_itr->AttemptAvailable());
1036     EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
1037 
1038     context.RecordServerFailure(0u /* server_index */, true /* is_doh_server */,
1039                                 ERR_FAILED, session.get());
1040     context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */,
1041                                 ERR_FAILED, session.get());
1042   }
1043 
1044   std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator(
1045       session->config(), SecureDnsMode::kAutomatic, session.get());
1046 
1047   ASSERT_TRUE(doh_itr->AttemptAvailable());
1048   EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
1049 
1050   base::HistogramTester histogram_tester;
1051   context.StartDohAutoupgradeSuccessTimer(session.get());
1052   // Fast-forward by enough time for the timer to trigger. Add one millisecond
1053   // just to make it clear that afterwards the timeout should definitely have
1054   // occurred (although this may not be strictly necessary).
1055   FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
1056                 base::Milliseconds(1));
1057   histogram_tester.ExpectTotalCount(
1058       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
1059       /*expected_count=*/3);
1060   histogram_tester.ExpectBucketCount(
1061       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
1062       DohServerAutoupgradeStatus::kSuccessWithSomePriorFailures,
1063       /*expected_count=*/2);
1064   histogram_tester.ExpectBucketCount(
1065       "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
1066       DohServerAutoupgradeStatus::kSuccessWithNoPriorFailures,
1067       /*expected_count=*/1);
1068 }
1069 
1070 // Expect default calculated fallback period to be within 10ms of
1071 // |DnsConfig::fallback_period|.
TEST_F(ResolveContextTest,FallbackPeriod_Default)1072 TEST_F(ResolveContextTest, FallbackPeriod_Default) {
1073   ResolveContext context(nullptr /* url_request_context */,
1074                          false /* enable_caching */);
1075   DnsConfig config =
1076       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1077   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1078   context.InvalidateCachesAndPerSessionData(session.get(),
1079                                             false /* network_change */);
1080 
1081   base::TimeDelta delta =
1082       context.NextClassicFallbackPeriod(0 /* server_index */, 0 /* attempt */,
1083                                         session.get()) -
1084       config.fallback_period;
1085   EXPECT_LE(delta, base::Milliseconds(10));
1086   delta =
1087       context.NextDohFallbackPeriod(0 /* doh_server_index */, session.get()) -
1088       config.fallback_period;
1089   EXPECT_LE(delta, base::Milliseconds(10));
1090 }
1091 
1092 // Expect short calculated fallback period to be within 10ms of
1093 // |DnsConfig::fallback_period|.
TEST_F(ResolveContextTest,FallbackPeriod_ShortConfigured)1094 TEST_F(ResolveContextTest, FallbackPeriod_ShortConfigured) {
1095   ResolveContext context(nullptr /* url_request_context */,
1096                          false /* enable_caching */);
1097   DnsConfig config =
1098       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1099   config.fallback_period = base::Milliseconds(15);
1100   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1101   context.InvalidateCachesAndPerSessionData(session.get(),
1102                                             false /* network_change */);
1103 
1104   base::TimeDelta delta =
1105       context.NextClassicFallbackPeriod(0 /* server_index */, 0 /* attempt */,
1106                                         session.get()) -
1107       config.fallback_period;
1108   EXPECT_LE(delta, base::Milliseconds(10));
1109   delta =
1110       context.NextDohFallbackPeriod(0 /* doh_server_index */, session.get()) -
1111       config.fallback_period;
1112   EXPECT_LE(delta, base::Milliseconds(10));
1113 }
1114 
1115 // Expect long calculated fallback period to be equal to
1116 // |DnsConfig::fallback_period|. (Default max fallback period is 5 seconds, so
1117 // NextClassicFallbackPeriod() should return exactly the config fallback
1118 // period.)
TEST_F(ResolveContextTest,FallbackPeriod_LongConfigured)1119 TEST_F(ResolveContextTest, FallbackPeriod_LongConfigured) {
1120   ResolveContext context(nullptr /* url_request_context */,
1121                          false /* enable_caching */);
1122   DnsConfig config =
1123       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1124   config.fallback_period = base::Seconds(15);
1125   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1126   context.InvalidateCachesAndPerSessionData(session.get(),
1127                                             false /* network_change */);
1128 
1129   EXPECT_EQ(context.NextClassicFallbackPeriod(0 /* server_index */,
1130                                               0 /* attempt */, session.get()),
1131             config.fallback_period);
1132   EXPECT_EQ(
1133       context.NextDohFallbackPeriod(0 /* doh_server_index */, session.get()),
1134       config.fallback_period);
1135 }
1136 
1137 // Expect fallback periods to increase on recording long round-trip times.
TEST_F(ResolveContextTest,FallbackPeriod_LongRtt)1138 TEST_F(ResolveContextTest, FallbackPeriod_LongRtt) {
1139   ResolveContext context(nullptr /* url_request_context */,
1140                          false /* enable_caching */);
1141   DnsConfig config =
1142       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1143   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1144   context.InvalidateCachesAndPerSessionData(session.get(),
1145                                             false /* network_change */);
1146 
1147   for (int i = 0; i < 50; ++i) {
1148     context.RecordRtt(0u /* server_index */, false /* is_doh_server */,
1149                       base::Minutes(10), OK, session.get());
1150     context.RecordRtt(1u /* server_index */, true /* is_doh_server */,
1151                       base::Minutes(10), OK, session.get());
1152   }
1153 
1154   // Expect servers with high recorded RTT to have increased fallback periods
1155   // (>10ms).
1156   base::TimeDelta delta =
1157       context.NextClassicFallbackPeriod(0u /* server_index */, 0 /* attempt */,
1158                                         session.get()) -
1159       config.fallback_period;
1160   EXPECT_GT(delta, base::Milliseconds(10));
1161   delta =
1162       context.NextDohFallbackPeriod(1u, session.get()) - config.fallback_period;
1163   EXPECT_GT(delta, base::Milliseconds(10));
1164 
1165   // Servers without recorded RTT expected to remain the same (<=10ms).
1166   delta = context.NextClassicFallbackPeriod(1u /* server_index */,
1167                                             0 /* attempt */, session.get()) -
1168           config.fallback_period;
1169   EXPECT_LE(delta, base::Milliseconds(10));
1170   delta =
1171       context.NextDohFallbackPeriod(0u /* doh_server_index */, session.get()) -
1172       config.fallback_period;
1173   EXPECT_LE(delta, base::Milliseconds(10));
1174 }
1175 
1176 // Expect recording round-trip times to have no affect on fallback period
1177 // without a current session.
TEST_F(ResolveContextTest,FallbackPeriod_NoSession)1178 TEST_F(ResolveContextTest, FallbackPeriod_NoSession) {
1179   ResolveContext context(nullptr /* url_request_context */,
1180                          false /* enable_caching */);
1181   DnsConfig config =
1182       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1183   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1184 
1185   for (int i = 0; i < 50; ++i) {
1186     context.RecordRtt(0u /* server_index */, false /* is_doh_server */,
1187                       base::Minutes(10), OK, session.get());
1188     context.RecordRtt(1u /* server_index */, true /* is_doh_server */,
1189                       base::Minutes(10), OK, session.get());
1190   }
1191 
1192   base::TimeDelta delta =
1193       context.NextClassicFallbackPeriod(0u /* server_index */, 0 /* attempt */,
1194                                         session.get()) -
1195       config.fallback_period;
1196   EXPECT_LE(delta, base::Milliseconds(10));
1197   delta =
1198       context.NextDohFallbackPeriod(1u /* doh_server_index */, session.get()) -
1199       config.fallback_period;
1200   EXPECT_LE(delta, base::Milliseconds(10));
1201 }
1202 
1203 // Expect recording round-trip times to have no affect on fallback periods
1204 // without a current session.
TEST_F(ResolveContextTest,FallbackPeriod_DifferentSession)1205 TEST_F(ResolveContextTest, FallbackPeriod_DifferentSession) {
1206   DnsConfig config1 =
1207       CreateDnsConfig(1 /* num_servers */, 3 /* num_doh_servers */);
1208   scoped_refptr<DnsSession> session1 = CreateDnsSession(config1);
1209 
1210   DnsConfig config2 =
1211       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1212   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
1213 
1214   ResolveContext context(nullptr /* url_request_context */,
1215                          false /* enable_caching */);
1216   context.InvalidateCachesAndPerSessionData(session2.get(),
1217                                             true /* network_change */);
1218 
1219   // Record RTT's to increase fallback periods for current session.
1220   for (int i = 0; i < 50; ++i) {
1221     context.RecordRtt(0u /* server_index */, false /* is_doh_server */,
1222                       base::Minutes(10), OK, session2.get());
1223     context.RecordRtt(1u /* server_index */, true /* is_doh_server */,
1224                       base::Minutes(10), OK, session2.get());
1225   }
1226 
1227   // Expect normal short fallback periods for other session.
1228   base::TimeDelta delta =
1229       context.NextClassicFallbackPeriod(0u /* server_index */, 0 /* attempt */,
1230                                         session1.get()) -
1231       config1.fallback_period;
1232   EXPECT_LE(delta, base::Milliseconds(10));
1233   delta =
1234       context.NextDohFallbackPeriod(0u /* doh_server_index */, session1.get()) -
1235       config1.fallback_period;
1236   EXPECT_LE(delta, base::Milliseconds(10));
1237 
1238   // Recording RTT's for other session should have no effect on current session
1239   // fallback periods.
1240   base::TimeDelta fallback_period = context.NextClassicFallbackPeriod(
1241       0u /* server_index */, 0 /* attempt */, session2.get());
1242   for (int i = 0; i < 50; ++i) {
1243     context.RecordRtt(0u /* server_index */, false /* is_doh_server */,
1244                       base::Milliseconds(1), OK, session1.get());
1245   }
1246   EXPECT_EQ(fallback_period,
1247             context.NextClassicFallbackPeriod(0u /* server_index */,
1248                                               0 /* attempt */, session2.get()));
1249 }
1250 
1251 // Expect minimum timeout will be used when fallback period is small.
TEST_F(ResolveContextTest,SecureTransactionTimeout_SmallFallbackPeriod)1252 TEST_F(ResolveContextTest, SecureTransactionTimeout_SmallFallbackPeriod) {
1253   ResolveContext context(nullptr /* url_request_context */,
1254                          false /* enable_caching */);
1255   DnsConfig config =
1256       CreateDnsConfig(0 /* num_servers */, 1 /* num_doh_servers */);
1257   config.fallback_period = base::TimeDelta();
1258   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1259   context.InvalidateCachesAndPerSessionData(session.get(),
1260                                             false /* network_change */);
1261 
1262   EXPECT_EQ(
1263       context.SecureTransactionTimeout(SecureDnsMode::kSecure, session.get()),
1264       features::kDnsMinTransactionTimeout.Get());
1265 }
1266 
1267 // Expect multiplier on fallback period to be used when larger than minimum
1268 // timeout.
TEST_F(ResolveContextTest,SecureTransactionTimeout_LongFallbackPeriod)1269 TEST_F(ResolveContextTest, SecureTransactionTimeout_LongFallbackPeriod) {
1270   ResolveContext context(nullptr /* url_request_context */,
1271                          false /* enable_caching */);
1272   const base::TimeDelta kFallbackPeriod = base::Minutes(5);
1273   DnsConfig config =
1274       CreateDnsConfig(0 /* num_servers */, 1 /* num_doh_servers */);
1275   config.fallback_period = kFallbackPeriod;
1276   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1277   context.InvalidateCachesAndPerSessionData(session.get(),
1278                                             false /* network_change */);
1279 
1280   base::TimeDelta expected =
1281       kFallbackPeriod * features::kDnsTransactionTimeoutMultiplier.Get();
1282   ASSERT_GT(expected, features::kDnsMinTransactionTimeout.Get());
1283 
1284   EXPECT_EQ(
1285       context.SecureTransactionTimeout(SecureDnsMode::kSecure, session.get()),
1286       expected);
1287 }
1288 
TEST_F(ResolveContextTest,SecureTransactionTimeout_LongRtt)1289 TEST_F(ResolveContextTest, SecureTransactionTimeout_LongRtt) {
1290   ResolveContext context(nullptr /* url_request_context */,
1291                          false /* enable_caching */);
1292   DnsConfig config =
1293       CreateDnsConfig(0 /* num_servers */, 2 /* num_doh_servers */);
1294   config.fallback_period = base::TimeDelta();
1295   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1296   context.InvalidateCachesAndPerSessionData(session.get(),
1297                                             false /* network_change */);
1298 
1299   // Record long RTTs for only 1 server.
1300   for (int i = 0; i < 50; ++i) {
1301     context.RecordRtt(1u /* server_index */, true /* is_doh_server */,
1302                       base::Minutes(10), OK, session.get());
1303   }
1304 
1305   // No expected change from recording RTT to single server because lowest
1306   // fallback period is used.
1307   EXPECT_EQ(
1308       context.SecureTransactionTimeout(SecureDnsMode::kSecure, session.get()),
1309       features::kDnsMinTransactionTimeout.Get());
1310 
1311   // Record long RTTs for remaining server.
1312   for (int i = 0; i < 50; ++i) {
1313     context.RecordRtt(0u /* server_index */, true /* is_doh_server */,
1314                       base::Minutes(10), OK, session.get());
1315   }
1316 
1317   // Expect longer timeouts.
1318   EXPECT_GT(
1319       context.SecureTransactionTimeout(SecureDnsMode::kSecure, session.get()),
1320       features::kDnsMinTransactionTimeout.Get());
1321 }
1322 
TEST_F(ResolveContextTest,SecureTransactionTimeout_DifferentSession)1323 TEST_F(ResolveContextTest, SecureTransactionTimeout_DifferentSession) {
1324   const base::TimeDelta kFallbackPeriod = base::Minutes(5);
1325   DnsConfig config1 =
1326       CreateDnsConfig(0 /* num_servers */, 1 /* num_doh_servers */);
1327   config1.fallback_period = kFallbackPeriod;
1328   scoped_refptr<DnsSession> session1 = CreateDnsSession(config1);
1329 
1330   DnsConfig config2 =
1331       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1332   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
1333 
1334   ResolveContext context(nullptr /* url_request_context */,
1335                          false /* enable_caching */);
1336   context.InvalidateCachesAndPerSessionData(session1.get(),
1337                                             true /* network_change */);
1338 
1339   // Confirm that if session data were used, the timeout would be higher than
1340   // the min.
1341   base::TimeDelta multiplier_expected =
1342       kFallbackPeriod * features::kDnsTransactionTimeoutMultiplier.Get();
1343   ASSERT_GT(multiplier_expected, features::kDnsMinTransactionTimeout.Get());
1344 
1345   // Expect timeout always minimum with wrong session.
1346   EXPECT_EQ(
1347       context.SecureTransactionTimeout(SecureDnsMode::kSecure, session2.get()),
1348       features::kDnsMinTransactionTimeout.Get());
1349 }
1350 
1351 // Expect minimum timeout will be used when fallback period is small.
TEST_F(ResolveContextTest,ClassicTransactionTimeout_SmallFallbackPeriod)1352 TEST_F(ResolveContextTest, ClassicTransactionTimeout_SmallFallbackPeriod) {
1353   ResolveContext context(nullptr /* url_request_context */,
1354                          false /* enable_caching */);
1355   DnsConfig config =
1356       CreateDnsConfig(1 /* num_servers */, 0 /* num_doh_servers */);
1357   config.fallback_period = base::TimeDelta();
1358   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1359   context.InvalidateCachesAndPerSessionData(session.get(),
1360                                             false /* network_change */);
1361 
1362   EXPECT_EQ(context.ClassicTransactionTimeout(session.get()),
1363             features::kDnsMinTransactionTimeout.Get());
1364 }
1365 
1366 // Expect multiplier on fallback period to be used when larger than minimum
1367 // timeout.
TEST_F(ResolveContextTest,ClassicTransactionTimeout_LongFallbackPeriod)1368 TEST_F(ResolveContextTest, ClassicTransactionTimeout_LongFallbackPeriod) {
1369   ResolveContext context(nullptr /* url_request_context */,
1370                          false /* enable_caching */);
1371   const base::TimeDelta kFallbackPeriod = base::Minutes(5);
1372   DnsConfig config =
1373       CreateDnsConfig(1 /* num_servers */, 0 /* num_doh_servers */);
1374   config.fallback_period = kFallbackPeriod;
1375   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1376   context.InvalidateCachesAndPerSessionData(session.get(),
1377                                             false /* network_change */);
1378 
1379   base::TimeDelta expected =
1380       kFallbackPeriod * features::kDnsTransactionTimeoutMultiplier.Get();
1381   ASSERT_GT(expected, features::kDnsMinTransactionTimeout.Get());
1382 
1383   EXPECT_EQ(context.ClassicTransactionTimeout(session.get()), expected);
1384 }
1385 
TEST_F(ResolveContextTest,ClassicTransactionTimeout_LongRtt)1386 TEST_F(ResolveContextTest, ClassicTransactionTimeout_LongRtt) {
1387   ResolveContext context(nullptr /* url_request_context */,
1388                          false /* enable_caching */);
1389   DnsConfig config =
1390       CreateDnsConfig(2 /* num_servers */, 0 /* num_doh_servers */);
1391   config.fallback_period = base::TimeDelta();
1392   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1393   context.InvalidateCachesAndPerSessionData(session.get(),
1394                                             false /* network_change */);
1395 
1396   // Record long RTTs for only 1 server.
1397   for (int i = 0; i < 50; ++i) {
1398     context.RecordRtt(1u /* server_index */, false /* is_doh_server */,
1399                       base::Minutes(10), OK, session.get());
1400   }
1401 
1402   // No expected change from recording RTT to single server because lowest
1403   // fallback period is used.
1404   EXPECT_EQ(context.ClassicTransactionTimeout(session.get()),
1405             features::kDnsMinTransactionTimeout.Get());
1406 
1407   // Record long RTTs for remaining server.
1408   for (int i = 0; i < 50; ++i) {
1409     context.RecordRtt(0u /* server_index */, false /* is_doh_server */,
1410                       base::Minutes(10), OK, session.get());
1411   }
1412 
1413   // Expect longer timeouts.
1414   EXPECT_GT(context.ClassicTransactionTimeout(session.get()),
1415             features::kDnsMinTransactionTimeout.Get());
1416 }
1417 
TEST_F(ResolveContextTest,ClassicTransactionTimeout_DifferentSession)1418 TEST_F(ResolveContextTest, ClassicTransactionTimeout_DifferentSession) {
1419   const base::TimeDelta kFallbackPeriod = base::Minutes(5);
1420   DnsConfig config1 =
1421       CreateDnsConfig(1 /* num_servers */, 0 /* num_doh_servers */);
1422   config1.fallback_period = kFallbackPeriod;
1423   scoped_refptr<DnsSession> session1 = CreateDnsSession(config1);
1424 
1425   DnsConfig config2 =
1426       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1427   scoped_refptr<DnsSession> session2 = CreateDnsSession(config2);
1428 
1429   ResolveContext context(nullptr /* url_request_context */,
1430                          false /* enable_caching */);
1431   context.InvalidateCachesAndPerSessionData(session1.get(),
1432                                             true /* network_change */);
1433 
1434   // Confirm that if session data were used, the timeout would be higher than
1435   // the min. If timeout defaults are ever changed to break this assertion, then
1436   // the expected wrong-session timeout could be the same as an actual
1437   // from-session timeout, making this test seem to pass even if the behavior
1438   // under test were broken.
1439   base::TimeDelta multiplier_expected =
1440       kFallbackPeriod * features::kDnsTransactionTimeoutMultiplier.Get();
1441   ASSERT_GT(multiplier_expected, features::kDnsMinTransactionTimeout.Get());
1442 
1443   // Expect timeout always minimum with wrong session.
1444   EXPECT_EQ(context.ClassicTransactionTimeout(session2.get()),
1445             features::kDnsMinTransactionTimeout.Get());
1446 }
1447 
1448 // Ensures that reported negative RTT values don't cause a crash. Regression
1449 // test for https://crbug.com/753568.
TEST_F(ResolveContextTest,NegativeRtt)1450 TEST_F(ResolveContextTest, NegativeRtt) {
1451   ResolveContext context(nullptr /* url_request_context */,
1452                          false /* enable_caching */);
1453   DnsConfig config =
1454       CreateDnsConfig(2 /* num_servers */, 2 /* num_doh_servers */);
1455   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1456   context.InvalidateCachesAndPerSessionData(session.get(),
1457                                             false /* network_change */);
1458 
1459   context.RecordRtt(0 /* server_index */, false /* is_doh_server */,
1460                     base::Milliseconds(-1), OK /* rv */, session.get());
1461   context.RecordRtt(0 /* server_index */, true /* is_doh_server */,
1462                     base::Milliseconds(-1), OK /* rv */, session.get());
1463 }
1464 
TEST_F(ResolveContextTest,SessionChange)1465 TEST_F(ResolveContextTest, SessionChange) {
1466   ResolveContext context(nullptr /* url_request_context */,
1467                          false /* enable_caching */);
1468 
1469   TestDohStatusObserver observer;
1470   context.RegisterDohStatusObserver(&observer);
1471 
1472   DnsConfig config =
1473       CreateDnsConfig(2 /* num_servers */, 3 /* num_doh_servers */);
1474   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1475   context.InvalidateCachesAndPerSessionData(session.get(),
1476                                             false /* network_change */);
1477 
1478   EXPECT_EQ(observer.session_changes(), 1);
1479   // Should get a server unavailable notification because there is >0 DoH
1480   // servers that are reset on cache invalidation.
1481   EXPECT_EQ(observer.server_unavailable_notifications(), 1);
1482 
1483   context.UnregisterDohStatusObserver(&observer);
1484 }
1485 
TEST_F(ResolveContextTest,SessionChange_NoSession)1486 TEST_F(ResolveContextTest, SessionChange_NoSession) {
1487   ResolveContext context(nullptr /* url_request_context */,
1488                          false /* enable_caching */);
1489 
1490   TestDohStatusObserver observer;
1491   context.RegisterDohStatusObserver(&observer);
1492 
1493   context.InvalidateCachesAndPerSessionData(nullptr /* new_session */,
1494                                             false /* network_change */);
1495 
1496   EXPECT_EQ(observer.session_changes(), 1);
1497   EXPECT_EQ(observer.server_unavailable_notifications(), 0);
1498 
1499   context.UnregisterDohStatusObserver(&observer);
1500 }
1501 
TEST_F(ResolveContextTest,SessionChange_NoDohServers)1502 TEST_F(ResolveContextTest, SessionChange_NoDohServers) {
1503   ResolveContext context(nullptr /* url_request_context */,
1504                          false /* enable_caching */);
1505 
1506   TestDohStatusObserver observer;
1507   context.RegisterDohStatusObserver(&observer);
1508 
1509   DnsConfig config =
1510       CreateDnsConfig(2 /* num_servers */, 0 /* num_doh_servers */);
1511   scoped_refptr<DnsSession> session = CreateDnsSession(config);
1512   context.InvalidateCachesAndPerSessionData(session.get(),
1513                                             false /* network_change */);
1514 
1515   EXPECT_EQ(observer.session_changes(), 1);
1516   EXPECT_EQ(observer.server_unavailable_notifications(), 0);
1517 
1518   context.UnregisterDohStatusObserver(&observer);
1519 }
1520 
1521 }  // namespace
1522 }  // namespace net
1523