xref: /aosp_15_r20/external/cronet/net/dns/host_cache_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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