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