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