xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_internal_result_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 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_resolver_internal_result.h"
6 
7 #include <map>
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <vector>
12 
13 #include "base/json/json_reader.h"
14 #include "base/time/time.h"
15 #include "net/base/connection_endpoint_metadata.h"
16 #include "net/base/host_port_pair.h"
17 #include "net/base/ip_address.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/base/net_errors.h"
20 #include "net/dns/https_record_rdata.h"
21 #include "net/dns/public/dns_query_type.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 using ::testing::ElementsAre;
26 using ::testing::Optional;
27 using ::testing::Ref;
28 
29 namespace net {
30 namespace {
31 
TEST(HostResolverInternalResultTest,DeserializeMalformedValue)32 TEST(HostResolverInternalResultTest, DeserializeMalformedValue) {
33   base::Value non_dict(base::Value::Type::BOOLEAN);
34   EXPECT_FALSE(HostResolverInternalResult::FromValue(non_dict));
35 
36   base::Value missing_type(base::Value::Type::DICT);
37   EXPECT_FALSE(HostResolverInternalResult::FromValue(missing_type));
38 
39   base::Value bad_type(base::Value::Type::DICT);
40   bad_type.GetDict().Set("type", "foo");
41   EXPECT_FALSE(HostResolverInternalResult::FromValue(bad_type));
42 }
43 
TEST(HostResolverInternalResultTest,DataResult)44 TEST(HostResolverInternalResultTest, DataResult) {
45   auto result = std::make_unique<HostResolverInternalDataResult>(
46       "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
47       HostResolverInternalResult::Source::kDns,
48       std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)},
49       std::vector<std::string>{"foo", "bar"},
50       std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)});
51 
52   EXPECT_EQ(result->domain_name(), "domain.test");
53   EXPECT_EQ(result->query_type(), DnsQueryType::AAAA);
54   EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kData);
55   EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kDns);
56   EXPECT_THAT(result->expiration(), Optional(base::TimeTicks()));
57   EXPECT_THAT(result->timed_expiration(), Optional(base::Time()));
58 
59   EXPECT_THAT(result->AsData(), Ref(*result));
60 
61   EXPECT_THAT(result->endpoints(),
62               ElementsAre(IPEndPoint(IPAddress(2, 2, 2, 2), 46)));
63   EXPECT_THAT(result->strings(), ElementsAre("foo", "bar"));
64   EXPECT_THAT(result->hosts(),
65               ElementsAre(HostPortPair("anotherdomain.test", 112)));
66 }
67 
TEST(HostResolverInternalResultTest,CloneDataResult)68 TEST(HostResolverInternalResultTest, CloneDataResult) {
69   auto result = std::make_unique<HostResolverInternalDataResult>(
70       "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
71       HostResolverInternalResult::Source::kDns,
72       std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)},
73       std::vector<std::string>{"foo", "bar"},
74       std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)});
75 
76   std::unique_ptr<HostResolverInternalResult> copy = result->Clone();
77   EXPECT_NE(copy.get(), result.get());
78 
79   EXPECT_EQ(copy->domain_name(), "domain.test");
80   EXPECT_EQ(copy->query_type(), DnsQueryType::AAAA);
81   EXPECT_EQ(copy->type(), HostResolverInternalResult::Type::kData);
82   EXPECT_EQ(copy->source(), HostResolverInternalResult::Source::kDns);
83   EXPECT_THAT(copy->expiration(), Optional(base::TimeTicks()));
84   EXPECT_THAT(copy->timed_expiration(), Optional(base::Time()));
85   EXPECT_THAT(copy->AsData().endpoints(),
86               ElementsAre(IPEndPoint(IPAddress(2, 2, 2, 2), 46)));
87   EXPECT_THAT(copy->AsData().strings(), ElementsAre("foo", "bar"));
88   EXPECT_THAT(copy->AsData().hosts(),
89               ElementsAre(HostPortPair("anotherdomain.test", 112)));
90 }
91 
TEST(HostResolverInternalResultTest,RoundtripDataResultThroughSerialization)92 TEST(HostResolverInternalResultTest, RoundtripDataResultThroughSerialization) {
93   auto result = std::make_unique<HostResolverInternalDataResult>(
94       "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
95       HostResolverInternalResult::Source::kDns,
96       std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)},
97       std::vector<std::string>{"foo", "bar"},
98       std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)});
99 
100   base::Value value = result->ToValue();
101   auto deserialized = HostResolverInternalResult::FromValue(value);
102   ASSERT_TRUE(deserialized);
103   ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kData);
104 
105   // Expect deserialized result to be the same as the original other than
106   // missing non-timed expiration.
107   EXPECT_EQ(deserialized->AsData(),
108             HostResolverInternalDataResult(
109                 result->domain_name(), result->query_type(),
110                 /*expiration=*/std::nullopt, result->timed_expiration().value(),
111                 result->source(), result->endpoints(), result->strings(),
112                 result->hosts()));
113 }
114 
115 // Expect results to serialize to a consistent base::Value format for
116 // consumption by NetLog and similar.
TEST(HostResolverInternalResultTest,SerializepDataResult)117 TEST(HostResolverInternalResultTest, SerializepDataResult) {
118   auto result = std::make_unique<HostResolverInternalDataResult>(
119       "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
120       HostResolverInternalResult::Source::kDns,
121       std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)},
122       std::vector<std::string>{"foo", "bar"},
123       std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)});
124   base::Value value = result->ToValue();
125 
126   std::optional<base::Value> expected = base::JSONReader::Read(
127       R"(
128         {
129           "domain_name": "domain.test",
130           "endpoints": [
131             {
132               "address": "2.2.2.2",
133               "port": 46
134             }
135           ],
136           "hosts": [
137             {
138               "host": "anotherdomain.test",
139               "port": 112
140             }
141           ],
142           "query_type": "AAAA",
143           "source": "dns",
144           "strings": [
145             "foo",
146             "bar"
147           ],
148           "timed_expiration": "0",
149           "type": "data"
150         }
151         )");
152   ASSERT_TRUE(expected.has_value());
153 
154   EXPECT_EQ(value, expected.value());
155 }
156 
TEST(HostResolverInternalResultTest,DeserializeMalformedDataValue)157 TEST(HostResolverInternalResultTest, DeserializeMalformedDataValue) {
158   auto result = std::make_unique<HostResolverInternalDataResult>(
159       "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
160       HostResolverInternalResult::Source::kDns,
161       std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)},
162       std::vector<std::string>{"foo", "bar"},
163       std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)});
164   base::Value valid_value = result->ToValue();
165   ASSERT_TRUE(HostResolverInternalDataResult::FromValue(valid_value));
166 
167   base::Value missing_domain = valid_value.Clone();
168   ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name"));
169   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_domain));
170 
171   base::Value missing_qtype = valid_value.Clone();
172   ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type"));
173   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_qtype));
174   base::Value unknown_qtype = valid_value.Clone();
175   ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo"));
176   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(unknown_qtype));
177 
178   base::Value missing_value_type = valid_value.Clone();
179   ASSERT_TRUE(missing_value_type.GetDict().Remove("type"));
180   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_value_type));
181   base::Value unknown_value_type = valid_value.Clone();
182   ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo"));
183   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(unknown_value_type));
184 
185   base::Value missing_source = valid_value.Clone();
186   ASSERT_TRUE(missing_source.GetDict().Remove("source"));
187   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_source));
188   base::Value unknown_source = valid_value.Clone();
189   ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo"));
190   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(unknown_source));
191 
192   base::Value missing_expiration = valid_value.Clone();
193   ASSERT_TRUE(missing_expiration.GetDict().Remove("timed_expiration"));
194   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_expiration));
195   base::Value invalid_expiration = valid_value.Clone();
196   ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo"));
197   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_expiration));
198 
199   base::Value missing_endpoints = valid_value.Clone();
200   ASSERT_TRUE(missing_endpoints.GetDict().Remove("endpoints"));
201   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_endpoints));
202   base::Value invalid_endpoint = valid_value.Clone();
203   invalid_endpoint.GetDict().FindList("endpoints")->front() =
204       base::Value("foo");
205   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_endpoint));
206 
207   base::Value missing_strings = valid_value.Clone();
208   ASSERT_TRUE(missing_strings.GetDict().Remove("strings"));
209   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_strings));
210   base::Value invalid_string = valid_value.Clone();
211   invalid_string.GetDict().FindList("strings")->front() = base::Value(5);
212   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_string));
213 
214   base::Value missing_hosts = valid_value.Clone();
215   ASSERT_TRUE(missing_hosts.GetDict().Remove("hosts"));
216   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_hosts));
217   base::Value invalid_hosts = valid_value.Clone();
218   invalid_hosts.GetDict().FindList("hosts")->front() = base::Value("foo");
219   EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_hosts));
220 }
221 
TEST(HostResolverInternalResultTest,MetadataResult)222 TEST(HostResolverInternalResultTest, MetadataResult) {
223   const ConnectionEndpointMetadata kMetadata(
224       /*supported_protocol_alpns=*/{"http/1.1", "h3"},
225       /*ech_config_list=*/{0x01, 0x13},
226       /*target_name*/ "target.test");
227   auto result = std::make_unique<HostResolverInternalMetadataResult>(
228       "domain1.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
229       HostResolverInternalResult::Source::kDns,
230       std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
231           {4, kMetadata}});
232 
233   EXPECT_EQ(result->domain_name(), "domain1.test");
234   EXPECT_EQ(result->query_type(), DnsQueryType::HTTPS);
235   EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kMetadata);
236   EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kDns);
237   EXPECT_THAT(result->expiration(), Optional(base::TimeTicks()));
238   EXPECT_THAT(result->timed_expiration(), Optional(base::Time()));
239 
240   EXPECT_THAT(result->AsMetadata(), Ref(*result));
241 
242   EXPECT_THAT(result->metadatas(), ElementsAre(std::pair(4, kMetadata)));
243 }
244 
TEST(HostResolverInternalResultTest,CloneMetadataResult)245 TEST(HostResolverInternalResultTest, CloneMetadataResult) {
246   const ConnectionEndpointMetadata kMetadata(
247       /*supported_protocol_alpns=*/{"http/1.1", "h3"},
248       /*ech_config_list=*/{0x01, 0x13},
249       /*target_name*/ "target.test");
250   auto result = std::make_unique<HostResolverInternalMetadataResult>(
251       "domain1.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
252       HostResolverInternalResult::Source::kDns,
253       std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
254           {4, kMetadata}});
255 
256   std::unique_ptr<HostResolverInternalResult> copy = result->Clone();
257   EXPECT_NE(copy.get(), result.get());
258 
259   EXPECT_EQ(copy->domain_name(), "domain1.test");
260   EXPECT_EQ(copy->query_type(), DnsQueryType::HTTPS);
261   EXPECT_EQ(copy->type(), HostResolverInternalResult::Type::kMetadata);
262   EXPECT_EQ(copy->source(), HostResolverInternalResult::Source::kDns);
263   EXPECT_THAT(copy->expiration(), Optional(base::TimeTicks()));
264   EXPECT_THAT(copy->timed_expiration(), Optional(base::Time()));
265   EXPECT_THAT(copy->AsMetadata().metadatas(),
266               ElementsAre(std::make_pair(4, kMetadata)));
267 }
268 
TEST(HostResolverInternalResultTest,RoundtripMetadataResultThroughSerialization)269 TEST(HostResolverInternalResultTest,
270      RoundtripMetadataResultThroughSerialization) {
271   const ConnectionEndpointMetadata kMetadata(
272       /*supported_protocol_alpns=*/{"http/1.1", "h2", "h3"},
273       /*ech_config_list=*/{0x01, 0x13, 0x15},
274       /*target_name*/ "target1.test");
275   auto result = std::make_unique<HostResolverInternalMetadataResult>(
276       "domain2.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
277       HostResolverInternalResult::Source::kDns,
278       std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
279           {2, kMetadata}});
280 
281   base::Value value = result->ToValue();
282   auto deserialized = HostResolverInternalResult::FromValue(value);
283   ASSERT_TRUE(deserialized);
284   ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kMetadata);
285 
286   // Expect deserialized result to be the same as the original other than
287   // missing non-timed expiration.
288   EXPECT_EQ(deserialized->AsMetadata(),
289             HostResolverInternalMetadataResult(
290                 result->domain_name(), result->query_type(),
291                 /*expiration=*/std::nullopt, result->timed_expiration().value(),
292                 result->source(), result->metadatas()));
293 }
294 
295 // Expect results to serialize to a consistent base::Value format for
296 // consumption by NetLog and similar.
TEST(HostResolverInternalResultTest,SerializepMetadataResult)297 TEST(HostResolverInternalResultTest, SerializepMetadataResult) {
298   const ConnectionEndpointMetadata kMetadata(
299       /*supported_protocol_alpns=*/{"http/1.1", "h2", "h3"},
300       /*ech_config_list=*/{0x01, 0x13, 0x15},
301       /*target_name*/ "target1.test");
302   auto result = std::make_unique<HostResolverInternalMetadataResult>(
303       "domain2.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
304       HostResolverInternalResult::Source::kDns,
305       std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
306           {2, kMetadata}});
307   base::Value value = result->ToValue();
308 
309   // Note that the `ech_config_list` base64 encodes to "ARMV".
310   std::optional<base::Value> expected = base::JSONReader::Read(
311       R"(
312         {
313           "domain_name": "domain2.test",
314           "metadatas": [
315             {
316               "metadata_value":
317               {
318                 "ech_config_list": "ARMV",
319                 "supported_protocol_alpns": ["http/1.1", "h2", "h3"],
320                 "target_name": "target1.test"
321               },
322               "metadata_weight": 2
323             }
324           ],
325           "query_type": "HTTPS",
326           "source": "dns",
327           "timed_expiration": "0",
328           "type": "metadata"
329         }
330         )");
331   ASSERT_TRUE(expected.has_value());
332 
333   EXPECT_EQ(value, expected.value());
334 }
335 
TEST(HostResolverInternalResultTest,DeserializeMalformedMetadataValue)336 TEST(HostResolverInternalResultTest, DeserializeMalformedMetadataValue) {
337   const ConnectionEndpointMetadata kMetadata(
338       /*supported_protocol_alpns=*/{"http/1.1", "h2", "h3"},
339       /*ech_config_list=*/{0x01, 0x13, 0x15},
340       /*target_name*/ "target1.test");
341   auto result = std::make_unique<HostResolverInternalMetadataResult>(
342       "domain2.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
343       HostResolverInternalResult::Source::kDns,
344       std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{
345           {2, kMetadata}});
346   base::Value valid_value = result->ToValue();
347   ASSERT_TRUE(HostResolverInternalMetadataResult::FromValue(valid_value));
348 
349   base::Value missing_domain = valid_value.Clone();
350   ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name"));
351   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_domain));
352 
353   base::Value missing_qtype = valid_value.Clone();
354   ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type"));
355   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_qtype));
356   base::Value unknown_qtype = valid_value.Clone();
357   ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo"));
358   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(unknown_qtype));
359 
360   base::Value missing_value_type = valid_value.Clone();
361   ASSERT_TRUE(missing_value_type.GetDict().Remove("type"));
362   EXPECT_FALSE(
363       HostResolverInternalMetadataResult::FromValue(missing_value_type));
364   base::Value unknown_value_type = valid_value.Clone();
365   ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo"));
366   EXPECT_FALSE(
367       HostResolverInternalMetadataResult::FromValue(unknown_value_type));
368 
369   base::Value missing_source = valid_value.Clone();
370   ASSERT_TRUE(missing_source.GetDict().Remove("source"));
371   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_source));
372   base::Value unknown_source = valid_value.Clone();
373   ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo"));
374   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(unknown_source));
375 
376   base::Value missing_expiration = valid_value.Clone();
377   ASSERT_TRUE(missing_expiration.GetDict().Remove("timed_expiration"));
378   EXPECT_FALSE(
379       HostResolverInternalMetadataResult::FromValue(missing_expiration));
380   base::Value invalid_expiration = valid_value.Clone();
381   ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo"));
382   EXPECT_FALSE(
383       HostResolverInternalMetadataResult::FromValue(invalid_expiration));
384 
385   base::Value missing_metadatas = valid_value.Clone();
386   ASSERT_TRUE(missing_metadatas.GetDict().Remove("metadatas"));
387   EXPECT_FALSE(
388       HostResolverInternalMetadataResult::FromValue(missing_metadatas));
389   base::Value invalid_metadatas = valid_value.Clone();
390   *invalid_metadatas.GetDict().Find("metadatas") = base::Value(4);
391   EXPECT_FALSE(
392       HostResolverInternalMetadataResult::FromValue(invalid_metadatas));
393 
394   base::Value missing_weight = valid_value.Clone();
395   ASSERT_TRUE(missing_weight.GetDict()
396                   .Find("metadatas")
397                   ->GetList()
398                   .front()
399                   .GetDict()
400                   .Remove("metadata_weight"));
401   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_weight));
402   base::Value invalid_weight = valid_value.Clone();
403   *invalid_weight.GetDict()
404        .Find("metadatas")
405        ->GetList()
406        .front()
407        .GetDict()
408        .Find("metadata_weight") = base::Value("foo");
409   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(invalid_weight));
410 
411   base::Value missing_value = valid_value.Clone();
412   ASSERT_TRUE(missing_value.GetDict()
413                   .Find("metadatas")
414                   ->GetList()
415                   .front()
416                   .GetDict()
417                   .Remove("metadata_value"));
418   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_value));
419   base::Value invalid_value = valid_value.Clone();
420   *invalid_value.GetDict()
421        .Find("metadatas")
422        ->GetList()
423        .front()
424        .GetDict()
425        .Find("metadata_value") = base::Value("foo");
426   EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(invalid_value));
427 }
428 
TEST(HostResolverInternalResultTest,ErrorResult)429 TEST(HostResolverInternalResultTest, ErrorResult) {
430   auto result = std::make_unique<HostResolverInternalErrorResult>(
431       "domain3.test", DnsQueryType::PTR, base::TimeTicks(), base::Time(),
432       HostResolverInternalResult::Source::kUnknown, ERR_NAME_NOT_RESOLVED);
433 
434   EXPECT_EQ(result->domain_name(), "domain3.test");
435   EXPECT_EQ(result->query_type(), DnsQueryType::PTR);
436   EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kError);
437   EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kUnknown);
438   EXPECT_THAT(result->expiration(), Optional(base::TimeTicks()));
439   EXPECT_THAT(result->timed_expiration(), Optional(base::Time()));
440 
441   EXPECT_THAT(result->AsError(), Ref(*result));
442 
443   EXPECT_EQ(result->error(), ERR_NAME_NOT_RESOLVED);
444 }
445 
TEST(HostResolverInternalResultTest,CloneErrorResult)446 TEST(HostResolverInternalResultTest, CloneErrorResult) {
447   auto result = std::make_unique<HostResolverInternalErrorResult>(
448       "domain3.test", DnsQueryType::PTR, base::TimeTicks(), base::Time(),
449       HostResolverInternalResult::Source::kUnknown, ERR_NAME_NOT_RESOLVED);
450 
451   std::unique_ptr<HostResolverInternalResult> copy = result->Clone();
452   EXPECT_NE(copy.get(), result.get());
453 
454   EXPECT_EQ(copy->domain_name(), "domain3.test");
455   EXPECT_EQ(copy->query_type(), DnsQueryType::PTR);
456   EXPECT_EQ(copy->type(), HostResolverInternalResult::Type::kError);
457   EXPECT_EQ(copy->source(), HostResolverInternalResult::Source::kUnknown);
458   EXPECT_THAT(copy->expiration(), Optional(base::TimeTicks()));
459   EXPECT_THAT(copy->timed_expiration(), Optional(base::Time()));
460   EXPECT_EQ(copy->AsError().error(), ERR_NAME_NOT_RESOLVED);
461 }
462 
TEST(HostResolverInternalResultTest,NoncachableErrorResult)463 TEST(HostResolverInternalResultTest, NoncachableErrorResult) {
464   auto result = std::make_unique<HostResolverInternalErrorResult>(
465       "domain3.test", DnsQueryType::PTR, /*expiration=*/std::nullopt,
466       /*timed_expiration=*/std::nullopt,
467       HostResolverInternalResult::Source::kUnknown, ERR_NAME_NOT_RESOLVED);
468 
469   EXPECT_EQ(result->domain_name(), "domain3.test");
470   EXPECT_EQ(result->query_type(), DnsQueryType::PTR);
471   EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kError);
472   EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kUnknown);
473   EXPECT_FALSE(result->expiration().has_value());
474   EXPECT_FALSE(result->timed_expiration().has_value());
475 
476   EXPECT_THAT(result->AsError(), Ref(*result));
477 
478   EXPECT_EQ(result->error(), ERR_NAME_NOT_RESOLVED);
479 }
480 
TEST(HostResolverInternalResultTest,RoundtripErrorResultThroughSerialization)481 TEST(HostResolverInternalResultTest, RoundtripErrorResultThroughSerialization) {
482   auto result = std::make_unique<HostResolverInternalErrorResult>(
483       "domain4.test", DnsQueryType::A, base::TimeTicks(), base::Time(),
484       HostResolverInternalResult::Source::kDns, ERR_DNS_SERVER_FAILED);
485 
486   base::Value value = result->ToValue();
487   auto deserialized = HostResolverInternalResult::FromValue(value);
488   ASSERT_TRUE(deserialized);
489   ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kError);
490 
491   // Expect deserialized result to be the same as the original other than
492   // missing non-timed expiration.
493   EXPECT_EQ(deserialized->AsError(),
494             HostResolverInternalErrorResult(
495                 result->domain_name(), result->query_type(),
496                 /*expiration=*/std::nullopt, result->timed_expiration().value(),
497                 result->source(), result->error()));
498 }
499 
500 // Expect results to serialize to a consistent base::Value format for
501 // consumption by NetLog and similar.
TEST(HostResolverInternalResultTest,SerializepErrorResult)502 TEST(HostResolverInternalResultTest, SerializepErrorResult) {
503   auto result = std::make_unique<HostResolverInternalErrorResult>(
504       "domain4.test", DnsQueryType::A, base::TimeTicks(), base::Time(),
505       HostResolverInternalResult::Source::kDns, ERR_DNS_SERVER_FAILED);
506   base::Value value = result->ToValue();
507 
508   std::optional<base::Value> expected = base::JSONReader::Read(
509       R"(
510         {
511           "domain_name": "domain4.test",
512           "error": -802,
513           "query_type": "A",
514           "source": "dns",
515           "timed_expiration": "0",
516           "type": "error"
517         }
518         )");
519   ASSERT_TRUE(expected.has_value());
520 
521   EXPECT_EQ(value, expected.value());
522 }
523 
TEST(HostResolverInternalResultTest,DeserializeMalformedErrorValue)524 TEST(HostResolverInternalResultTest, DeserializeMalformedErrorValue) {
525   auto result = std::make_unique<HostResolverInternalErrorResult>(
526       "domain4.test", DnsQueryType::A, base::TimeTicks(), base::Time(),
527       HostResolverInternalResult::Source::kDns, ERR_DNS_SERVER_FAILED);
528   base::Value valid_value = result->ToValue();
529   ASSERT_TRUE(HostResolverInternalErrorResult::FromValue(valid_value));
530 
531   base::Value missing_domain = valid_value.Clone();
532   ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name"));
533   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_domain));
534 
535   base::Value missing_qtype = valid_value.Clone();
536   ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type"));
537   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_qtype));
538   base::Value unknown_qtype = valid_value.Clone();
539   ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo"));
540   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(unknown_qtype));
541 
542   base::Value missing_value_type = valid_value.Clone();
543   ASSERT_TRUE(missing_value_type.GetDict().Remove("type"));
544   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_value_type));
545   base::Value unknown_value_type = valid_value.Clone();
546   ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo"));
547   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(unknown_value_type));
548 
549   base::Value missing_source = valid_value.Clone();
550   ASSERT_TRUE(missing_source.GetDict().Remove("source"));
551   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_source));
552   base::Value unknown_source = valid_value.Clone();
553   ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo"));
554   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(unknown_source));
555 
556   base::Value invalid_expiration = valid_value.Clone();
557   ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo"));
558   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(invalid_expiration));
559 
560   base::Value missing_error = valid_value.Clone();
561   ASSERT_TRUE(missing_error.GetDict().Remove("error"));
562   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_error));
563   base::Value invalid_error = valid_value.Clone();
564   *invalid_error.GetDict().Find("error") = base::Value("foo");
565   EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(invalid_error));
566 }
567 
TEST(HostResolverInternalResultTest,AliasResult)568 TEST(HostResolverInternalResultTest, AliasResult) {
569   auto result = std::make_unique<HostResolverInternalAliasResult>(
570       "domain5.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
571       HostResolverInternalResult::Source::kDns, "alias_target.test");
572 
573   EXPECT_EQ(result->domain_name(), "domain5.test");
574   EXPECT_EQ(result->query_type(), DnsQueryType::HTTPS);
575   EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kAlias);
576   EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kDns);
577   EXPECT_THAT(result->expiration(), Optional(base::TimeTicks()));
578   EXPECT_THAT(result->timed_expiration(), Optional(base::Time()));
579 
580   EXPECT_THAT(result->AsAlias(), Ref(*result));
581 
582   EXPECT_THAT(result->alias_target(), "alias_target.test");
583 }
584 
TEST(HostResolverInternalResultTest,CloneAliasResult)585 TEST(HostResolverInternalResultTest, CloneAliasResult) {
586   auto result = std::make_unique<HostResolverInternalAliasResult>(
587       "domain5.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(),
588       HostResolverInternalResult::Source::kDns, "alias_target.test");
589 
590   std::unique_ptr<HostResolverInternalResult> copy = result->Clone();
591   EXPECT_NE(copy.get(), result.get());
592 
593   EXPECT_EQ(copy->domain_name(), "domain5.test");
594   EXPECT_EQ(copy->query_type(), DnsQueryType::HTTPS);
595   EXPECT_EQ(copy->type(), HostResolverInternalResult::Type::kAlias);
596   EXPECT_EQ(copy->source(), HostResolverInternalResult::Source::kDns);
597   EXPECT_THAT(copy->expiration(), Optional(base::TimeTicks()));
598   EXPECT_THAT(copy->timed_expiration(), Optional(base::Time()));
599   EXPECT_THAT(copy->AsAlias().alias_target(), "alias_target.test");
600 }
601 
TEST(HostResolverInternalResultTest,RoundtripAliasResultThroughSerialization)602 TEST(HostResolverInternalResultTest, RoundtripAliasResultThroughSerialization) {
603   auto result = std::make_unique<HostResolverInternalAliasResult>(
604       "domain6.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
605       HostResolverInternalResult::Source::kDns, "alias_target1.test");
606 
607   base::Value value = result->ToValue();
608   auto deserialized = HostResolverInternalResult::FromValue(value);
609   ASSERT_TRUE(deserialized);
610   ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kAlias);
611 
612   // Expect deserialized result to be the same as the original other than
613   // missing non-timed expiration.
614   EXPECT_EQ(deserialized->AsAlias(),
615             HostResolverInternalAliasResult(
616                 result->domain_name(), result->query_type(),
617                 /*expiration=*/std::nullopt, result->timed_expiration().value(),
618                 result->source(), result->alias_target()));
619 }
620 
621 // Expect results to serialize to a consistent base::Value format for
622 // consumption by NetLog and similar.
TEST(HostResolverInternalResultTest,SerializepAliasResult)623 TEST(HostResolverInternalResultTest, SerializepAliasResult) {
624   auto result = std::make_unique<HostResolverInternalAliasResult>(
625       "domain6.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
626       HostResolverInternalResult::Source::kDns, "alias_target1.test");
627   base::Value value = result->ToValue();
628 
629   std::optional<base::Value> expected = base::JSONReader::Read(
630       R"(
631         {
632           "alias_target": "alias_target1.test",
633           "domain_name": "domain6.test",
634           "query_type": "AAAA",
635           "source": "dns",
636           "timed_expiration": "0",
637           "type": "alias"
638         }
639         )");
640   ASSERT_TRUE(expected.has_value());
641 
642   EXPECT_EQ(value, expected.value());
643 }
644 
TEST(HostResolverInternalResultTest,DeserializeMalformedAliasValue)645 TEST(HostResolverInternalResultTest, DeserializeMalformedAliasValue) {
646   auto result = std::make_unique<HostResolverInternalAliasResult>(
647       "domain6.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(),
648       HostResolverInternalResult::Source::kDns, "alias_target1.test");
649   base::Value valid_value = result->ToValue();
650   ASSERT_TRUE(HostResolverInternalAliasResult::FromValue(valid_value));
651 
652   base::Value missing_domain = valid_value.Clone();
653   ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name"));
654   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_domain));
655 
656   base::Value missing_qtype = valid_value.Clone();
657   ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type"));
658   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_qtype));
659   base::Value unknown_qtype = valid_value.Clone();
660   ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo"));
661   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(unknown_qtype));
662 
663   base::Value missing_value_type = valid_value.Clone();
664   ASSERT_TRUE(missing_value_type.GetDict().Remove("type"));
665   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_value_type));
666   base::Value unknown_value_type = valid_value.Clone();
667   ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo"));
668   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(unknown_value_type));
669 
670   base::Value missing_source = valid_value.Clone();
671   ASSERT_TRUE(missing_source.GetDict().Remove("source"));
672   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_source));
673   base::Value unknown_source = valid_value.Clone();
674   ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo"));
675   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(unknown_source));
676 
677   base::Value missing_expiration = valid_value.Clone();
678   ASSERT_TRUE(missing_expiration.GetDict().Remove("timed_expiration"));
679   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_expiration));
680   base::Value invalid_expiration = valid_value.Clone();
681   ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo"));
682   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(invalid_expiration));
683 
684   base::Value missing_alias = valid_value.Clone();
685   ASSERT_TRUE(missing_alias.GetDict().Remove("alias_target"));
686   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_alias));
687   base::Value invalid_alias = valid_value.Clone();
688   *invalid_alias.GetDict().Find("alias_target") = base::Value(5);
689   EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(invalid_alias));
690 }
691 
692 }  // namespace
693 }  // namespace net
694