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