1 // Copyright 2012 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/host_cache.h"
6
7 #include <map>
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <string_view>
12 #include <utility>
13 #include <vector>
14
15 #include "base/format_macros.h"
16 #include "base/functional/bind.h"
17 #include "base/functional/callback.h"
18 #include "base/functional/callback_helpers.h"
19 #include "base/json/json_reader.h"
20 #include "base/json/json_writer.h"
21 #include "base/ranges/algorithm.h"
22 #include "base/strings/strcat.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/time/time.h"
27 #include "base/values.h"
28 #include "net/base/connection_endpoint_metadata.h"
29 #include "net/base/host_port_pair.h"
30 #include "net/base/ip_address.h"
31 #include "net/base/ip_endpoint.h"
32 #include "net/base/network_anonymization_key.h"
33 #include "net/base/schemeful_site.h"
34 #include "net/dns/host_resolver_internal_result.h"
35 #include "net/dns/host_resolver_results_test_util.h"
36 #include "net/dns/https_record_rdata.h"
37 #include "net/dns/public/host_resolver_results.h"
38 #include "testing/gmock/include/gmock/gmock.h"
39 #include "testing/gtest/include/gtest/gtest.h"
40 #include "url/gurl.h"
41 #include "url/scheme_host_port.h"
42 #include "url/url_constants.h"
43
44 using ::testing::_;
45 using ::testing::ElementsAre;
46 using ::testing::ElementsAreArray;
47 using ::testing::IsEmpty;
48 using ::testing::Optional;
49 using ::testing::Pair;
50 using ::testing::Pointee;
51 using ::testing::Property;
52 using ::testing::UnorderedElementsAre;
53
54 namespace net {
55
56 namespace {
57
58 const int kMaxCacheEntries = 10;
59
60 // Builds a key for |hostname|, defaulting the query type to unspecified.
Key(const std::string & hostname)61 HostCache::Key Key(const std::string& hostname) {
62 return HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, hostname, 443),
63 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
64 NetworkAnonymizationKey());
65 }
66
FoobarIndexIsOdd(const std::string & foobarx_com)67 bool FoobarIndexIsOdd(const std::string& foobarx_com) {
68 return (foobarx_com[6] - '0') % 2 == 1;
69 }
70
71 class MockPersistenceDelegate : public HostCache::PersistenceDelegate {
72 public:
ScheduleWrite()73 void ScheduleWrite() override { ++num_changes_; }
74
num_changes() const75 int num_changes() const { return num_changes_; }
76
77 private:
78 int num_changes_ = 0;
79 };
80
81 MATCHER_P(EntryContentsEqual,
82 entry,
83 base::StrCat({"contents ", negation ? "!=" : "==", " contents of ",
84 testing::PrintToString(entry)})) {
85 return arg.ContentsEqual(entry);
86 }
87
MakeIP(std::string_view literal)88 IPAddress MakeIP(std::string_view literal) {
89 IPAddress ret;
90 CHECK(ret.AssignFromIPLiteral(literal));
91 return ret;
92 }
93
MakeEndpoints(std::vector<std::string> my_addresses)94 std::vector<IPEndPoint> MakeEndpoints(std::vector<std::string> my_addresses) {
95 std::vector<IPEndPoint> out(my_addresses.size());
96 base::ranges::transform(my_addresses, out.begin(),
97 [](auto& s) { return IPEndPoint(MakeIP(s), 0); });
98 return out;
99 }
100
101 } // namespace
102
TEST(HostCacheTest,Basic)103 TEST(HostCacheTest, Basic) {
104 const base::TimeDelta kTTL = base::Seconds(10);
105
106 HostCache cache(kMaxCacheEntries);
107
108 // Start at t=0.
109 base::TimeTicks now;
110
111 HostCache::Key key1 = Key("foobar.com");
112 HostCache::Key key2 = Key("foobar2.com");
113 HostCache::Entry entry =
114 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{"foobar.com"},
115 HostCache::Entry::SOURCE_UNKNOWN);
116
117 EXPECT_EQ(0U, cache.size());
118
119 // Add an entry for "foobar.com" at t=0.
120 EXPECT_FALSE(cache.Lookup(key1, now));
121 cache.Set(key1, entry, now, kTTL);
122 EXPECT_TRUE(cache.Lookup(key1, now));
123 EXPECT_TRUE(cache.Lookup(key1, now)->second.error() == entry.error());
124
125 EXPECT_EQ(1U, cache.size());
126
127 // Advance to t=5.
128 now += base::Seconds(5);
129
130 // Add an entry for "foobar2.com" at t=5.
131 EXPECT_FALSE(cache.Lookup(key2, now));
132 cache.Set(key2, entry, now, kTTL);
133 EXPECT_TRUE(cache.Lookup(key2, now));
134 EXPECT_EQ(2U, cache.size());
135
136 // Advance to t=9
137 now += base::Seconds(4);
138
139 // Verify that the entries we added are still retrievable, and usable.
140 EXPECT_TRUE(cache.Lookup(key1, now));
141 EXPECT_TRUE(cache.Lookup(key2, now));
142 EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
143
144 // Advance to t=10; key is now expired.
145 now += base::Seconds(1);
146
147 EXPECT_FALSE(cache.Lookup(key1, now));
148 EXPECT_TRUE(cache.Lookup(key2, now));
149
150 // Update key1, so it is no longer expired.
151 cache.Set(key1, entry, now, kTTL);
152 EXPECT_TRUE(cache.Lookup(key1, now));
153 EXPECT_EQ(2U, cache.size());
154
155 // Both entries should still be retrievable and usable.
156 EXPECT_TRUE(cache.Lookup(key1, now));
157 EXPECT_TRUE(cache.Lookup(key2, now));
158
159 // Advance to t=20; both entries are now expired.
160 now += base::Seconds(10);
161
162 EXPECT_FALSE(cache.Lookup(key1, now));
163 EXPECT_FALSE(cache.Lookup(key2, now));
164 }
165
TEST(HostCacheTest,GetEndpoints)166 TEST(HostCacheTest, GetEndpoints) {
167 std::vector<IPEndPoint> ip_endpoints = {IPEndPoint(IPAddress(1, 1, 1, 1), 0),
168 IPEndPoint(IPAddress(2, 2, 2, 2), 0)};
169 HostCache::Entry entry(OK, ip_endpoints, /*aliases=*/{},
170 HostCache::Entry::SOURCE_DNS);
171
172 EXPECT_THAT(entry.GetEndpoints(),
173 ElementsAre(ExpectEndpointResult(ip_endpoints)));
174 }
175
TEST(HostCacheTest,GetEmptyEndpoints)176 TEST(HostCacheTest, GetEmptyEndpoints) {
177 HostCache::Entry entry(ERR_NAME_NOT_RESOLVED, /*ip_endpoints=*/{},
178 /*aliases=*/{}, HostCache::Entry::SOURCE_DNS);
179 EXPECT_THAT(entry.GetEndpoints(), IsEmpty());
180 }
181
TEST(HostCacheTest,GetEmptyEndpointsWithMetadata)182 TEST(HostCacheTest, GetEmptyEndpointsWithMetadata) {
183 HostCache::Entry entry(ERR_NAME_NOT_RESOLVED, /*ip_endpoints=*/{},
184 /*aliases=*/{}, HostCache::Entry::SOURCE_DNS);
185
186 // Merge in non-empty metadata.
187 ConnectionEndpointMetadata metadata;
188 metadata.supported_protocol_alpns = {"h3", "h2"};
189 HostCache::Entry metadata_entry(
190 OK,
191 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
192 {1u, metadata}},
193 HostCache::Entry::SOURCE_DNS);
194
195 auto merged_entry = HostCache::Entry::MergeEntries(entry, metadata_entry);
196
197 // Result should still be empty.
198 EXPECT_THAT(merged_entry.GetEndpoints(), IsEmpty());
199 }
200
TEST(HostCacheTest,GetMissingEndpoints)201 TEST(HostCacheTest, GetMissingEndpoints) {
202 HostCache::Entry entry(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
203 EXPECT_THAT(entry.GetEndpoints(), IsEmpty());
204 }
205
TEST(HostCacheTest,GetMissingEndpointsWithMetadata)206 TEST(HostCacheTest, GetMissingEndpointsWithMetadata) {
207 HostCache::Entry entry(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
208
209 // Merge in non-empty metadata.
210 ConnectionEndpointMetadata metadata;
211 metadata.supported_protocol_alpns = {"h3", "h2"};
212 HostCache::Entry metadata_entry(
213 OK,
214 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
215 {1u, metadata}},
216 HostCache::Entry::SOURCE_DNS);
217
218 auto merged_entry = HostCache::Entry::MergeEntries(entry, metadata_entry);
219
220 // Result should still be empty.
221 EXPECT_THAT(merged_entry.GetEndpoints(), IsEmpty());
222 }
223
224 // Test that Keys without scheme are allowed and treated as completely different
225 // from similar Keys with scheme.
TEST(HostCacheTest,HandlesKeysWithoutScheme)226 TEST(HostCacheTest, HandlesKeysWithoutScheme) {
227 const base::TimeDelta kTTL = base::Seconds(10);
228
229 HostCache cache(kMaxCacheEntries);
230
231 // t=0.
232 base::TimeTicks now;
233
234 HostCache::Key key("host1.test", DnsQueryType::UNSPECIFIED, 0,
235 HostResolverSource::ANY, NetworkAnonymizationKey());
236 HostCache::Key key_with_scheme(
237 url::SchemeHostPort(url::kHttpsScheme, "host1.test", 443),
238 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
239 NetworkAnonymizationKey());
240 ASSERT_NE(key, key_with_scheme);
241 HostCache::Entry entry =
242 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
243 HostCache::Entry::SOURCE_UNKNOWN);
244
245 ASSERT_EQ(0U, cache.size());
246 ASSERT_FALSE(cache.Lookup(key, now));
247 ASSERT_FALSE(cache.Lookup(key_with_scheme, now));
248
249 // Add entry for `key`.
250 cache.Set(key, entry, now, kTTL);
251 EXPECT_EQ(1U, cache.size());
252 EXPECT_TRUE(cache.Lookup(key, now));
253 EXPECT_FALSE(cache.Lookup(key_with_scheme, now));
254
255 // Add entry for `key_with_scheme`.
256 cache.Set(key_with_scheme, entry, now, kTTL);
257 EXPECT_EQ(2U, cache.size());
258 EXPECT_TRUE(cache.Lookup(key, now));
259 EXPECT_TRUE(cache.Lookup(key_with_scheme, now));
260
261 // Clear the cache and try adding in reverse order.
262 cache.clear();
263 ASSERT_EQ(0U, cache.size());
264 ASSERT_FALSE(cache.Lookup(key, now));
265 ASSERT_FALSE(cache.Lookup(key_with_scheme, now));
266
267 // Add entry for `key_with_scheme`.
268 cache.Set(key_with_scheme, entry, now, kTTL);
269 EXPECT_EQ(1U, cache.size());
270 EXPECT_FALSE(cache.Lookup(key, now));
271 EXPECT_TRUE(cache.Lookup(key_with_scheme, now));
272
273 // Add entry for `key`.
274 cache.Set(key, entry, now, kTTL);
275 EXPECT_EQ(2U, cache.size());
276 EXPECT_TRUE(cache.Lookup(key, now));
277 EXPECT_TRUE(cache.Lookup(key_with_scheme, now));
278 }
279
280 // Make sure NetworkAnonymizationKey is respected.
TEST(HostCacheTest,NetworkAnonymizationKey)281 TEST(HostCacheTest, NetworkAnonymizationKey) {
282 const url::SchemeHostPort kHost(url::kHttpsScheme, "hostname.test", 443);
283 const base::TimeDelta kTTL = base::Seconds(10);
284
285 const SchemefulSite kSite1(GURL("https://site1.test/"));
286 const auto kNetworkAnonymizationKey1 =
287 NetworkAnonymizationKey::CreateSameSite(kSite1);
288 const SchemefulSite kSite2(GURL("https://site2.test/"));
289 const auto kNetworkAnonymizationKey2 =
290 NetworkAnonymizationKey::CreateSameSite(kSite2);
291
292 HostCache::Key key1(kHost, DnsQueryType::UNSPECIFIED, 0,
293 HostResolverSource::ANY, kNetworkAnonymizationKey1);
294 HostCache::Key key2(kHost, DnsQueryType::UNSPECIFIED, 0,
295 HostResolverSource::ANY, kNetworkAnonymizationKey2);
296 HostCache::Entry entry1 =
297 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
298 HostCache::Entry::SOURCE_UNKNOWN);
299 HostCache::Entry entry2 =
300 HostCache::Entry(ERR_FAILED, /*ip_endpoints=*/{}, /*aliases=*/{},
301 HostCache::Entry::SOURCE_UNKNOWN);
302
303 HostCache cache(kMaxCacheEntries);
304
305 // Start at t=0.
306 base::TimeTicks now;
307
308 EXPECT_EQ(0U, cache.size());
309
310 // Add an entry for kNetworkAnonymizationKey1.
311 EXPECT_FALSE(cache.Lookup(key1, now));
312 cache.Set(key1, entry1, now, kTTL);
313
314 const std::pair<const HostCache::Key, HostCache::Entry>* result =
315 cache.Lookup(key1, now);
316 ASSERT_TRUE(result);
317 EXPECT_EQ(kNetworkAnonymizationKey1, result->first.network_anonymization_key);
318 EXPECT_EQ(OK, result->second.error());
319 EXPECT_FALSE(cache.Lookup(key2, now));
320 EXPECT_EQ(1U, cache.size());
321
322 // Add a different entry for kNetworkAnonymizationKey2.
323 cache.Set(key2, entry2, now, 3 * kTTL);
324 result = cache.Lookup(key1, now);
325 ASSERT_TRUE(result);
326 EXPECT_EQ(kNetworkAnonymizationKey1, result->first.network_anonymization_key);
327 EXPECT_EQ(OK, result->second.error());
328 result = cache.Lookup(key2, now);
329 ASSERT_TRUE(result);
330 EXPECT_EQ(kNetworkAnonymizationKey2, result->first.network_anonymization_key);
331 EXPECT_EQ(ERR_FAILED, result->second.error());
332 EXPECT_EQ(2U, cache.size());
333
334 // Advance time so that first entry times out. Second entry should remain.
335 now += 2 * kTTL;
336 EXPECT_FALSE(cache.Lookup(key1, now));
337 result = cache.Lookup(key2, now);
338 ASSERT_TRUE(result);
339 EXPECT_EQ(kNetworkAnonymizationKey2, result->first.network_anonymization_key);
340 EXPECT_EQ(ERR_FAILED, result->second.error());
341 }
342
343 // Try caching entries for a failed resolve attempt -- since we set the TTL of
344 // such entries to 0 it won't store, but it will kick out the previous result.
TEST(HostCacheTest,NoCacheZeroTTL)345 TEST(HostCacheTest, NoCacheZeroTTL) {
346 const base::TimeDelta kSuccessEntryTTL = base::Seconds(10);
347 const base::TimeDelta kFailureEntryTTL = base::Seconds(0);
348
349 HostCache cache(kMaxCacheEntries);
350
351 // Set t=0.
352 base::TimeTicks now;
353
354 HostCache::Key key1 = Key("foobar.com");
355 HostCache::Key key2 = Key("foobar2.com");
356 HostCache::Entry entry =
357 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
358 HostCache::Entry::SOURCE_UNKNOWN);
359
360 EXPECT_FALSE(cache.Lookup(key1, now));
361 cache.Set(key1, entry, now, kFailureEntryTTL);
362 EXPECT_EQ(1U, cache.size());
363
364 // We disallow use of negative entries.
365 EXPECT_FALSE(cache.Lookup(key1, now));
366
367 // Now overwrite with a valid entry, and then overwrite with negative entry
368 // again -- the valid entry should be kicked out.
369 cache.Set(key1, entry, now, kSuccessEntryTTL);
370 EXPECT_TRUE(cache.Lookup(key1, now));
371 cache.Set(key1, entry, now, kFailureEntryTTL);
372 EXPECT_FALSE(cache.Lookup(key1, now));
373 }
374
375 // Try caching entries for a failed resolves for 10 seconds.
TEST(HostCacheTest,CacheNegativeEntry)376 TEST(HostCacheTest, CacheNegativeEntry) {
377 const base::TimeDelta kFailureEntryTTL = base::Seconds(10);
378
379 HostCache cache(kMaxCacheEntries);
380
381 // Start at t=0.
382 base::TimeTicks now;
383
384 HostCache::Key key1 = Key("foobar.com");
385 HostCache::Key key2 = Key("foobar2.com");
386 HostCache::Entry entry =
387 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
388 HostCache::Entry::SOURCE_UNKNOWN);
389
390 EXPECT_EQ(0U, cache.size());
391
392 // Add an entry for "foobar.com" at t=0.
393 EXPECT_FALSE(cache.Lookup(key1, now));
394 cache.Set(key1, entry, now, kFailureEntryTTL);
395 EXPECT_TRUE(cache.Lookup(key1, now));
396 EXPECT_EQ(1U, cache.size());
397
398 // Advance to t=5.
399 now += base::Seconds(5);
400
401 // Add an entry for "foobar2.com" at t=5.
402 EXPECT_FALSE(cache.Lookup(key2, now));
403 cache.Set(key2, entry, now, kFailureEntryTTL);
404 EXPECT_TRUE(cache.Lookup(key2, now));
405 EXPECT_EQ(2U, cache.size());
406
407 // Advance to t=9
408 now += base::Seconds(4);
409
410 // Verify that the entries we added are still retrievable, and usable.
411 EXPECT_TRUE(cache.Lookup(key1, now));
412 EXPECT_TRUE(cache.Lookup(key2, now));
413
414 // Advance to t=10; key1 is now expired.
415 now += base::Seconds(1);
416
417 EXPECT_FALSE(cache.Lookup(key1, now));
418 EXPECT_TRUE(cache.Lookup(key2, now));
419
420 // Update key1, so it is no longer expired.
421 cache.Set(key1, entry, now, kFailureEntryTTL);
422 // Re-uses existing entry storage.
423 EXPECT_TRUE(cache.Lookup(key1, now));
424 EXPECT_EQ(2U, cache.size());
425
426 // Both entries should still be retrievable and usable.
427 EXPECT_TRUE(cache.Lookup(key1, now));
428 EXPECT_TRUE(cache.Lookup(key2, now));
429
430 // Advance to t=20; both entries are now expired.
431 now += base::Seconds(10);
432
433 EXPECT_FALSE(cache.Lookup(key1, now));
434 EXPECT_FALSE(cache.Lookup(key2, now));
435 }
436
437 // Tests that the same hostname can be duplicated in the cache, so long as
438 // the query type differs.
TEST(HostCacheTest,DnsQueryTypeIsPartOfKey)439 TEST(HostCacheTest, DnsQueryTypeIsPartOfKey) {
440 const base::TimeDelta kSuccessEntryTTL = base::Seconds(10);
441
442 HostCache cache(kMaxCacheEntries);
443
444 // t=0.
445 base::TimeTicks now;
446
447 HostCache::Key key1(url::SchemeHostPort(url::kHttpScheme, "foobar.com", 80),
448 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
449 NetworkAnonymizationKey());
450 HostCache::Key key2(url::SchemeHostPort(url::kHttpScheme, "foobar.com", 80),
451 DnsQueryType::A, 0, HostResolverSource::ANY,
452 NetworkAnonymizationKey());
453 HostCache::Entry entry =
454 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
455 HostCache::Entry::SOURCE_UNKNOWN);
456
457 EXPECT_EQ(0U, cache.size());
458
459 // Add an entry for ("foobar.com", UNSPECIFIED) at t=0.
460 EXPECT_FALSE(cache.Lookup(key1, now));
461 cache.Set(key1, entry, now, kSuccessEntryTTL);
462 EXPECT_TRUE(cache.Lookup(key1, now));
463 EXPECT_EQ(1U, cache.size());
464
465 // Add an entry for ("foobar.com", IPV4_ONLY) at t=0.
466 EXPECT_FALSE(cache.Lookup(key2, now));
467 cache.Set(key2, entry, now, kSuccessEntryTTL);
468 EXPECT_TRUE(cache.Lookup(key2, now));
469 EXPECT_EQ(2U, cache.size());
470
471 // Even though the hostnames were the same, we should have two unique
472 // entries (because the address families differ).
473 EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
474 }
475
476 // Tests that the same hostname can be duplicated in the cache, so long as
477 // the HostResolverFlags differ.
TEST(HostCacheTest,HostResolverFlagsArePartOfKey)478 TEST(HostCacheTest, HostResolverFlagsArePartOfKey) {
479 const url::SchemeHostPort kHost(url::kHttpsScheme, "foobar.test", 443);
480 const base::TimeDelta kTTL = base::Seconds(10);
481
482 HostCache cache(kMaxCacheEntries);
483
484 // t=0.
485 base::TimeTicks now;
486
487 HostCache::Key key1(kHost, DnsQueryType::A, 0, HostResolverSource::ANY,
488 NetworkAnonymizationKey());
489 HostCache::Key key2(kHost, DnsQueryType::A, HOST_RESOLVER_CANONNAME,
490 HostResolverSource::ANY, NetworkAnonymizationKey());
491 HostCache::Key key3(kHost, DnsQueryType::A, HOST_RESOLVER_LOOPBACK_ONLY,
492 HostResolverSource::ANY, NetworkAnonymizationKey());
493 HostCache::Entry entry =
494 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
495 HostCache::Entry::SOURCE_UNKNOWN);
496
497 EXPECT_EQ(0U, cache.size());
498
499 // Add an entry for ("foobar.com", IPV4, NONE) at t=0.
500 EXPECT_FALSE(cache.Lookup(key1, now));
501 cache.Set(key1, entry, now, kTTL);
502 EXPECT_TRUE(cache.Lookup(key1, now));
503 EXPECT_EQ(1U, cache.size());
504
505 // Add an entry for ("foobar.com", IPV4, CANONNAME) at t=0.
506 EXPECT_FALSE(cache.Lookup(key2, now));
507 cache.Set(key2, entry, now, kTTL);
508 EXPECT_TRUE(cache.Lookup(key2, now));
509 EXPECT_EQ(2U, cache.size());
510
511 // Add an entry for ("foobar.com", IPV4, LOOPBACK_ONLY) at t=0.
512 EXPECT_FALSE(cache.Lookup(key3, now));
513 cache.Set(key3, entry, now, kTTL);
514 EXPECT_TRUE(cache.Lookup(key3, now));
515 EXPECT_EQ(3U, cache.size());
516
517 // Even though the hostnames were the same, we should have two unique
518 // entries (because the HostResolverFlags differ).
519 EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
520 EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key3, now));
521 EXPECT_NE(cache.Lookup(key2, now), cache.Lookup(key3, now));
522 }
523
524 // Tests that the same hostname can be duplicated in the cache, so long as
525 // the HostResolverSource differs.
TEST(HostCacheTest,HostResolverSourceIsPartOfKey)526 TEST(HostCacheTest, HostResolverSourceIsPartOfKey) {
527 const url::SchemeHostPort kHost(url::kHttpsScheme, "foobar.test", 443);
528 const base::TimeDelta kSuccessEntryTTL = base::Seconds(10);
529
530 HostCache cache(kMaxCacheEntries);
531
532 // t=0.
533 base::TimeTicks now;
534
535 HostCache::Key key1(kHost, DnsQueryType::UNSPECIFIED, 0,
536 HostResolverSource::ANY, NetworkAnonymizationKey());
537 HostCache::Key key2(kHost, DnsQueryType::UNSPECIFIED, 0,
538 HostResolverSource::DNS, NetworkAnonymizationKey());
539 HostCache::Entry entry =
540 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
541 HostCache::Entry::SOURCE_UNKNOWN);
542
543 EXPECT_EQ(0U, cache.size());
544
545 // Add an entry for ("foobar.com", UNSPECIFIED, ANY) at t=0.
546 EXPECT_FALSE(cache.Lookup(key1, now));
547 cache.Set(key1, entry, now, kSuccessEntryTTL);
548 EXPECT_TRUE(cache.Lookup(key1, now));
549 EXPECT_EQ(1U, cache.size());
550
551 // Add an entry for ("foobar.com", UNSPECIFIED, DNS) at t=0.
552 EXPECT_FALSE(cache.Lookup(key2, now));
553 cache.Set(key2, entry, now, kSuccessEntryTTL);
554 EXPECT_TRUE(cache.Lookup(key2, now));
555 EXPECT_EQ(2U, cache.size());
556
557 // Even though the hostnames were the same, we should have two unique
558 // entries (because the HostResolverSource differs).
559 EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
560 }
561
562 // Tests that the same hostname can be duplicated in the cache, so long as
563 // the secure field in the key differs.
TEST(HostCacheTest,SecureIsPartOfKey)564 TEST(HostCacheTest, SecureIsPartOfKey) {
565 const url::SchemeHostPort kHost(url::kHttpsScheme, "foobar.test", 443);
566 const base::TimeDelta kSuccessEntryTTL = base::Seconds(10);
567
568 HostCache cache(kMaxCacheEntries);
569
570 // t=0.
571 base::TimeTicks now;
572 HostCache::EntryStaleness stale;
573
574 HostCache::Key key1(kHost, DnsQueryType::A, 0, HostResolverSource::ANY,
575 NetworkAnonymizationKey());
576 key1.secure = true;
577 HostCache::Key key2(kHost, DnsQueryType::A, 0, HostResolverSource::ANY,
578 NetworkAnonymizationKey());
579 key2.secure = false;
580 HostCache::Entry entry =
581 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
582 HostCache::Entry::SOURCE_UNKNOWN);
583
584 EXPECT_EQ(0U, cache.size());
585
586 // Add an entry for ("foobar.com", IPV4, true /* secure */) at t=0.
587 EXPECT_FALSE(cache.Lookup(key1, now));
588 cache.Set(key1, entry, now, kSuccessEntryTTL);
589 EXPECT_TRUE(cache.Lookup(key1, now));
590 EXPECT_EQ(1U, cache.size());
591
592 // Lookup a key that is identical to the inserted key except for the secure
593 // field.
594 EXPECT_FALSE(cache.Lookup(key2, now));
595 EXPECT_FALSE(cache.LookupStale(key2, now, &stale));
596 const std::pair<const HostCache::Key, HostCache::Entry>* result;
597 result = cache.Lookup(key2, now, true /* ignore_secure */);
598 EXPECT_TRUE(result);
599 EXPECT_TRUE(result->first.secure);
600 result = cache.LookupStale(key2, now, &stale, true /* ignore_secure */);
601 EXPECT_TRUE(result);
602 EXPECT_TRUE(result->first.secure);
603
604 // Add an entry for ("foobar.com", IPV4, false */ secure */) at t=0.
605 cache.Set(key2, entry, now, kSuccessEntryTTL);
606 EXPECT_TRUE(cache.Lookup(key2, now));
607 EXPECT_TRUE(cache.LookupStale(key2, now, &stale));
608 EXPECT_EQ(2U, cache.size());
609 }
610
TEST(HostCacheTest,PreferLessStaleMoreSecure)611 TEST(HostCacheTest, PreferLessStaleMoreSecure) {
612 const url::SchemeHostPort kHost(url::kHttpsScheme, "foobar.test", 443);
613 const base::TimeDelta kSuccessEntryTTL = base::Seconds(10);
614
615 HostCache cache(kMaxCacheEntries);
616
617 // t=0.
618 base::TimeTicks now;
619 HostCache::EntryStaleness stale;
620
621 HostCache::Key insecure_key(kHost, DnsQueryType::A, 0,
622 HostResolverSource::ANY,
623 NetworkAnonymizationKey());
624 HostCache::Key secure_key(kHost, DnsQueryType::A, 0, HostResolverSource::ANY,
625 NetworkAnonymizationKey());
626 secure_key.secure = true;
627 HostCache::Entry entry =
628 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
629 HostCache::Entry::SOURCE_UNKNOWN);
630
631 EXPECT_EQ(0U, cache.size());
632
633 // Add both insecure and secure entries.
634 cache.Set(insecure_key, entry, now, kSuccessEntryTTL);
635 cache.Set(secure_key, entry, now, kSuccessEntryTTL);
636 EXPECT_EQ(insecure_key, cache.Lookup(insecure_key, now)->first);
637 EXPECT_EQ(secure_key, cache.Lookup(secure_key, now)->first);
638 // Secure key is preferred when equally stale.
639 EXPECT_EQ(secure_key,
640 cache.Lookup(insecure_key, now, true /* ignore_secure */)->first);
641 EXPECT_EQ(secure_key,
642 cache.Lookup(insecure_key, now, true /* ignore_secure */)->first);
643
644 // Simulate network change.
645 cache.Invalidate();
646
647 // Re-add insecure entry.
648 cache.Set(insecure_key, entry, now, kSuccessEntryTTL);
649 EXPECT_EQ(insecure_key, cache.Lookup(insecure_key, now)->first);
650 EXPECT_FALSE(cache.Lookup(secure_key, now));
651 EXPECT_EQ(secure_key, cache.LookupStale(secure_key, now, &stale)->first);
652 // Result with fewer network changes is preferred.
653 EXPECT_EQ(
654 insecure_key,
655 cache.LookupStale(secure_key, now, &stale, true /* ignore-secure */)
656 ->first);
657
658 // Add both insecure and secure entries to a cleared cache, still at t=0.
659 cache.clear();
660 cache.Set(insecure_key, entry, now, base::Seconds(20));
661 cache.Set(secure_key, entry, now, kSuccessEntryTTL);
662
663 // Advance to t=15 to expire the secure entry only.
664 now += base::Seconds(15);
665 EXPECT_EQ(insecure_key, cache.Lookup(insecure_key, now)->first);
666 EXPECT_FALSE(cache.Lookup(secure_key, now));
667 EXPECT_EQ(secure_key, cache.LookupStale(secure_key, now, &stale)->first);
668 // Non-expired result is preferred.
669 EXPECT_EQ(
670 insecure_key,
671 cache.LookupStale(secure_key, now, &stale, true /* ignore-secure */)
672 ->first);
673 }
674
TEST(HostCacheTest,NoCache)675 TEST(HostCacheTest, NoCache) {
676 const base::TimeDelta kTTL = base::Seconds(10);
677
678 // Disable caching.
679 HostCache cache(0);
680 EXPECT_TRUE(cache.caching_is_disabled());
681
682 // Set t=0.
683 base::TimeTicks now;
684
685 HostCache::Entry entry =
686 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
687 HostCache::Entry::SOURCE_UNKNOWN);
688
689 // Lookup and Set should have no effect.
690 EXPECT_FALSE(cache.Lookup(Key("foobar.com"), now));
691 cache.Set(Key("foobar.com"), entry, now, kTTL);
692 EXPECT_FALSE(cache.Lookup(Key("foobar.com"), now));
693
694 EXPECT_EQ(0U, cache.size());
695 }
696
TEST(HostCacheTest,Clear)697 TEST(HostCacheTest, Clear) {
698 const base::TimeDelta kTTL = base::Seconds(10);
699
700 HostCache cache(kMaxCacheEntries);
701
702 // Set t=0.
703 base::TimeTicks now;
704
705 HostCache::Entry entry =
706 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
707 HostCache::Entry::SOURCE_UNKNOWN);
708
709 EXPECT_EQ(0u, cache.size());
710
711 // Add three entries.
712 cache.Set(Key("foobar1.com"), entry, now, kTTL);
713 cache.Set(Key("foobar2.com"), entry, now, kTTL);
714 cache.Set(Key("foobar3.com"), entry, now, kTTL);
715
716 EXPECT_EQ(3u, cache.size());
717
718 cache.clear();
719
720 EXPECT_EQ(0u, cache.size());
721 }
722
TEST(HostCacheTest,ClearForHosts)723 TEST(HostCacheTest, ClearForHosts) {
724 const base::TimeDelta kTTL = base::Seconds(10);
725
726 HostCache cache(kMaxCacheEntries);
727
728 // Set t=0.
729 base::TimeTicks now;
730
731 HostCache::Entry entry =
732 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
733 HostCache::Entry::SOURCE_UNKNOWN);
734
735 EXPECT_EQ(0u, cache.size());
736
737 // Add several entries.
738 cache.Set(Key("foobar1.com"), entry, now, kTTL);
739 cache.Set(Key("foobar2.com"), entry, now, kTTL);
740 cache.Set(Key("foobar3.com"), entry, now, kTTL);
741 cache.Set(Key("foobar4.com"), entry, now, kTTL);
742 cache.Set(Key("foobar5.com"), entry, now, kTTL);
743
744 EXPECT_EQ(5u, cache.size());
745
746 // Clear the hosts matching a certain predicate, such as the number being odd.
747 cache.ClearForHosts(base::BindRepeating(&FoobarIndexIsOdd));
748
749 EXPECT_EQ(2u, cache.size());
750 EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), now));
751 EXPECT_TRUE(cache.Lookup(Key("foobar4.com"), now));
752
753 // Passing null callback will delete all hosts.
754 cache.ClearForHosts(base::NullCallback());
755
756 EXPECT_EQ(0u, cache.size());
757 }
758
759 // Try to add too many entries to cache; it should evict the one with the oldest
760 // expiration time.
TEST(HostCacheTest,Evict)761 TEST(HostCacheTest, Evict) {
762 HostCache cache(2);
763
764 base::TimeTicks now;
765
766 HostCache::Key key1 = Key("foobar.com");
767 HostCache::Key key2 = Key("foobar2.com");
768 HostCache::Key key3 = Key("foobar3.com");
769 HostCache::Entry entry =
770 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
771 HostCache::Entry::SOURCE_UNKNOWN);
772
773 EXPECT_EQ(0u, cache.size());
774 EXPECT_FALSE(cache.Lookup(key1, now));
775 EXPECT_FALSE(cache.Lookup(key2, now));
776 EXPECT_FALSE(cache.Lookup(key3, now));
777
778 // |key1| expires in 10 seconds, but |key2| in just 5.
779 cache.Set(key1, entry, now, base::Seconds(10));
780 cache.Set(key2, entry, now, base::Seconds(5));
781 EXPECT_EQ(2u, cache.size());
782 EXPECT_TRUE(cache.Lookup(key1, now));
783 EXPECT_TRUE(cache.Lookup(key2, now));
784 EXPECT_FALSE(cache.Lookup(key3, now));
785
786 // |key2| should be chosen for eviction, since it expires sooner.
787 cache.Set(key3, entry, now, base::Seconds(10));
788 EXPECT_EQ(2u, cache.size());
789 EXPECT_TRUE(cache.Lookup(key1, now));
790 EXPECT_FALSE(cache.Lookup(key2, now));
791 EXPECT_TRUE(cache.Lookup(key3, now));
792 }
793
794 // Try to retrieve stale entries from the cache. They should be returned by
795 // |LookupStale()| but not |Lookup()|, with correct |EntryStaleness| data.
TEST(HostCacheTest,Stale)796 TEST(HostCacheTest, Stale) {
797 const base::TimeDelta kTTL = base::Seconds(10);
798
799 HostCache cache(kMaxCacheEntries);
800
801 // Start at t=0.
802 base::TimeTicks now;
803 HostCache::EntryStaleness stale;
804
805 HostCache::Key key = Key("foobar.com");
806 HostCache::Entry entry =
807 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
808 HostCache::Entry::SOURCE_UNKNOWN);
809
810 EXPECT_EQ(0U, cache.size());
811
812 // Add an entry for "foobar.com" at t=0.
813 EXPECT_FALSE(cache.Lookup(key, now));
814 EXPECT_FALSE(cache.LookupStale(key, now, &stale));
815 cache.Set(key, entry, now, kTTL);
816 EXPECT_TRUE(cache.Lookup(key, now));
817 EXPECT_TRUE(cache.LookupStale(key, now, &stale));
818 EXPECT_FALSE(stale.is_stale());
819 EXPECT_EQ(0, stale.stale_hits);
820
821 EXPECT_EQ(1U, cache.size());
822
823 // Advance to t=5.
824 now += base::Seconds(5);
825
826 EXPECT_TRUE(cache.Lookup(key, now));
827 EXPECT_TRUE(cache.LookupStale(key, now, &stale));
828 EXPECT_FALSE(stale.is_stale());
829 EXPECT_EQ(0, stale.stale_hits);
830
831 // Advance to t=15.
832 now += base::Seconds(10);
833
834 EXPECT_FALSE(cache.Lookup(key, now));
835 EXPECT_TRUE(cache.LookupStale(key, now, &stale));
836 EXPECT_TRUE(stale.is_stale());
837 EXPECT_EQ(base::Seconds(5), stale.expired_by);
838 EXPECT_EQ(0, stale.network_changes);
839 EXPECT_EQ(1, stale.stale_hits);
840
841 // Advance to t=20.
842 now += base::Seconds(5);
843
844 EXPECT_FALSE(cache.Lookup(key, now));
845 EXPECT_TRUE(cache.LookupStale(key, now, &stale));
846 EXPECT_TRUE(stale.is_stale());
847 EXPECT_EQ(base::Seconds(10), stale.expired_by);
848 EXPECT_EQ(0, stale.network_changes);
849 EXPECT_EQ(2, stale.stale_hits);
850
851 // Simulate network change.
852 cache.Invalidate();
853
854 EXPECT_FALSE(cache.Lookup(key, now));
855 EXPECT_TRUE(cache.LookupStale(key, now, &stale));
856 EXPECT_TRUE(stale.is_stale());
857 EXPECT_EQ(base::Seconds(10), stale.expired_by);
858 EXPECT_EQ(1, stale.network_changes);
859 EXPECT_EQ(3, stale.stale_hits);
860 }
861
TEST(HostCacheTest,EvictStale)862 TEST(HostCacheTest, EvictStale) {
863 HostCache cache(2);
864
865 base::TimeTicks now;
866 HostCache::EntryStaleness stale;
867
868 HostCache::Key key1 = Key("foobar.com");
869 HostCache::Key key2 = Key("foobar2.com");
870 HostCache::Key key3 = Key("foobar3.com");
871 HostCache::Entry entry =
872 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
873 HostCache::Entry::SOURCE_UNKNOWN);
874
875 EXPECT_EQ(0u, cache.size());
876 EXPECT_FALSE(cache.Lookup(key1, now));
877 EXPECT_FALSE(cache.Lookup(key2, now));
878 EXPECT_FALSE(cache.Lookup(key3, now));
879
880 // |key1| expires in 10 seconds.
881 cache.Set(key1, entry, now, base::Seconds(10));
882 EXPECT_EQ(1u, cache.size());
883 EXPECT_TRUE(cache.Lookup(key1, now));
884 EXPECT_FALSE(cache.Lookup(key2, now));
885 EXPECT_FALSE(cache.Lookup(key3, now));
886
887 // Simulate network change, expiring the cache.
888 cache.Invalidate();
889
890 EXPECT_EQ(1u, cache.size());
891 EXPECT_FALSE(cache.Lookup(key1, now));
892 EXPECT_TRUE(cache.LookupStale(key1, now, &stale));
893 EXPECT_EQ(1, stale.network_changes);
894
895 // Advance to t=1.
896 now += base::Seconds(1);
897
898 // |key2| expires before |key1| would originally have expired.
899 cache.Set(key2, entry, now, base::Seconds(5));
900 EXPECT_EQ(2u, cache.size());
901 EXPECT_FALSE(cache.Lookup(key1, now));
902 EXPECT_TRUE(cache.LookupStale(key1, now, &stale));
903 EXPECT_TRUE(cache.Lookup(key2, now));
904 EXPECT_FALSE(cache.Lookup(key3, now));
905
906 // |key1| should be chosen for eviction, since it is stale.
907 cache.Set(key3, entry, now, base::Seconds(1));
908 EXPECT_EQ(2u, cache.size());
909 EXPECT_FALSE(cache.Lookup(key1, now));
910 EXPECT_FALSE(cache.LookupStale(key1, now, &stale));
911 EXPECT_TRUE(cache.Lookup(key2, now));
912 EXPECT_TRUE(cache.Lookup(key3, now));
913
914 // Advance to t=6.
915 now += base::Seconds(5);
916
917 // Insert |key1| again. |key3| should be evicted.
918 cache.Set(key1, entry, now, base::Seconds(10));
919 EXPECT_EQ(2u, cache.size());
920 EXPECT_TRUE(cache.Lookup(key1, now));
921 EXPECT_FALSE(cache.Lookup(key2, now));
922 EXPECT_TRUE(cache.LookupStale(key2, now, &stale));
923 EXPECT_FALSE(cache.Lookup(key3, now));
924 EXPECT_FALSE(cache.LookupStale(key3, now, &stale));
925 }
926
927 // Pinned entries should not be evicted, even if the cache is full and the Entry
928 // has expired.
TEST(HostCacheTest,NoEvictPinned)929 TEST(HostCacheTest, NoEvictPinned) {
930 HostCache cache(2);
931
932 base::TimeTicks now;
933
934 HostCache::Key key1 = Key("foobar.com");
935 HostCache::Key key2 = Key("foobar2.com");
936 HostCache::Key key3 = Key("foobar3.com");
937 HostCache::Entry entry =
938 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
939 HostCache::Entry::SOURCE_UNKNOWN);
940 entry.set_pinning(true);
941
942 cache.Set(key1, entry, now, base::Seconds(5));
943 now += base::Seconds(10);
944 cache.Set(key2, entry, now, base::Seconds(5));
945 now += base::Seconds(10);
946 cache.Set(key3, entry, now, base::Seconds(5));
947
948 // There are 3 entries in this cache whose nominal max size is 2.
949 EXPECT_EQ(3u, cache.size());
950 EXPECT_TRUE(cache.LookupStale(key1, now, nullptr));
951 EXPECT_TRUE(cache.LookupStale(key2, now, nullptr));
952 EXPECT_TRUE(cache.Lookup(key3, now));
953 }
954
955 // Obsolete pinned entries should be evicted normally.
TEST(HostCacheTest,EvictObsoletePinned)956 TEST(HostCacheTest, EvictObsoletePinned) {
957 HostCache cache(2);
958
959 base::TimeTicks now;
960
961 HostCache::Key key1 = Key("foobar.com");
962 HostCache::Key key2 = Key("foobar2.com");
963 HostCache::Key key3 = Key("foobar3.com");
964 HostCache::Key key4 = Key("foobar4.com");
965 HostCache::Entry entry =
966 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
967 HostCache::Entry::SOURCE_UNKNOWN);
968 entry.set_pinning(true);
969
970 // |key2| should be preserved, since it expires later.
971 cache.Set(key1, entry, now, base::Seconds(5));
972 cache.Set(key2, entry, now, base::Seconds(10));
973 cache.Set(key3, entry, now, base::Seconds(5));
974 // There are 3 entries in this cache whose nominal max size is 2.
975 EXPECT_EQ(3u, cache.size());
976
977 cache.Invalidate();
978 // |Invalidate()| does not trigger eviction.
979 EXPECT_EQ(3u, cache.size());
980
981 // |Set()| triggers an eviction, leaving only |key2| in cache,
982 // before adding |key4|
983 cache.Set(key4, entry, now, base::Seconds(2));
984 EXPECT_EQ(2u, cache.size());
985 EXPECT_FALSE(cache.LookupStale(key1, now, nullptr));
986 EXPECT_TRUE(cache.LookupStale(key2, now, nullptr));
987 EXPECT_FALSE(cache.LookupStale(key3, now, nullptr));
988 EXPECT_TRUE(cache.LookupStale(key4, now, nullptr));
989 }
990
991 // An active pin is preserved if the record is
992 // replaced due to a Set() call without the pin.
TEST(HostCacheTest,PreserveActivePin)993 TEST(HostCacheTest, PreserveActivePin) {
994 HostCache cache(2);
995
996 base::TimeTicks now;
997
998 // Make entry1 and entry2, identical except for IP and pinned flag.
999 IPEndPoint endpoint1(IPAddress(192, 0, 2, 1), 0);
1000 IPEndPoint endpoint2(IPAddress(192, 0, 2, 2), 0);
1001 HostCache::Entry entry1 = HostCache::Entry(OK, {endpoint1}, /*aliases=*/{},
1002 HostCache::Entry::SOURCE_UNKNOWN);
1003 HostCache::Entry entry2 = HostCache::Entry(OK, {endpoint2}, /*aliases=*/{},
1004 HostCache::Entry::SOURCE_UNKNOWN);
1005 entry1.set_pinning(true);
1006
1007 HostCache::Key key = Key("foobar.com");
1008
1009 // Insert entry1, and verify that it can be retrieved with the
1010 // correct IP and |pinning()| == true.
1011 cache.Set(key, entry1, now, base::Seconds(10));
1012 const auto* pair1 = cache.Lookup(key, now);
1013 ASSERT_TRUE(pair1);
1014 const HostCache::Entry& result1 = pair1->second;
1015 EXPECT_THAT(result1.GetEndpoints(),
1016 ElementsAre(ExpectEndpointResult(ElementsAre(endpoint1))));
1017 EXPECT_THAT(result1.pinning(), Optional(true));
1018
1019 // Insert |entry2|, and verify that it when it is retrieved, it
1020 // has the new IP, and the "pinned" flag copied from |entry1|.
1021 cache.Set(key, entry2, now, base::Seconds(10));
1022 const auto* pair2 = cache.Lookup(key, now);
1023 ASSERT_TRUE(pair2);
1024 const HostCache::Entry& result2 = pair2->second;
1025 EXPECT_THAT(result2.GetEndpoints(),
1026 ElementsAre(ExpectEndpointResult(ElementsAre(endpoint2))));
1027 EXPECT_THAT(result2.pinning(), Optional(true));
1028 }
1029
1030 // An obsolete cache pin is not preserved if the record is replaced.
TEST(HostCacheTest,DontPreserveObsoletePin)1031 TEST(HostCacheTest, DontPreserveObsoletePin) {
1032 HostCache cache(2);
1033
1034 base::TimeTicks now;
1035
1036 // Make entry1 and entry2, identical except for IP and "pinned" flag.
1037 IPEndPoint endpoint1(IPAddress(192, 0, 2, 1), 0);
1038 IPEndPoint endpoint2(IPAddress(192, 0, 2, 2), 0);
1039 HostCache::Entry entry1 = HostCache::Entry(OK, {endpoint1}, /*aliases=*/{},
1040 HostCache::Entry::SOURCE_UNKNOWN);
1041 HostCache::Entry entry2 = HostCache::Entry(OK, {endpoint2}, /*aliases=*/{},
1042 HostCache::Entry::SOURCE_UNKNOWN);
1043 entry1.set_pinning(true);
1044
1045 HostCache::Key key = Key("foobar.com");
1046
1047 // Insert entry1, and verify that it can be retrieved with the
1048 // correct IP and |pinning()| == true.
1049 cache.Set(key, entry1, now, base::Seconds(10));
1050 const auto* pair1 = cache.Lookup(key, now);
1051 ASSERT_TRUE(pair1);
1052 const HostCache::Entry& result1 = pair1->second;
1053 EXPECT_THAT(result1.GetEndpoints(),
1054 ElementsAre(ExpectEndpointResult(ElementsAre(endpoint1))));
1055 EXPECT_THAT(result1.pinning(), Optional(true));
1056
1057 // Make entry1 obsolete.
1058 cache.Invalidate();
1059
1060 // Insert |entry2|, and verify that it when it is retrieved, it
1061 // has the new IP, and the "pinned" flag is not copied from |entry1|.
1062 cache.Set(key, entry2, now, base::Seconds(10));
1063 const auto* pair2 = cache.Lookup(key, now);
1064 ASSERT_TRUE(pair2);
1065 const HostCache::Entry& result2 = pair2->second;
1066 EXPECT_THAT(result2.GetEndpoints(),
1067 ElementsAre(ExpectEndpointResult(ElementsAre(endpoint2))));
1068 EXPECT_THAT(result2.pinning(), Optional(false));
1069 }
1070
1071 // An active pin is removed if the record is replaced by a Set() call
1072 // with the pin flag set to false.
TEST(HostCacheTest,Unpin)1073 TEST(HostCacheTest, Unpin) {
1074 HostCache cache(2);
1075
1076 base::TimeTicks now;
1077
1078 // Make entry1 and entry2, identical except for IP and pinned flag.
1079 IPEndPoint endpoint1(IPAddress(192, 0, 2, 1), 0);
1080 IPEndPoint endpoint2(IPAddress(192, 0, 2, 2), 0);
1081 HostCache::Entry entry1 = HostCache::Entry(OK, {endpoint1}, /*aliases=*/{},
1082 HostCache::Entry::SOURCE_UNKNOWN);
1083 HostCache::Entry entry2 = HostCache::Entry(OK, {endpoint2}, /*aliases=*/{},
1084 HostCache::Entry::SOURCE_UNKNOWN);
1085 entry1.set_pinning(true);
1086 entry2.set_pinning(false);
1087
1088 HostCache::Key key = Key("foobar.com");
1089
1090 // Insert entry1, and verify that it can be retrieved with the
1091 // correct IP and |pinning()| == true.
1092 cache.Set(key, entry1, now, base::Seconds(10));
1093 const auto* pair1 = cache.Lookup(key, now);
1094 ASSERT_TRUE(pair1);
1095 const HostCache::Entry& result1 = pair1->second;
1096 EXPECT_THAT(result1.GetEndpoints(),
1097 ElementsAre(ExpectEndpointResult(ElementsAre(endpoint1))));
1098 EXPECT_THAT(result1.pinning(), Optional(true));
1099
1100 // Insert |entry2|, and verify that it when it is retrieved, it
1101 // has the new IP, and the "pinned" flag is now false.
1102 cache.Set(key, entry2, now, base::Seconds(10));
1103 const auto* pair2 = cache.Lookup(key, now);
1104 ASSERT_TRUE(pair2);
1105 const HostCache::Entry& result2 = pair2->second;
1106 EXPECT_THAT(result2.GetEndpoints(),
1107 ElementsAre(ExpectEndpointResult(ElementsAre(endpoint2))));
1108 EXPECT_THAT(result2.pinning(), Optional(false));
1109 }
1110
1111 // Tests the less than and equal operators for HostCache::Key work.
TEST(HostCacheTest,KeyComparators)1112 TEST(HostCacheTest, KeyComparators) {
1113 struct CacheTestParameters {
1114 CacheTestParameters(const HostCache::Key key1,
1115 const HostCache::Key key2,
1116 int expected_comparison)
1117 : key1(key1), key2(key2), expected_comparison(expected_comparison) {}
1118
1119 // Inputs.
1120 HostCache::Key key1;
1121 HostCache::Key key2;
1122
1123 // Expectation.
1124 // -1 means key1 is less than key2
1125 // 0 means key1 equals key2
1126 // 1 means key1 is greater than key2
1127 int expected_comparison;
1128 };
1129 std::vector<CacheTestParameters> tests = {
1130 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1131 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1132 NetworkAnonymizationKey()),
1133 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1134 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1135 NetworkAnonymizationKey()),
1136 0},
1137 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1138 DnsQueryType::A, 0, HostResolverSource::ANY,
1139 NetworkAnonymizationKey()),
1140 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1141 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1142 NetworkAnonymizationKey()),
1143 1},
1144 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1145 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1146 NetworkAnonymizationKey()),
1147 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1148 DnsQueryType::A, 0, HostResolverSource::ANY,
1149 NetworkAnonymizationKey()),
1150 -1},
1151 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1152 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1153 NetworkAnonymizationKey()),
1154 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host2", 443),
1155 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1156 NetworkAnonymizationKey()),
1157 -1},
1158 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1159 DnsQueryType::A, 0, HostResolverSource::ANY,
1160 NetworkAnonymizationKey()),
1161 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host2", 443),
1162 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1163 NetworkAnonymizationKey()),
1164 1},
1165 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1166 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1167 NetworkAnonymizationKey()),
1168 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host2", 443),
1169 DnsQueryType::A, 0, HostResolverSource::ANY,
1170 NetworkAnonymizationKey()),
1171 -1},
1172 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1173 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1174 NetworkAnonymizationKey()),
1175 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1176 DnsQueryType::UNSPECIFIED, HOST_RESOLVER_CANONNAME,
1177 HostResolverSource::ANY, NetworkAnonymizationKey()),
1178 -1},
1179 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1180 DnsQueryType::UNSPECIFIED, HOST_RESOLVER_CANONNAME,
1181 HostResolverSource::ANY, NetworkAnonymizationKey()),
1182 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1183 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1184 NetworkAnonymizationKey()),
1185 1},
1186 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1187 DnsQueryType::UNSPECIFIED, HOST_RESOLVER_CANONNAME,
1188 HostResolverSource::ANY, NetworkAnonymizationKey()),
1189 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host2", 443),
1190 DnsQueryType::UNSPECIFIED, HOST_RESOLVER_CANONNAME,
1191 HostResolverSource::ANY, NetworkAnonymizationKey()),
1192 -1},
1193 // 9: Different host scheme.
1194 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1195 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1196 NetworkAnonymizationKey()),
1197 HostCache::Key(url::SchemeHostPort(url::kHttpScheme, "host1", 443),
1198 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1199 NetworkAnonymizationKey()),
1200 1},
1201 // 10: Different host port.
1202 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1203 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1204 NetworkAnonymizationKey()),
1205 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 1544),
1206 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1207 NetworkAnonymizationKey()),
1208 -1},
1209 // 11: Same host name without scheme/port.
1210 {HostCache::Key("host1", DnsQueryType::UNSPECIFIED, 0,
1211 HostResolverSource::ANY, NetworkAnonymizationKey()),
1212 HostCache::Key("host1", DnsQueryType::UNSPECIFIED, 0,
1213 HostResolverSource::ANY, NetworkAnonymizationKey()),
1214 0},
1215 // 12: Different host name without scheme/port.
1216 {HostCache::Key("host1", DnsQueryType::UNSPECIFIED, 0,
1217 HostResolverSource::ANY, NetworkAnonymizationKey()),
1218 HostCache::Key("host2", DnsQueryType::UNSPECIFIED, 0,
1219 HostResolverSource::ANY, NetworkAnonymizationKey()),
1220 -1},
1221 // 13: Only one with scheme/port.
1222 {HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1223 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1224 NetworkAnonymizationKey()),
1225 HostCache::Key("host1", DnsQueryType::UNSPECIFIED, 0,
1226 HostResolverSource::ANY, NetworkAnonymizationKey()),
1227 -1},
1228 };
1229 HostCache::Key insecure_key =
1230 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1231 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1232 NetworkAnonymizationKey());
1233 HostCache::Key secure_key =
1234 HostCache::Key(url::SchemeHostPort(url::kHttpsScheme, "host1", 443),
1235 DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY,
1236 NetworkAnonymizationKey());
1237 secure_key.secure = true;
1238 tests.emplace_back(insecure_key, secure_key, -1);
1239
1240 for (size_t i = 0; i < std::size(tests); ++i) {
1241 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
1242
1243 const HostCache::Key& key1 = tests[i].key1;
1244 const HostCache::Key& key2 = tests[i].key2;
1245
1246 switch (tests[i].expected_comparison) {
1247 case -1:
1248 EXPECT_TRUE(key1 < key2);
1249 EXPECT_FALSE(key2 < key1);
1250 break;
1251 case 0:
1252 EXPECT_FALSE(key1 < key2);
1253 EXPECT_FALSE(key2 < key1);
1254 break;
1255 case 1:
1256 EXPECT_FALSE(key1 < key2);
1257 EXPECT_TRUE(key2 < key1);
1258 break;
1259 default:
1260 FAIL() << "Invalid expectation. Can be only -1, 0, 1";
1261 }
1262 }
1263 }
1264
TEST(HostCacheTest,SerializeAndDeserializeWithExpirations)1265 TEST(HostCacheTest, SerializeAndDeserializeWithExpirations) {
1266 const base::TimeDelta kTTL = base::Seconds(10);
1267
1268 HostCache cache(kMaxCacheEntries);
1269
1270 // Start at t=0.
1271 base::TimeTicks now;
1272
1273 HostCache::Key expire_by_time_key = Key("expire.by.time.test");
1274 HostCache::Key expire_by_changes_key = Key("expire.by.changes.test");
1275
1276 IPEndPoint endpoint(IPAddress(1, 2, 3, 4), 0);
1277 HostCache::Entry entry = HostCache::Entry(OK, {endpoint}, /*aliases=*/{},
1278 HostCache::Entry::SOURCE_UNKNOWN);
1279
1280 EXPECT_EQ(0u, cache.size());
1281
1282 // Add an entry for `expire_by_time_key` at t=0.
1283 EXPECT_FALSE(cache.Lookup(expire_by_time_key, now));
1284 cache.Set(expire_by_time_key, entry, now, kTTL);
1285 EXPECT_THAT(cache.Lookup(expire_by_time_key, now),
1286 Pointee(Pair(expire_by_time_key, EntryContentsEqual(entry))));
1287
1288 EXPECT_EQ(1u, cache.size());
1289
1290 // Advance to t=5.
1291 now += base::Seconds(5);
1292
1293 // Add entry for `expire_by_changes_key` at t=5.
1294 EXPECT_FALSE(cache.Lookup(expire_by_changes_key, now));
1295 cache.Set(expire_by_changes_key, entry, now, kTTL);
1296 EXPECT_TRUE(cache.Lookup(expire_by_changes_key, now));
1297 EXPECT_EQ(2u, cache.size());
1298
1299 EXPECT_EQ(0u, cache.last_restore_size());
1300
1301 // Advance to t=12, and serialize/deserialize the cache.
1302 now += base::Seconds(7);
1303
1304 base::Value::List serialized_cache;
1305 cache.GetList(serialized_cache, false /* include_staleness */,
1306 HostCache::SerializationType::kRestorable);
1307 HostCache restored_cache(kMaxCacheEntries);
1308
1309 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1310
1311 HostCache::EntryStaleness stale;
1312
1313 // The `expire_by_time_key` entry is stale due to both network changes and
1314 // expiration time.
1315 EXPECT_FALSE(restored_cache.Lookup(expire_by_time_key, now));
1316 EXPECT_THAT(restored_cache.LookupStale(expire_by_time_key, now, &stale),
1317 Pointee(Pair(expire_by_time_key, EntryContentsEqual(entry))));
1318 EXPECT_EQ(1, stale.network_changes);
1319 // Time to TimeTicks conversion is fuzzy, so just check that expected and
1320 // actual expiration times are close.
1321 EXPECT_GT(base::Milliseconds(100),
1322 (base::Seconds(2) - stale.expired_by).magnitude());
1323
1324 // The `expire_by_changes_key` entry is stale only due to network changes.
1325 EXPECT_FALSE(restored_cache.Lookup(expire_by_changes_key, now));
1326 EXPECT_THAT(restored_cache.LookupStale(expire_by_changes_key, now, &stale),
1327 Pointee(Pair(expire_by_changes_key, EntryContentsEqual(entry))));
1328 EXPECT_EQ(1, stale.network_changes);
1329 EXPECT_GT(base::Milliseconds(100),
1330 (base::Seconds(-3) - stale.expired_by).magnitude());
1331
1332 EXPECT_EQ(2u, restored_cache.last_restore_size());
1333 }
1334
1335 // Test that any changes between serialization and restore are preferred over
1336 // old restored entries.
TEST(HostCacheTest,SerializeAndDeserializeWithChanges)1337 TEST(HostCacheTest, SerializeAndDeserializeWithChanges) {
1338 const base::TimeDelta kTTL = base::Seconds(10);
1339
1340 HostCache cache(kMaxCacheEntries);
1341
1342 // Start at t=0.
1343 base::TimeTicks now;
1344
1345 HostCache::Key to_serialize_key1 = Key("to.serialize1.test");
1346 HostCache::Key to_serialize_key2 = Key("to.serialize2.test");
1347 HostCache::Key other_key = Key("other.test");
1348
1349 IPEndPoint endpoint(IPAddress(1, 1, 1, 1), 0);
1350 HostCache::Entry serialized_entry = HostCache::Entry(
1351 OK, {endpoint}, /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1352
1353 IPEndPoint replacement_endpoint(IPAddress(2, 2, 2, 2), 0);
1354 HostCache::Entry replacement_entry =
1355 HostCache::Entry(OK, {replacement_endpoint}, /*aliases=*/{},
1356 HostCache::Entry::SOURCE_UNKNOWN);
1357
1358 IPEndPoint other_endpoint(IPAddress(3, 3, 3, 3), 0);
1359 HostCache::Entry other_entry = HostCache::Entry(
1360 OK, {other_endpoint}, /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1361
1362 EXPECT_EQ(0u, cache.size());
1363
1364 // Add `to_serialize_key1` and `to_serialize_key2`
1365 EXPECT_FALSE(cache.Lookup(to_serialize_key1, now));
1366 cache.Set(to_serialize_key1, serialized_entry, now, kTTL);
1367 EXPECT_THAT(
1368 cache.Lookup(to_serialize_key1, now),
1369 Pointee(Pair(to_serialize_key1, EntryContentsEqual(serialized_entry))));
1370 EXPECT_FALSE(cache.Lookup(to_serialize_key2, now));
1371 cache.Set(to_serialize_key2, serialized_entry, now, kTTL);
1372 EXPECT_THAT(
1373 cache.Lookup(to_serialize_key2, now),
1374 Pointee(Pair(to_serialize_key2, EntryContentsEqual(serialized_entry))));
1375 EXPECT_EQ(2u, cache.size());
1376
1377 // Serialize the cache.
1378 base::Value::List serialized_cache;
1379 cache.GetList(serialized_cache, false /* include_staleness */,
1380 HostCache::SerializationType::kRestorable);
1381 HostCache restored_cache(kMaxCacheEntries);
1382
1383 // Add entries for `to_serialize_key1` and `other_key` to the new cache
1384 // before restoring the serialized one. The `to_serialize_key1` result is
1385 // different from the original.
1386 EXPECT_FALSE(restored_cache.Lookup(to_serialize_key1, now));
1387 restored_cache.Set(to_serialize_key1, replacement_entry, now, kTTL);
1388 EXPECT_THAT(
1389 restored_cache.Lookup(to_serialize_key1, now),
1390 Pointee(Pair(to_serialize_key1, EntryContentsEqual(replacement_entry))));
1391 EXPECT_EQ(1u, restored_cache.size());
1392
1393 EXPECT_FALSE(restored_cache.Lookup(other_key, now));
1394 restored_cache.Set(other_key, other_entry, now, kTTL);
1395 EXPECT_THAT(restored_cache.Lookup(other_key, now),
1396 Pointee(Pair(other_key, EntryContentsEqual(other_entry))));
1397 EXPECT_EQ(2u, restored_cache.size());
1398
1399 EXPECT_EQ(0u, restored_cache.last_restore_size());
1400
1401 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1402 EXPECT_EQ(1u, restored_cache.last_restore_size());
1403
1404 HostCache::EntryStaleness stale;
1405
1406 // Expect `to_serialize_key1` has the replacement entry.
1407 EXPECT_THAT(
1408 restored_cache.Lookup(to_serialize_key1, now),
1409 Pointee(Pair(to_serialize_key1, EntryContentsEqual(replacement_entry))));
1410
1411 // Expect `to_serialize_key2` has the original entry.
1412 EXPECT_THAT(
1413 restored_cache.LookupStale(to_serialize_key2, now, &stale),
1414 Pointee(Pair(to_serialize_key2, EntryContentsEqual(serialized_entry))));
1415
1416 // Expect no change for `other_key`.
1417 EXPECT_THAT(restored_cache.Lookup(other_key, now),
1418 Pointee(Pair(other_key, EntryContentsEqual(other_entry))));
1419 }
1420
TEST(HostCacheTest,SerializeAndDeserializeAddresses)1421 TEST(HostCacheTest, SerializeAndDeserializeAddresses) {
1422 const base::TimeDelta kTTL = base::Seconds(10);
1423
1424 HostCache cache(kMaxCacheEntries);
1425
1426 // Start at t=0.
1427 base::TimeTicks now;
1428
1429 HostCache::Key key1 = Key("foobar.com");
1430 key1.secure = true;
1431 HostCache::Key key2 = Key("foobar2.com");
1432 HostCache::Key key3 = Key("foobar3.com");
1433 HostCache::Key key4 = Key("foobar4.com");
1434
1435 IPAddress address_ipv4(1, 2, 3, 4);
1436 IPAddress address_ipv6(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1437 IPEndPoint endpoint_ipv4(address_ipv4, 0);
1438 IPEndPoint endpoint_ipv6(address_ipv6, 0);
1439
1440 HostCache::Entry entry1 = HostCache::Entry(
1441 OK, {endpoint_ipv4}, /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1442 HostCache::Entry entry2 =
1443 HostCache::Entry(OK, {endpoint_ipv6, endpoint_ipv4}, /*aliases=*/{},
1444 HostCache::Entry::SOURCE_UNKNOWN);
1445 HostCache::Entry entry3 = HostCache::Entry(
1446 OK, {endpoint_ipv6}, /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1447 HostCache::Entry entry4 = HostCache::Entry(
1448 OK, {endpoint_ipv4}, /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1449
1450 EXPECT_EQ(0u, cache.size());
1451
1452 // Add an entry for "foobar.com" at t=0.
1453 EXPECT_FALSE(cache.Lookup(key1, now));
1454 cache.Set(key1, entry1, now, kTTL);
1455 EXPECT_TRUE(cache.Lookup(key1, now));
1456 EXPECT_TRUE(cache.Lookup(key1, now)->second.error() == entry1.error());
1457
1458 EXPECT_EQ(1u, cache.size());
1459
1460 // Advance to t=5.
1461 now += base::Seconds(5);
1462
1463 // Add entries for "foobar2.com" and "foobar3.com" at t=5.
1464 EXPECT_FALSE(cache.Lookup(key2, now));
1465 cache.Set(key2, entry2, now, kTTL);
1466 EXPECT_TRUE(cache.Lookup(key2, now));
1467 EXPECT_EQ(2u, cache.size());
1468
1469 EXPECT_FALSE(cache.Lookup(key3, now));
1470 cache.Set(key3, entry3, now, kTTL);
1471 EXPECT_TRUE(cache.Lookup(key3, now));
1472 EXPECT_EQ(3u, cache.size());
1473
1474 EXPECT_EQ(0u, cache.last_restore_size());
1475
1476 // Advance to t=12, ansd serialize the cache.
1477 now += base::Seconds(7);
1478
1479 base::Value::List serialized_cache;
1480 cache.GetList(serialized_cache, false /* include_staleness */,
1481 HostCache::SerializationType::kRestorable);
1482 HostCache restored_cache(kMaxCacheEntries);
1483
1484 // Add entries for "foobar3.com" and "foobar4.com" to the cache before
1485 // restoring it. The "foobar3.com" result is different from the original.
1486 EXPECT_FALSE(restored_cache.Lookup(key3, now));
1487 restored_cache.Set(key3, entry1, now, kTTL);
1488 EXPECT_TRUE(restored_cache.Lookup(key3, now));
1489 EXPECT_EQ(1u, restored_cache.size());
1490
1491 EXPECT_FALSE(restored_cache.Lookup(key4, now));
1492 restored_cache.Set(key4, entry4, now, kTTL);
1493 EXPECT_TRUE(restored_cache.Lookup(key4, now));
1494 EXPECT_EQ(2u, restored_cache.size());
1495
1496 EXPECT_EQ(0u, restored_cache.last_restore_size());
1497
1498 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1499
1500 HostCache::EntryStaleness stale;
1501
1502 // The "foobar.com" entry is stale due to both network changes and expiration
1503 // time.
1504 EXPECT_FALSE(restored_cache.Lookup(key1, now));
1505 const std::pair<const HostCache::Key, HostCache::Entry>* result1 =
1506 restored_cache.LookupStale(key1, now, &stale);
1507 EXPECT_TRUE(result1);
1508 EXPECT_TRUE(result1->first.secure);
1509 EXPECT_THAT(result1->second.text_records(), IsEmpty());
1510 EXPECT_THAT(result1->second.hostnames(), IsEmpty());
1511 EXPECT_EQ(1u, result1->second.ip_endpoints().size());
1512 EXPECT_EQ(endpoint_ipv4, result1->second.ip_endpoints().front());
1513 EXPECT_EQ(1, stale.network_changes);
1514 // Time to TimeTicks conversion is fuzzy, so just check that expected and
1515 // actual expiration times are close.
1516 EXPECT_GT(base::Milliseconds(100),
1517 (base::Seconds(2) - stale.expired_by).magnitude());
1518
1519 // The "foobar2.com" entry is stale only due to network changes.
1520 EXPECT_FALSE(restored_cache.Lookup(key2, now));
1521 const std::pair<const HostCache::Key, HostCache::Entry>* result2 =
1522 restored_cache.LookupStale(key2, now, &stale);
1523 EXPECT_TRUE(result2);
1524 EXPECT_FALSE(result2->first.secure);
1525 EXPECT_EQ(2u, result2->second.ip_endpoints().size());
1526 EXPECT_EQ(endpoint_ipv6, result2->second.ip_endpoints().front());
1527 EXPECT_EQ(endpoint_ipv4, result2->second.ip_endpoints().back());
1528 EXPECT_EQ(1, stale.network_changes);
1529 EXPECT_GT(base::Milliseconds(100),
1530 (base::Seconds(-3) - stale.expired_by).magnitude());
1531
1532 // The "foobar3.com" entry is the new one, not the restored one.
1533 const std::pair<const HostCache::Key, HostCache::Entry>* result3 =
1534 restored_cache.Lookup(key3, now);
1535 EXPECT_TRUE(result3);
1536 EXPECT_EQ(1u, result3->second.ip_endpoints().size());
1537 EXPECT_EQ(endpoint_ipv4, result3->second.ip_endpoints().front());
1538
1539 // The "foobar4.com" entry is still present and usable.
1540 const std::pair<const HostCache::Key, HostCache::Entry>* result4 =
1541 restored_cache.Lookup(key4, now);
1542 EXPECT_TRUE(result4);
1543 EXPECT_EQ(1u, result4->second.ip_endpoints().size());
1544 EXPECT_EQ(endpoint_ipv4, result4->second.ip_endpoints().front());
1545
1546 EXPECT_EQ(2u, restored_cache.last_restore_size());
1547 }
1548
TEST(HostCacheTest,SerializeAndDeserializeEntryWithoutScheme)1549 TEST(HostCacheTest, SerializeAndDeserializeEntryWithoutScheme) {
1550 const base::TimeDelta kTTL = base::Seconds(10);
1551
1552 HostCache::Key key("host.test", DnsQueryType::UNSPECIFIED, 0,
1553 HostResolverSource::ANY, NetworkAnonymizationKey());
1554 HostCache::Entry entry =
1555 HostCache::Entry(OK, /*ip_endpoints=*/{},
1556 /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1557
1558 base::TimeTicks now;
1559 HostCache cache(kMaxCacheEntries);
1560
1561 cache.Set(key, entry, now, kTTL);
1562 ASSERT_TRUE(cache.Lookup(key, now));
1563 ASSERT_EQ(cache.size(), 1u);
1564
1565 base::Value::List serialized_cache;
1566 cache.GetList(serialized_cache, /*include_staleness=*/false,
1567 HostCache::SerializationType::kRestorable);
1568 HostCache restored_cache(kMaxCacheEntries);
1569 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1570 EXPECT_EQ(restored_cache.size(), 1u);
1571
1572 HostCache::EntryStaleness staleness;
1573 EXPECT_THAT(restored_cache.LookupStale(key, now, &staleness),
1574 Pointee(Pair(key, EntryContentsEqual(entry))));
1575 }
1576
TEST(HostCacheTest,SerializeAndDeserializeWithNetworkAnonymizationKey)1577 TEST(HostCacheTest, SerializeAndDeserializeWithNetworkAnonymizationKey) {
1578 const url::SchemeHostPort kHost =
1579 url::SchemeHostPort(url::kHttpsScheme, "hostname.test", 443);
1580 const base::TimeDelta kTTL = base::Seconds(10);
1581 const SchemefulSite kSite(GURL("https://site.test/"));
1582 const auto kNetworkAnonymizationKey =
1583 NetworkAnonymizationKey::CreateSameSite(kSite);
1584 const SchemefulSite kOpaqueSite;
1585 const auto kOpaqueNetworkAnonymizationKey =
1586 NetworkAnonymizationKey::CreateSameSite(kOpaqueSite);
1587
1588 HostCache::Key key1(kHost, DnsQueryType::UNSPECIFIED, 0,
1589 HostResolverSource::ANY, kNetworkAnonymizationKey);
1590 HostCache::Key key2(kHost, DnsQueryType::UNSPECIFIED, 0,
1591 HostResolverSource::ANY, kOpaqueNetworkAnonymizationKey);
1592
1593 IPEndPoint endpoint(IPAddress(1, 2, 3, 4), 0);
1594 HostCache::Entry entry = HostCache::Entry(OK, {endpoint}, /*aliases=*/{},
1595 HostCache::Entry::SOURCE_UNKNOWN);
1596
1597 base::TimeTicks now;
1598 HostCache cache(kMaxCacheEntries);
1599
1600 cache.Set(key1, entry, now, kTTL);
1601 cache.Set(key2, entry, now, kTTL);
1602
1603 EXPECT_TRUE(cache.Lookup(key1, now));
1604 EXPECT_EQ(kNetworkAnonymizationKey,
1605 cache.Lookup(key1, now)->first.network_anonymization_key);
1606 EXPECT_TRUE(cache.Lookup(key2, now));
1607 EXPECT_EQ(kOpaqueNetworkAnonymizationKey,
1608 cache.Lookup(key2, now)->first.network_anonymization_key);
1609 EXPECT_EQ(2u, cache.size());
1610
1611 base::Value::List serialized_cache;
1612 cache.GetList(serialized_cache, false /* include_staleness */,
1613 HostCache::SerializationType::kRestorable);
1614 HostCache restored_cache(kMaxCacheEntries);
1615 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1616 EXPECT_EQ(1u, restored_cache.size());
1617
1618 HostCache::EntryStaleness stale;
1619 EXPECT_THAT(restored_cache.LookupStale(key1, now, &stale),
1620 Pointee(Pair(key1, EntryContentsEqual(entry))));
1621 EXPECT_FALSE(restored_cache.Lookup(key2, now));
1622 }
1623
TEST(HostCacheTest,SerializeForDebugging)1624 TEST(HostCacheTest, SerializeForDebugging) {
1625 const url::SchemeHostPort kHost(url::kHttpsScheme, "hostname.test", 443);
1626 const base::TimeDelta kTTL = base::Seconds(10);
1627 const NetworkAnonymizationKey kNetworkAnonymizationKey =
1628 NetworkAnonymizationKey::CreateTransient();
1629
1630 HostCache::Key key(kHost, DnsQueryType::UNSPECIFIED, 0,
1631 HostResolverSource::ANY, kNetworkAnonymizationKey);
1632
1633 IPEndPoint endpoint(IPAddress(1, 2, 3, 4), 0);
1634 HostCache::Entry entry = HostCache::Entry(OK, {endpoint}, /*aliases=*/{},
1635 HostCache::Entry::SOURCE_UNKNOWN);
1636
1637 base::TimeTicks now;
1638 HostCache cache(kMaxCacheEntries);
1639
1640 cache.Set(key, entry, now, kTTL);
1641
1642 EXPECT_TRUE(cache.Lookup(key, now));
1643 EXPECT_EQ(kNetworkAnonymizationKey,
1644 cache.Lookup(key, now)->first.network_anonymization_key);
1645 EXPECT_EQ(1u, cache.size());
1646
1647 base::Value::List serialized_cache;
1648 cache.GetList(serialized_cache, false /* include_staleness */,
1649 HostCache::SerializationType::kDebug);
1650 HostCache restored_cache(kMaxCacheEntries);
1651 EXPECT_FALSE(restored_cache.RestoreFromListValue(serialized_cache));
1652
1653 ASSERT_EQ(1u, serialized_cache.size());
1654 ASSERT_TRUE(serialized_cache[0].is_dict());
1655 const std::string* nak_string =
1656 serialized_cache[0].GetDict().FindString("network_anonymization_key");
1657 ASSERT_TRUE(nak_string);
1658 ASSERT_EQ(kNetworkAnonymizationKey.ToDebugString(), *nak_string);
1659 }
1660
TEST(HostCacheTest,SerializeAndDeserialize_Text)1661 TEST(HostCacheTest, SerializeAndDeserialize_Text) {
1662 base::TimeTicks now;
1663
1664 base::TimeDelta ttl = base::Seconds(99);
1665 std::vector<std::string> text_records({"foo", "bar"});
1666 HostCache::Key key(url::SchemeHostPort(url::kHttpsScheme, "example.com", 443),
1667 DnsQueryType::A, 0, HostResolverSource::DNS,
1668 NetworkAnonymizationKey());
1669 key.secure = true;
1670 HostCache::Entry entry(OK, text_records, HostCache::Entry::SOURCE_DNS, ttl);
1671 EXPECT_THAT(entry.text_records(), Not(IsEmpty()));
1672
1673 HostCache cache(kMaxCacheEntries);
1674 cache.Set(key, entry, now, ttl);
1675 EXPECT_EQ(1u, cache.size());
1676
1677 base::Value::List serialized_cache;
1678 cache.GetList(serialized_cache, false /* include_staleness */,
1679 HostCache::SerializationType::kRestorable);
1680 HostCache restored_cache(kMaxCacheEntries);
1681 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1682
1683 ASSERT_EQ(1u, serialized_cache.size());
1684 ASSERT_EQ(1u, restored_cache.size());
1685 HostCache::EntryStaleness stale;
1686 const std::pair<const HostCache::Key, HostCache::Entry>* result =
1687 restored_cache.LookupStale(key, now, &stale);
1688 EXPECT_THAT(result, Pointee(Pair(key, EntryContentsEqual(entry))));
1689 EXPECT_THAT(result->second.text_records(), text_records);
1690 }
1691
TEST(HostCacheTest,SerializeAndDeserialize_Hostname)1692 TEST(HostCacheTest, SerializeAndDeserialize_Hostname) {
1693 base::TimeTicks now;
1694
1695 base::TimeDelta ttl = base::Seconds(99);
1696 std::vector<HostPortPair> hostnames(
1697 {HostPortPair("example.com", 95), HostPortPair("chromium.org", 122)});
1698 HostCache::Key key(url::SchemeHostPort(url::kHttpsScheme, "example.com", 443),
1699 DnsQueryType::A, 0, HostResolverSource::DNS,
1700 NetworkAnonymizationKey());
1701 HostCache::Entry entry(OK, hostnames, HostCache::Entry::SOURCE_DNS, ttl);
1702 EXPECT_THAT(entry.hostnames(), Not(IsEmpty()));
1703
1704 HostCache cache(kMaxCacheEntries);
1705 cache.Set(key, entry, now, ttl);
1706 EXPECT_EQ(1u, cache.size());
1707
1708 base::Value::List serialized_cache;
1709 cache.GetList(serialized_cache, false /* include_staleness */,
1710 HostCache::SerializationType::kRestorable);
1711 HostCache restored_cache(kMaxCacheEntries);
1712 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1713
1714 ASSERT_EQ(1u, restored_cache.size());
1715 HostCache::EntryStaleness stale;
1716 const std::pair<const HostCache::Key, HostCache::Entry>* result =
1717 restored_cache.LookupStale(key, now, &stale);
1718 EXPECT_THAT(result, Pointee(Pair(key, EntryContentsEqual(entry))));
1719 EXPECT_THAT(result->second.hostnames(), hostnames);
1720 }
1721
TEST(HostCacheTest,SerializeAndDeserializeEndpointResult)1722 TEST(HostCacheTest, SerializeAndDeserializeEndpointResult) {
1723 base::TimeTicks now;
1724
1725 base::TimeDelta ttl = base::Seconds(99);
1726 HostCache::Key key(url::SchemeHostPort(url::kHttpsScheme, "example.com", 443),
1727 DnsQueryType::A, 0, HostResolverSource::DNS,
1728 NetworkAnonymizationKey());
1729 IPEndPoint ipv6_endpoint(
1730 IPAddress(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4), 110);
1731 IPEndPoint ipv4_endpoint1(IPAddress(1, 1, 1, 1), 80);
1732 IPEndPoint ipv4_endpoint2(IPAddress(2, 2, 2, 2), 90);
1733 IPEndPoint other_ipv4_endpoint(IPAddress(3, 3, 3, 3), 100);
1734 std::string ipv6_alias = "ipv6_alias.test";
1735 std::string ipv4_alias = "ipv4_alias.test";
1736 std::string other_alias = "other_alias.test";
1737 std::vector<IPEndPoint> ip_endpoints = {ipv6_endpoint, ipv4_endpoint1,
1738 ipv4_endpoint2, other_ipv4_endpoint};
1739 std::set<std::string> aliases = {ipv6_alias, ipv4_alias, other_alias};
1740 HostCache::Entry entry(OK, ip_endpoints, aliases,
1741 HostCache::Entry::SOURCE_DNS, ttl);
1742
1743 std::set<std::string> canonical_names = {ipv6_alias, ipv4_alias};
1744 entry.set_canonical_names(canonical_names);
1745
1746 EXPECT_THAT(entry.GetEndpoints(), Not(IsEmpty()));
1747
1748 ConnectionEndpointMetadata metadata1;
1749 metadata1.supported_protocol_alpns = {"h3", "h2"};
1750 metadata1.ech_config_list = {'f', 'o', 'o'};
1751 metadata1.target_name = ipv6_alias;
1752 ConnectionEndpointMetadata metadata2;
1753 metadata2.supported_protocol_alpns = {"h2", "h4"};
1754 metadata2.target_name = ipv4_alias;
1755 HostCache::Entry metadata_entry(
1756 OK,
1757 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
1758 {1u, metadata1}, {2u, metadata2}},
1759 HostCache::Entry::SOURCE_DNS);
1760
1761 auto merged_entry = HostCache::Entry::MergeEntries(entry, metadata_entry);
1762
1763 EXPECT_THAT(merged_entry.GetEndpoints(),
1764 ElementsAre(ExpectEndpointResult(ip_endpoints)));
1765 EXPECT_THAT(
1766 merged_entry.GetMetadatas(),
1767 testing::ElementsAre(
1768 ExpectConnectionEndpointMetadata(testing::ElementsAre("h3", "h2"),
1769 testing::ElementsAre('f', 'o', 'o'),
1770 ipv6_alias),
1771 ExpectConnectionEndpointMetadata(testing::ElementsAre("h2", "h4"),
1772 IsEmpty(), ipv4_alias)));
1773 EXPECT_THAT(merged_entry.canonical_names(),
1774 UnorderedElementsAre(ipv4_alias, ipv6_alias));
1775
1776 HostCache cache(kMaxCacheEntries);
1777 cache.Set(key, merged_entry, now, ttl);
1778 EXPECT_EQ(1u, cache.size());
1779
1780 base::Value::List serialized_cache;
1781 cache.GetList(serialized_cache, false /* include_staleness */,
1782 HostCache::SerializationType::kRestorable);
1783 HostCache restored_cache(kMaxCacheEntries);
1784 EXPECT_TRUE(restored_cache.RestoreFromListValue(serialized_cache));
1785
1786 // Check `serialized_cache` can be encoded as JSON. This ensures it has no
1787 // binary values.
1788 std::string json;
1789 EXPECT_TRUE(base::JSONWriter::Write(serialized_cache, &json));
1790
1791 ASSERT_EQ(1u, restored_cache.size());
1792 HostCache::EntryStaleness stale;
1793 const std::pair<const HostCache::Key, HostCache::Entry>* result =
1794 restored_cache.LookupStale(key, now, &stale);
1795
1796 ASSERT_TRUE(result);
1797 EXPECT_THAT(result, Pointee(Pair(key, EntryContentsEqual(merged_entry))));
1798 EXPECT_THAT(result->second.GetEndpoints(),
1799 ElementsAre(ExpectEndpointResult(ip_endpoints)));
1800 EXPECT_THAT(
1801 result->second.GetMetadatas(),
1802 testing::ElementsAre(
1803 ExpectConnectionEndpointMetadata(testing::ElementsAre("h3", "h2"),
1804 testing::ElementsAre('f', 'o', 'o'),
1805 ipv6_alias),
1806 ExpectConnectionEndpointMetadata(testing::ElementsAre("h2", "h4"),
1807 IsEmpty(), ipv4_alias)));
1808 EXPECT_THAT(result->second.canonical_names(),
1809 UnorderedElementsAre(ipv4_alias, ipv6_alias));
1810
1811 EXPECT_EQ(result->second.aliases(), aliases);
1812 }
1813
TEST(HostCacheTest,DeserializeNoEndpointNoAliase)1814 TEST(HostCacheTest, DeserializeNoEndpointNoAliase) {
1815 base::TimeDelta ttl = base::Seconds(99);
1816 std::string expiration_time_str = base::NumberToString(
1817 (base::Time::Now() + ttl).since_origin().InMicroseconds());
1818
1819 auto dict = base::JSONReader::Read(base::StringPrintf(
1820 R"(
1821 [ {
1822 "dns_query_type": 1,
1823 "expiration": "%s",
1824 "flags": 0,
1825 "host_resolver_source": 2,
1826 "hostname": "example.com",
1827 "network_anonymization_key": [ ],
1828 "port": 443,
1829 "scheme": "https",
1830 "secure": false
1831 } ]
1832 )",
1833 expiration_time_str.c_str()));
1834 ASSERT_TRUE(dict);
1835
1836 HostCache restored_cache(kMaxCacheEntries);
1837 ASSERT_TRUE(dict->is_list());
1838 EXPECT_TRUE(restored_cache.RestoreFromListValue(dict->GetList()));
1839
1840 ASSERT_EQ(1u, restored_cache.size());
1841
1842 HostCache::Key key(url::SchemeHostPort(url::kHttpsScheme, "example.com", 443),
1843 DnsQueryType::A, 0, HostResolverSource::DNS,
1844 NetworkAnonymizationKey());
1845
1846 HostCache::EntryStaleness stale;
1847 const std::pair<const HostCache::Key, HostCache::Entry>* result =
1848 restored_cache.LookupStale(key, base::TimeTicks::Now(), &stale);
1849
1850 ASSERT_TRUE(result);
1851 EXPECT_THAT(result->second.aliases(), ElementsAre());
1852 EXPECT_THAT(result->second.ip_endpoints(), ElementsAre());
1853 }
1854
TEST(HostCacheTest,DeserializeLegacyAddresses)1855 TEST(HostCacheTest, DeserializeLegacyAddresses) {
1856 base::TimeDelta ttl = base::Seconds(99);
1857 std::string expiration_time_str = base::NumberToString(
1858 (base::Time::Now() + ttl).since_origin().InMicroseconds());
1859
1860 auto dict = base::JSONReader::Read(base::StringPrintf(
1861 R"(
1862 [ {
1863 "addresses": [ "2000::", "1.2.3.4" ],
1864 "dns_query_type": 1,
1865 "expiration": "%s",
1866 "flags": 0,
1867 "host_resolver_source": 2,
1868 "hostname": "example.com",
1869 "network_anonymization_key": [ ],
1870 "port": 443,
1871 "scheme": "https",
1872 "secure": false
1873 } ]
1874 )",
1875 expiration_time_str.c_str()));
1876 ASSERT_TRUE(dict);
1877
1878 HostCache restored_cache(kMaxCacheEntries);
1879 ASSERT_TRUE(dict->is_list());
1880 EXPECT_TRUE(restored_cache.RestoreFromListValue(dict->GetList()));
1881
1882 ASSERT_EQ(1u, restored_cache.size());
1883
1884 HostCache::Key key(url::SchemeHostPort(url::kHttpsScheme, "example.com", 443),
1885 DnsQueryType::A, 0, HostResolverSource::DNS,
1886 NetworkAnonymizationKey());
1887
1888 HostCache::EntryStaleness stale;
1889 const std::pair<const HostCache::Key, HostCache::Entry>* result =
1890 restored_cache.LookupStale(key, base::TimeTicks::Now(), &stale);
1891
1892 ASSERT_TRUE(result);
1893 EXPECT_THAT(result->second.ip_endpoints(),
1894 ElementsAreArray(MakeEndpoints({"2000::", "1.2.3.4"})));
1895 EXPECT_THAT(result->second.aliases(), ElementsAre());
1896 }
1897
TEST(HostCacheTest,DeserializeInvalidQueryTypeIntegrity)1898 TEST(HostCacheTest, DeserializeInvalidQueryTypeIntegrity) {
1899 base::TimeDelta ttl = base::Seconds(99);
1900 std::string expiration_time_str = base::NumberToString(
1901 (base::Time::Now() + ttl).since_origin().InMicroseconds());
1902
1903 // RestoreFromListValue doesn't support dns_query_type=6 (INTEGRITY).
1904 auto dict = base::JSONReader::Read(base::StringPrintf(
1905 R"(
1906 [ {
1907 "addresses": [ "2000::", "1.2.3.4" ],
1908 "dns_query_type": 6,
1909 "expiration": "%s",
1910 "flags": 0,
1911 "host_resolver_source": 2,
1912 "hostname": "example.com",
1913 "network_anonymization_key": [ ],
1914 "port": 443,
1915 "scheme": "https",
1916 "secure": false
1917 } ]
1918 )",
1919 expiration_time_str.c_str()));
1920 ASSERT_TRUE(dict);
1921
1922 HostCache restored_cache(kMaxCacheEntries);
1923 ASSERT_TRUE(dict->is_list());
1924 EXPECT_FALSE(restored_cache.RestoreFromListValue(dict->GetList()));
1925
1926 ASSERT_EQ(0u, restored_cache.size());
1927 }
1928
TEST(HostCacheTest,DeserializeInvalidQueryTypeHttpsExperimental)1929 TEST(HostCacheTest, DeserializeInvalidQueryTypeHttpsExperimental) {
1930 base::TimeDelta ttl = base::Seconds(99);
1931 std::string expiration_time_str = base::NumberToString(
1932 (base::Time::Now() + ttl).since_origin().InMicroseconds());
1933
1934 // RestoreFromListValue doesn't support dns_query_type=8 (HTTPS_EXPERIMENTAL).
1935 auto dict = base::JSONReader::Read(base::StringPrintf(
1936 R"(
1937 [ {
1938 "addresses": [ "2000::", "1.2.3.4" ],
1939 "dns_query_type": 8,
1940 "expiration": "%s",
1941 "flags": 0,
1942 "host_resolver_source": 2,
1943 "hostname": "example.com",
1944 "network_anonymization_key": [ ],
1945 "port": 443,
1946 "scheme": "https",
1947 "secure": false
1948 } ]
1949 )",
1950 expiration_time_str.c_str()));
1951 ASSERT_TRUE(dict);
1952
1953 HostCache restored_cache(kMaxCacheEntries);
1954 ASSERT_TRUE(dict->is_list());
1955 EXPECT_FALSE(restored_cache.RestoreFromListValue(dict->GetList()));
1956
1957 ASSERT_EQ(0u, restored_cache.size());
1958 }
1959
TEST(HostCacheTest,PersistenceDelegate)1960 TEST(HostCacheTest, PersistenceDelegate) {
1961 const base::TimeDelta kTTL = base::Seconds(10);
1962 HostCache cache(kMaxCacheEntries);
1963 MockPersistenceDelegate delegate;
1964 cache.set_persistence_delegate(&delegate);
1965
1966 HostCache::Key key1 = Key("foobar.com");
1967 HostCache::Key key2 = Key("foobar2.com");
1968
1969 HostCache::Entry ok_entry =
1970 HostCache::Entry(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
1971 HostCache::Entry::SOURCE_UNKNOWN);
1972 std::vector<IPEndPoint> other_endpoints = {
1973 IPEndPoint(IPAddress(1, 1, 1, 1), 300)};
1974 HostCache::Entry other_entry(OK, std::move(other_endpoints), /*aliases=*/{},
1975 HostCache::Entry::SOURCE_UNKNOWN);
1976 HostCache::Entry error_entry =
1977 HostCache::Entry(ERR_NAME_NOT_RESOLVED, /*ip_endpoints=*/{},
1978 /*aliases=*/{}, HostCache::Entry::SOURCE_UNKNOWN);
1979
1980 // Start at t=0.
1981 base::TimeTicks now;
1982 EXPECT_EQ(0u, cache.size());
1983
1984 // Add two entries at t=0.
1985 EXPECT_FALSE(cache.Lookup(key1, now));
1986 cache.Set(key1, ok_entry, now, kTTL);
1987 EXPECT_TRUE(cache.Lookup(key1, now));
1988 EXPECT_EQ(1u, cache.size());
1989 EXPECT_EQ(1, delegate.num_changes());
1990
1991 EXPECT_FALSE(cache.Lookup(key2, now));
1992 cache.Set(key2, error_entry, now, kTTL);
1993 EXPECT_TRUE(cache.Lookup(key2, now));
1994 EXPECT_EQ(2u, cache.size());
1995 EXPECT_EQ(2, delegate.num_changes());
1996
1997 // Advance to t=5.
1998 now += base::Seconds(5);
1999
2000 // Changes that shouldn't trigger a write:
2001 // Add an entry for "foobar.com" with different expiration time.
2002 EXPECT_TRUE(cache.Lookup(key1, now));
2003 cache.Set(key1, ok_entry, now, kTTL);
2004 EXPECT_TRUE(cache.Lookup(key1, now));
2005 EXPECT_EQ(2u, cache.size());
2006 EXPECT_EQ(2, delegate.num_changes());
2007
2008 // Add an entry for "foobar.com" with different TTL.
2009 EXPECT_TRUE(cache.Lookup(key1, now));
2010 cache.Set(key1, ok_entry, now, kTTL - base::Seconds(5));
2011 EXPECT_TRUE(cache.Lookup(key1, now));
2012 EXPECT_EQ(2u, cache.size());
2013 EXPECT_EQ(2, delegate.num_changes());
2014
2015 // Changes that should trigger a write:
2016 // Add an entry for "foobar.com" with different address list.
2017 EXPECT_TRUE(cache.Lookup(key1, now));
2018 cache.Set(key1, other_entry, now, kTTL);
2019 EXPECT_TRUE(cache.Lookup(key1, now));
2020 EXPECT_EQ(2u, cache.size());
2021 EXPECT_EQ(3, delegate.num_changes());
2022
2023 // Add an entry for "foobar2.com" with different error.
2024 EXPECT_TRUE(cache.Lookup(key1, now));
2025 cache.Set(key2, ok_entry, now, kTTL);
2026 EXPECT_TRUE(cache.Lookup(key1, now));
2027 EXPECT_EQ(2u, cache.size());
2028 EXPECT_EQ(4, delegate.num_changes());
2029 }
2030
TEST(HostCacheTest,MergeEndpointsWithAliases)2031 TEST(HostCacheTest, MergeEndpointsWithAliases) {
2032 const IPAddress kAddressFront(1, 2, 3, 4);
2033 const IPEndPoint kEndpointFront(kAddressFront, 0);
2034 HostCache::Entry front(OK, {kEndpointFront}, {"alias1", "alias2", "alias3"},
2035 HostCache::Entry::SOURCE_DNS);
2036 front.set_text_records(std::vector<std::string>{"text1"});
2037 const HostPortPair kHostnameFront("host", 1);
2038 front.set_hostnames(std::vector<HostPortPair>{kHostnameFront});
2039
2040 const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2041 0);
2042 const IPEndPoint kEndpointBack(kAddressBack, 0);
2043 HostCache::Entry back(OK, {kEndpointBack}, {"alias2", "alias4", "alias5"},
2044 HostCache::Entry::SOURCE_DNS);
2045 back.set_text_records(std::vector<std::string>{"text2"});
2046 const HostPortPair kHostnameBack("host", 2);
2047 back.set_hostnames(std::vector<HostPortPair>{kHostnameBack});
2048
2049 HostCache::Entry result =
2050 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2051
2052 EXPECT_EQ(OK, result.error());
2053 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2054
2055 EXPECT_THAT(result.ip_endpoints(),
2056 ElementsAre(kEndpointFront, kEndpointBack));
2057 EXPECT_THAT(result.text_records(), ElementsAre("text1", "text2"));
2058
2059 EXPECT_THAT(result.hostnames(), ElementsAre(kHostnameFront, kHostnameBack));
2060
2061 EXPECT_THAT(
2062 result.aliases(),
2063 UnorderedElementsAre("alias1", "alias2", "alias3", "alias4", "alias5"));
2064 }
2065
TEST(HostCacheTest,MergeEndpointsKeepEndpointsOrder)2066 TEST(HostCacheTest, MergeEndpointsKeepEndpointsOrder) {
2067 std::vector<IPEndPoint> front_addresses =
2068 MakeEndpoints({"::1", "0.0.0.2", "0.0.0.4"});
2069 std::vector<IPEndPoint> back_addresses =
2070 MakeEndpoints({"0.0.0.2", "0.0.0.2", "::3", "::3", "0.0.0.4"});
2071
2072 HostCache::Entry front(OK, front_addresses, /*aliases=*/{"front"},
2073 HostCache::Entry::SOURCE_DNS);
2074 HostCache::Entry back(OK, back_addresses, /*aliases=*/{"back"},
2075 HostCache::Entry::SOURCE_DNS);
2076
2077 HostCache::Entry result =
2078 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2079
2080 EXPECT_THAT(
2081 result.ip_endpoints(),
2082 ElementsAreArray(MakeEndpoints({"::1", "0.0.0.2", "0.0.0.4", "0.0.0.2",
2083 "0.0.0.2", "::3", "::3", "0.0.0.4"})));
2084 EXPECT_THAT(result.aliases(), UnorderedElementsAre("front", "back"));
2085 }
2086
TEST(HostCacheTest,MergeMetadatas)2087 TEST(HostCacheTest, MergeMetadatas) {
2088 ConnectionEndpointMetadata front_metadata;
2089 front_metadata.supported_protocol_alpns = {"h5", "h6", "monster truck rally"};
2090 front_metadata.ech_config_list = {'h', 'i'};
2091 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>
2092 front_metadata_map{{4u, front_metadata}};
2093 HostCache::Entry front(OK, front_metadata_map, HostCache::Entry::SOURCE_DNS);
2094
2095 ConnectionEndpointMetadata back_metadata;
2096 back_metadata.supported_protocol_alpns = {"h5"};
2097 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>
2098 back_metadata_map{{2u, back_metadata}};
2099 HostCache::Entry back(OK, back_metadata_map, HostCache::Entry::SOURCE_DNS);
2100
2101 HostCache::Entry result = HostCache::Entry::MergeEntries(front, back);
2102
2103 // Expect `GetEndpoints()` to ignore metadatas if no `IPEndPoint`s.
2104 EXPECT_THAT(result.GetEndpoints(), IsEmpty());
2105
2106 // Expect order irrelevant for endpoint metadata merging.
2107 result = HostCache::Entry::MergeEntries(back, front);
2108 EXPECT_THAT(result.GetEndpoints(), IsEmpty());
2109 }
2110
TEST(HostCacheTest,MergeMetadatasWithIpEndpointsDifferentCanonicalName)2111 TEST(HostCacheTest, MergeMetadatasWithIpEndpointsDifferentCanonicalName) {
2112 std::string target_name = "example.com";
2113 std::string other_target_name = "other.example.com";
2114 ConnectionEndpointMetadata metadata;
2115 metadata.supported_protocol_alpns = {"h5", "h6", "monster truck rally"};
2116 metadata.ech_config_list = {'h', 'i'};
2117 metadata.target_name = target_name;
2118
2119 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata> metadata_map{
2120 {4u, metadata}};
2121 HostCache::Entry metadata_entry(OK, metadata_map,
2122 HostCache::Entry::SOURCE_DNS);
2123
2124 // Expect `GetEndpoints()` to always ignore metadatas with no `IPEndPoint`s.
2125 EXPECT_THAT(metadata_entry.GetEndpoints(), IsEmpty());
2126
2127 // Merge in an `IPEndPoint` with different canonical name.
2128 IPEndPoint ip_endpoint(IPAddress(1, 1, 1, 1), 0);
2129 HostCache::Entry with_ip_endpoint(OK, {ip_endpoint}, /*aliases=*/{},
2130 HostCache::Entry::SOURCE_DNS);
2131 with_ip_endpoint.set_canonical_names(
2132 std::set<std::string>{other_target_name});
2133 HostCache::Entry result =
2134 HostCache::Entry::MergeEntries(metadata_entry, with_ip_endpoint);
2135
2136 // Expect `GetEndpoints()` not to return the metadata.
2137 EXPECT_THAT(
2138 result.GetEndpoints(),
2139 ElementsAre(ExpectEndpointResult(std::vector<IPEndPoint>{ip_endpoint})));
2140
2141 // Expect merge order irrelevant.
2142 EXPECT_EQ(result,
2143 HostCache::Entry::MergeEntries(with_ip_endpoint, metadata_entry));
2144 }
2145
TEST(HostCacheTest,MergeMetadatasWithIpEndpointsMatchingCanonicalName)2146 TEST(HostCacheTest, MergeMetadatasWithIpEndpointsMatchingCanonicalName) {
2147 std::string target_name = "example.com";
2148 ConnectionEndpointMetadata metadata;
2149 metadata.supported_protocol_alpns = {"h5", "h6", "monster truck rally"};
2150 metadata.ech_config_list = {'h', 'i'};
2151 metadata.target_name = target_name;
2152
2153 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata> metadata_map{
2154 {4u, metadata}};
2155 HostCache::Entry metadata_entry(OK, metadata_map,
2156 HostCache::Entry::SOURCE_DNS);
2157
2158 // Expect `GetEndpoints()` to always ignore metadatas with no `IPEndPoint`s.
2159 EXPECT_THAT(metadata_entry.GetEndpoints(), IsEmpty());
2160
2161 // Merge in an `IPEndPoint` with different canonical name.
2162 IPEndPoint ip_endpoint(IPAddress(1, 1, 1, 1), 0);
2163 HostCache::Entry with_ip_endpoint(OK, {ip_endpoint}, /*aliases=*/{},
2164 HostCache::Entry::SOURCE_DNS);
2165 with_ip_endpoint.set_canonical_names(std::set<std::string>{target_name});
2166 HostCache::Entry result =
2167 HostCache::Entry::MergeEntries(metadata_entry, with_ip_endpoint);
2168
2169 // Expect `GetEndpoints()` to return the metadata.
2170 EXPECT_THAT(
2171 result.GetEndpoints(),
2172 ElementsAre(ExpectEndpointResult(ElementsAre(ip_endpoint), metadata),
2173 ExpectEndpointResult(ElementsAre(ip_endpoint))));
2174
2175 // Expect merge order irrelevant.
2176 EXPECT_EQ(result,
2177 HostCache::Entry::MergeEntries(with_ip_endpoint, metadata_entry));
2178 }
2179
TEST(HostCacheTest,MergeMultipleMetadatasWithIpEndpoints)2180 TEST(HostCacheTest, MergeMultipleMetadatasWithIpEndpoints) {
2181 std::string target_name = "example.com";
2182 ConnectionEndpointMetadata front_metadata;
2183 front_metadata.supported_protocol_alpns = {"h5", "h6", "monster truck rally"};
2184 front_metadata.ech_config_list = {'h', 'i'};
2185 front_metadata.target_name = target_name;
2186
2187 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>
2188 front_metadata_map{{4u, front_metadata}};
2189 HostCache::Entry front(OK, front_metadata_map, HostCache::Entry::SOURCE_DNS);
2190
2191 ConnectionEndpointMetadata back_metadata;
2192 back_metadata.supported_protocol_alpns = {"h5"};
2193 back_metadata.target_name = target_name;
2194 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>
2195 back_metadata_map{{2u, back_metadata}};
2196 HostCache::Entry back(OK, back_metadata_map, HostCache::Entry::SOURCE_DNS);
2197
2198 HostCache::Entry merged_metadatas =
2199 HostCache::Entry::MergeEntries(front, back);
2200 HostCache::Entry reversed_merged_metadatas =
2201 HostCache::Entry::MergeEntries(back, front);
2202
2203 // Expect `GetEndpoints()` to always ignore metadatas with no `IPEndPoint`s.
2204 EXPECT_THAT(merged_metadatas.GetEndpoints(), IsEmpty());
2205 EXPECT_THAT(reversed_merged_metadatas.GetEndpoints(), IsEmpty());
2206
2207 // Merge in an `IPEndPoint`.
2208 IPEndPoint ip_endpoint(IPAddress(1, 1, 1, 1), 0);
2209 HostCache::Entry with_ip_endpoint(OK, {ip_endpoint}, /*aliases=*/{},
2210 HostCache::Entry::SOURCE_DNS);
2211 with_ip_endpoint.set_canonical_names(std::set<std::string>{target_name});
2212
2213 HostCache::Entry result =
2214 HostCache::Entry::MergeEntries(merged_metadatas, with_ip_endpoint);
2215
2216 // Expect `back_metadata` before `front_metadata` because it has lower
2217 // priority number.
2218 EXPECT_THAT(
2219 result.GetEndpoints(),
2220 ElementsAre(
2221 ExpectEndpointResult(ElementsAre(ip_endpoint), back_metadata),
2222 ExpectEndpointResult(ElementsAre(ip_endpoint), front_metadata),
2223 ExpectEndpointResult(ElementsAre(ip_endpoint))));
2224
2225 // Expect merge order irrelevant.
2226 EXPECT_EQ(result, HostCache::Entry::MergeEntries(reversed_merged_metadatas,
2227 with_ip_endpoint));
2228 EXPECT_EQ(result,
2229 HostCache::Entry::MergeEntries(with_ip_endpoint, merged_metadatas));
2230 EXPECT_EQ(result, HostCache::Entry::MergeEntries(with_ip_endpoint,
2231 reversed_merged_metadatas));
2232 }
2233
TEST(HostCacheTest,MergeAliases)2234 TEST(HostCacheTest, MergeAliases) {
2235 HostCache::Entry front(OK, /*ip_endpoints=*/{},
2236 /*aliases=*/{"foo1.test", "foo2.test", "foo3.test"},
2237 HostCache::Entry::SOURCE_DNS);
2238
2239 HostCache::Entry back(OK, /*ip_endpoints=*/{},
2240 /*aliases=*/{"foo2.test", "foo4.test"},
2241 HostCache::Entry::SOURCE_DNS);
2242
2243 HostCache::Entry expected(
2244 OK, /*ip_endpoints=*/{},
2245 /*aliases=*/{"foo1.test", "foo2.test", "foo3.test", "foo4.test"},
2246 HostCache::Entry::SOURCE_DNS);
2247
2248 HostCache::Entry result = HostCache::Entry::MergeEntries(front, back);
2249 EXPECT_EQ(result, expected);
2250
2251 // Expect order irrelevant for alias merging.
2252 result = HostCache::Entry::MergeEntries(back, front);
2253 EXPECT_EQ(result, expected);
2254 }
2255
TEST(HostCacheTest,MergeEntries_frontEmpty)2256 TEST(HostCacheTest, MergeEntries_frontEmpty) {
2257 HostCache::Entry front(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
2258
2259 const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2260 0);
2261 const IPEndPoint kEndpointBack(kAddressBack, 0);
2262 HostCache::Entry back(OK, {kEndpointBack}, {"alias1", "alias2", "alias3"},
2263 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2264 back.set_text_records(std::vector<std::string>{"text2"});
2265 const HostPortPair kHostnameBack("host", 2);
2266 back.set_hostnames(std::vector<HostPortPair>{kHostnameBack});
2267
2268 HostCache::Entry result =
2269 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2270
2271 EXPECT_EQ(OK, result.error());
2272 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2273
2274 EXPECT_THAT(result.ip_endpoints(), ElementsAre(kEndpointBack));
2275 EXPECT_THAT(result.text_records(), ElementsAre("text2"));
2276 EXPECT_THAT(result.hostnames(), ElementsAre(kHostnameBack));
2277
2278 EXPECT_EQ(base::Hours(4), result.ttl());
2279
2280 EXPECT_THAT(result.aliases(),
2281 UnorderedElementsAre("alias1", "alias2", "alias3"));
2282 }
2283
TEST(HostCacheTest,MergeEntries_backEmpty)2284 TEST(HostCacheTest, MergeEntries_backEmpty) {
2285 const IPAddress kAddressFront(1, 2, 3, 4);
2286 const IPEndPoint kEndpointFront(kAddressFront, 0);
2287 HostCache::Entry front(OK, {kEndpointFront}, {"alias1", "alias2", "alias3"},
2288 HostCache::Entry::SOURCE_DNS, base::Minutes(5));
2289 front.set_text_records(std::vector<std::string>{"text1"});
2290 const HostPortPair kHostnameFront("host", 1);
2291 front.set_hostnames(std::vector<HostPortPair>{kHostnameFront});
2292
2293 HostCache::Entry back(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
2294
2295 HostCache::Entry result =
2296 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2297
2298 EXPECT_EQ(OK, result.error());
2299 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2300
2301 EXPECT_THAT(result.ip_endpoints(), ElementsAre(kEndpointFront));
2302 EXPECT_THAT(result.text_records(), ElementsAre("text1"));
2303 EXPECT_THAT(result.hostnames(), ElementsAre(kHostnameFront));
2304
2305 EXPECT_EQ(base::Minutes(5), result.ttl());
2306
2307 EXPECT_THAT(result.aliases(),
2308 UnorderedElementsAre("alias1", "alias2", "alias3"));
2309 }
2310
TEST(HostCacheTest,MergeEntries_bothEmpty)2311 TEST(HostCacheTest, MergeEntries_bothEmpty) {
2312 HostCache::Entry front(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
2313 HostCache::Entry back(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
2314
2315 HostCache::Entry result =
2316 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2317
2318 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, result.error());
2319 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2320
2321 EXPECT_THAT(result.ip_endpoints(), IsEmpty());
2322 EXPECT_THAT(result.text_records(), IsEmpty());
2323 EXPECT_THAT(result.hostnames(), IsEmpty());
2324 EXPECT_FALSE(result.has_ttl());
2325 }
2326
TEST(HostCacheTest,MergeEntries_frontWithAliasesNoAddressesBackWithBoth)2327 TEST(HostCacheTest, MergeEntries_frontWithAliasesNoAddressesBackWithBoth) {
2328 HostCache::Entry front(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
2329 std::set<std::string> aliases_front({"alias0", "alias1", "alias2"});
2330 front.set_aliases(aliases_front);
2331
2332 const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2333 0);
2334 const IPEndPoint kEndpointBack(kAddressBack, 0);
2335 HostCache::Entry back(OK, {kEndpointBack}, {"alias1", "alias2", "alias3"},
2336 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2337
2338 HostCache::Entry result =
2339 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2340
2341 EXPECT_EQ(OK, result.error());
2342 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2343
2344 EXPECT_THAT(result.ip_endpoints(), ElementsAre(kEndpointBack));
2345
2346 EXPECT_EQ(base::Hours(4), result.ttl());
2347
2348 EXPECT_THAT(result.aliases(),
2349 UnorderedElementsAre("alias0", "alias1", "alias2", "alias3"));
2350 }
2351
TEST(HostCacheTest,MergeEntries_backWithAliasesNoAddressesFrontWithBoth)2352 TEST(HostCacheTest, MergeEntries_backWithAliasesNoAddressesFrontWithBoth) {
2353 HostCache::Entry back(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS);
2354 std::set<std::string> aliases_back({"alias1", "alias2", "alias3"});
2355 back.set_aliases(aliases_back);
2356
2357 const IPAddress kAddressFront(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2358 0);
2359 const IPEndPoint kEndpointFront(kAddressFront, 0);
2360 HostCache::Entry front(OK, {kEndpointFront}, {"alias0", "alias1", "alias2"},
2361 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2362
2363 HostCache::Entry result =
2364 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2365
2366 EXPECT_EQ(OK, result.error());
2367 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2368
2369 EXPECT_THAT(result.ip_endpoints(), ElementsAre(kEndpointFront));
2370
2371 EXPECT_EQ(base::Hours(4), result.ttl());
2372
2373 EXPECT_THAT(result.aliases(),
2374 UnorderedElementsAre("alias0", "alias1", "alias2", "alias3"));
2375 }
2376
TEST(HostCacheTest,MergeEntries_frontWithAddressesNoAliasesBackWithBoth)2377 TEST(HostCacheTest, MergeEntries_frontWithAddressesNoAliasesBackWithBoth) {
2378 const IPAddress kAddressFront(1, 2, 3, 4);
2379 const IPEndPoint kEndpointFront(kAddressFront, 0);
2380 HostCache::Entry front(OK, {kEndpointFront}, /*aliases=*/{},
2381 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2382
2383 const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2384 0);
2385 const IPEndPoint kEndpointBack(kAddressBack, 0);
2386 HostCache::Entry back(OK, {kEndpointBack}, {"alias1", "alias2", "alias3"},
2387 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2388 HostCache::Entry result =
2389 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2390
2391 EXPECT_EQ(OK, result.error());
2392 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2393
2394 EXPECT_THAT(result.ip_endpoints(),
2395 ElementsAre(kEndpointFront, kEndpointBack));
2396
2397 EXPECT_EQ(base::Hours(4), result.ttl());
2398
2399 EXPECT_THAT(result.aliases(),
2400 UnorderedElementsAre("alias1", "alias2", "alias3"));
2401 }
2402
TEST(HostCacheTest,MergeEntries_backWithAddressesNoAliasesFrontWithBoth)2403 TEST(HostCacheTest, MergeEntries_backWithAddressesNoAliasesFrontWithBoth) {
2404 const IPAddress kAddressFront(1, 2, 3, 4);
2405 const IPEndPoint kEndpointFront(kAddressFront, 0);
2406 HostCache::Entry front(OK, {kEndpointFront}, {"alias1", "alias2", "alias3"},
2407 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2408 const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2409 0);
2410 const IPEndPoint kEndpointBack(kAddressBack, 0);
2411 HostCache::Entry back(OK, {kEndpointBack}, /*aliases=*/{},
2412 HostCache::Entry::SOURCE_DNS, base::Hours(4));
2413
2414 HostCache::Entry result =
2415 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2416
2417 EXPECT_EQ(OK, result.error());
2418 EXPECT_EQ(HostCache::Entry::SOURCE_DNS, result.source());
2419
2420 EXPECT_THAT(result.ip_endpoints(),
2421 ElementsAre(kEndpointFront, kEndpointBack));
2422
2423 EXPECT_EQ(base::Hours(4), result.ttl());
2424
2425 EXPECT_THAT(result.aliases(),
2426 UnorderedElementsAre("alias1", "alias2", "alias3"));
2427 }
2428
TEST(HostCacheTest,MergeEntries_differentTtl)2429 TEST(HostCacheTest, MergeEntries_differentTtl) {
2430 HostCache::Entry front(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS,
2431 base::Days(12));
2432 HostCache::Entry back(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS,
2433 base::Seconds(42));
2434
2435 HostCache::Entry result =
2436 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2437
2438 EXPECT_EQ(base::Seconds(42), result.ttl());
2439 }
2440
TEST(HostCacheTest,MergeEntries_FrontCannonnamePreserved)2441 TEST(HostCacheTest, MergeEntries_FrontCannonnamePreserved) {
2442 HostCache::Entry front(OK, /*ip_endpoints=*/{}, /*aliases=*/{"name1"},
2443 HostCache::Entry::SOURCE_DNS);
2444
2445 HostCache::Entry back(OK, /*ip_endpoints=*/{}, /*aliases=*/{"name2"},
2446 HostCache::Entry::SOURCE_DNS);
2447
2448 HostCache::Entry result =
2449 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2450
2451 EXPECT_THAT(result.aliases(), UnorderedElementsAre("name1", "name2"));
2452 }
2453
2454 // Test that the back canonname can be used if there is no front cannonname.
TEST(HostCacheTest,MergeEntries_BackCannonnameUsable)2455 TEST(HostCacheTest, MergeEntries_BackCannonnameUsable) {
2456 HostCache::Entry front(OK, /*ip_endpoints=*/{}, /*aliases=*/{},
2457 HostCache::Entry::SOURCE_DNS);
2458
2459 HostCache::Entry back(OK, /*ip_endpoints=*/{}, /*aliases=*/{"name2"},
2460 HostCache::Entry::SOURCE_DNS);
2461
2462 HostCache::Entry result =
2463 HostCache::Entry::MergeEntries(std::move(front), std::move(back));
2464
2465 EXPECT_THAT(result.aliases(), UnorderedElementsAre("name2"));
2466 }
2467
TEST(HostCacheTest,ConvertFromInternalAddressResult)2468 TEST(HostCacheTest, ConvertFromInternalAddressResult) {
2469 const std::vector<IPEndPoint> kEndpoints{
2470 IPEndPoint(IPAddress(2, 2, 2, 2), 46)};
2471 constexpr base::TimeDelta kTtl1 = base::Minutes(45);
2472 constexpr base::TimeDelta kTtl2 = base::Minutes(40);
2473 constexpr base::TimeDelta kTtl3 = base::Minutes(55);
2474
2475 std::set<std::unique_ptr<HostResolverInternalResult>> results;
2476 results.insert(std::make_unique<HostResolverInternalDataResult>(
2477 "endpoint.test", DnsQueryType::AAAA, base::TimeTicks() + kTtl1,
2478 base::Time() + kTtl1, HostResolverInternalResult::Source::kDns,
2479 kEndpoints, std::vector<std::string>{}, std::vector<HostPortPair>{}));
2480 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2481 "domain1.test", DnsQueryType::AAAA, base::TimeTicks() + kTtl2,
2482 base::Time() + kTtl2, HostResolverInternalResult::Source::kDns,
2483 "domain2.test"));
2484 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2485 "domain2.test", DnsQueryType::AAAA, base::TimeTicks() + kTtl3,
2486 base::Time() + kTtl3, HostResolverInternalResult::Source::kDns,
2487 "endpoint.test"));
2488
2489 HostCache::Entry converted(std::move(results), base::Time(),
2490 base::TimeTicks());
2491
2492 // Expect kTtl2 because it is the min TTL.
2493 HostCache::Entry expected(
2494 OK, kEndpoints,
2495 /*aliases=*/{"domain1.test", "domain2.test", "endpoint.test"},
2496 HostCache::Entry::SOURCE_DNS, kTtl2);
2497 expected.set_canonical_names(std::set<std::string>{"endpoint.test"});
2498
2499 // Entries converted from HostResolverInternalDataResults do not differentiate
2500 // between empty and no-data for the various data types, so need to set empty
2501 // strings and hostname entries into `expected`.
2502 expected.set_text_records(std::vector<std::string>());
2503 expected.set_hostnames(std::vector<HostPortPair>());
2504
2505 EXPECT_EQ(converted, expected);
2506 }
2507
TEST(HostCacheTest,ConvertFromInternalMetadataResult)2508 TEST(HostCacheTest, ConvertFromInternalMetadataResult) {
2509 const std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>
2510 kMetadatas{{1, ConnectionEndpointMetadata({"h2", "h3"},
2511 /*ech_config_list=*/{},
2512 "target.test")}};
2513 constexpr base::TimeDelta kTtl1 = base::Minutes(45);
2514 constexpr base::TimeDelta kTtl2 = base::Minutes(40);
2515 constexpr base::TimeDelta kTtl3 = base::Minutes(55);
2516
2517 std::set<std::unique_ptr<HostResolverInternalResult>> results;
2518 results.insert(std::make_unique<HostResolverInternalMetadataResult>(
2519 "endpoint.test", DnsQueryType::HTTPS, base::TimeTicks() + kTtl1,
2520 base::Time() + kTtl1, HostResolverInternalResult::Source::kDns,
2521 kMetadatas));
2522 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2523 "domain1.test", DnsQueryType::HTTPS, base::TimeTicks() + kTtl2,
2524 base::Time() + kTtl2, HostResolverInternalResult::Source::kDns,
2525 "domain2.test"));
2526 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2527 "domain2.test", DnsQueryType::HTTPS, base::TimeTicks() + kTtl3,
2528 base::Time() + kTtl3, HostResolverInternalResult::Source::kDns,
2529 "endpoint.test"));
2530
2531 HostCache::Entry converted(std::move(results), base::Time(),
2532 base::TimeTicks());
2533
2534 // Expect kTtl2 because it is the min TTL.
2535 HostCache::Entry expected(OK, kMetadatas, HostCache::Entry::SOURCE_DNS,
2536 kTtl2);
2537 expected.set_https_record_compatibility(std::vector<bool>{true});
2538
2539 EXPECT_EQ(converted, expected);
2540 }
2541
2542 // Test the case of compatible HTTPS records but no metadata of use to Chrome.
2543 // Represented in internal result type as an empty metadata result. Represented
2544 // in HostCache::Entry as empty metadata with at least one true in
2545 // `https_record_compatibility_`.
TEST(HostCacheTest,ConvertFromCompatibleOnlyInternalMetadataResult)2546 TEST(HostCacheTest, ConvertFromCompatibleOnlyInternalMetadataResult) {
2547 const std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>
2548 kMetadatas;
2549 constexpr base::TimeDelta kTtl1 = base::Minutes(45);
2550 constexpr base::TimeDelta kTtl2 = base::Minutes(40);
2551 constexpr base::TimeDelta kTtl3 = base::Minutes(55);
2552
2553 std::set<std::unique_ptr<HostResolverInternalResult>> results;
2554 results.insert(std::make_unique<HostResolverInternalMetadataResult>(
2555 "endpoint.test", DnsQueryType::HTTPS, base::TimeTicks() + kTtl1,
2556 base::Time() + kTtl1, HostResolverInternalResult::Source::kDns,
2557 kMetadatas));
2558 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2559 "domain1.test", DnsQueryType::HTTPS, base::TimeTicks() + kTtl2,
2560 base::Time() + kTtl2, HostResolverInternalResult::Source::kDns,
2561 "domain2.test"));
2562 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2563 "domain2.test", DnsQueryType::HTTPS, base::TimeTicks() + kTtl3,
2564 base::Time() + kTtl3, HostResolverInternalResult::Source::kDns,
2565 "endpoint.test"));
2566
2567 HostCache::Entry converted(std::move(results), base::Time(),
2568 base::TimeTicks());
2569
2570 // Expect kTtl2 because it is the min TTL.
2571 HostCache::Entry expected(ERR_NAME_NOT_RESOLVED, kMetadatas,
2572 HostCache::Entry::SOURCE_DNS, kTtl2);
2573 expected.set_https_record_compatibility(std::vector<bool>{true});
2574
2575 EXPECT_EQ(converted, expected);
2576 }
2577
TEST(HostCacheTest,ConvertFromInternalErrorResult)2578 TEST(HostCacheTest, ConvertFromInternalErrorResult) {
2579 constexpr base::TimeDelta kTtl1 = base::Minutes(45);
2580 constexpr base::TimeDelta kTtl2 = base::Minutes(40);
2581 constexpr base::TimeDelta kTtl3 = base::Minutes(55);
2582
2583 std::set<std::unique_ptr<HostResolverInternalResult>> results;
2584 results.insert(std::make_unique<HostResolverInternalErrorResult>(
2585 "endpoint.test", DnsQueryType::A, base::TimeTicks() + kTtl1,
2586 base::Time() + kTtl1, HostResolverInternalResult::Source::kDns,
2587 ERR_NAME_NOT_RESOLVED));
2588 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2589 "domain1.test", DnsQueryType::A, base::TimeTicks() + kTtl2,
2590 base::Time() + kTtl2, HostResolverInternalResult::Source::kDns,
2591 "domain2.test"));
2592 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2593 "domain2.test", DnsQueryType::A, base::TimeTicks() + kTtl3,
2594 base::Time() + kTtl3, HostResolverInternalResult::Source::kDns,
2595 "endpoint.test"));
2596
2597 HostCache::Entry converted(std::move(results), base::Time(),
2598 base::TimeTicks());
2599
2600 // Expect kTtl2 because it is the min TTL.
2601 HostCache::Entry expected(ERR_NAME_NOT_RESOLVED, HostCache::Entry::SOURCE_DNS,
2602 kTtl2);
2603
2604 EXPECT_EQ(converted, expected);
2605 }
2606
TEST(HostCacheTest,ConvertFromNonCachableInternalErrorResult)2607 TEST(HostCacheTest, ConvertFromNonCachableInternalErrorResult) {
2608 constexpr base::TimeDelta kTtl1 = base::Minutes(45);
2609 constexpr base::TimeDelta kTtl2 = base::Minutes(40);
2610
2611 std::set<std::unique_ptr<HostResolverInternalResult>> results;
2612 results.insert(std::make_unique<HostResolverInternalErrorResult>(
2613 "endpoint.test", DnsQueryType::AAAA, /*expiration=*/std::nullopt,
2614 /*timed_expiration=*/std::nullopt,
2615 HostResolverInternalResult::Source::kDns, ERR_NAME_NOT_RESOLVED));
2616 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2617 "domain1.test", DnsQueryType::AAAA, base::TimeTicks() + kTtl1,
2618 base::Time() + kTtl1, HostResolverInternalResult::Source::kDns,
2619 "domain2.test"));
2620 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2621 "domain2.test", DnsQueryType::AAAA, base::TimeTicks() + kTtl2,
2622 base::Time() + kTtl2, HostResolverInternalResult::Source::kDns,
2623 "endpoint.test"));
2624
2625 HostCache::Entry converted(std::move(results), base::Time(),
2626 base::TimeTicks());
2627
2628 // Expect no TTL because error is non-cachable (has no TTL itself).
2629 HostCache::Entry expected(ERR_NAME_NOT_RESOLVED,
2630 HostCache::Entry::SOURCE_DNS);
2631
2632 EXPECT_EQ(converted, expected);
2633 }
2634
TEST(HostCacheTest,ConvertFromInternalAliasOnlyResult)2635 TEST(HostCacheTest, ConvertFromInternalAliasOnlyResult) {
2636 constexpr base::TimeDelta kTtl1 = base::Minutes(45);
2637 constexpr base::TimeDelta kTtl2 = base::Minutes(40);
2638
2639 std::set<std::unique_ptr<HostResolverInternalResult>> results;
2640 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2641 "domain1.test", DnsQueryType::A, base::TimeTicks() + kTtl1,
2642 base::Time() + kTtl1, HostResolverInternalResult::Source::kDns,
2643 "domain2.test"));
2644 results.insert(std::make_unique<HostResolverInternalAliasResult>(
2645 "domain2.test", DnsQueryType::A, base::TimeTicks() + kTtl2,
2646 base::Time() + kTtl2, HostResolverInternalResult::Source::kDns,
2647 "endpoint.test"));
2648
2649 HostCache::Entry converted(std::move(results), base::Time(),
2650 base::TimeTicks());
2651
2652 // Expect no TTL because alias-only results are not cacheable.
2653 HostCache::Entry expected(ERR_NAME_NOT_RESOLVED,
2654 HostCache::Entry::SOURCE_DNS);
2655
2656 EXPECT_EQ(converted, expected);
2657 }
2658
TEST(HostCacheTest,ConvertFromEmptyInternalResult)2659 TEST(HostCacheTest, ConvertFromEmptyInternalResult) {
2660 HostCache::Entry converted({}, base::Time(), base::TimeTicks());
2661 HostCache::Entry expected(ERR_NAME_NOT_RESOLVED,
2662 HostCache::Entry::SOURCE_UNKNOWN);
2663
2664 EXPECT_EQ(converted, expected);
2665 }
2666
2667 } // namespace net
2668