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