| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/dns/host_resolver_internal_result.h" |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/json/json_reader.h" |
| #include "base/time/time.h" |
| #include "net/base/connection_endpoint_metadata.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/ip_endpoint.h" |
| #include "net/base/net_errors.h" |
| #include "net/dns/https_record_rdata.h" |
| #include "net/dns/public/dns_query_type.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| using ::testing::ElementsAre; |
| using ::testing::Optional; |
| using ::testing::Ref; |
| |
| namespace net { |
| namespace { |
| |
| TEST(HostResolverInternalResultTest, DeserializeMalformedValue) { |
| base::Value non_dict(base::Value::Type::BOOLEAN); |
| EXPECT_FALSE(HostResolverInternalResult::FromValue(non_dict)); |
| |
| base::Value missing_type(base::Value::Type::DICT); |
| EXPECT_FALSE(HostResolverInternalResult::FromValue(missing_type)); |
| |
| base::Value bad_type(base::Value::Type::DICT); |
| bad_type.GetDict().Set("type", "foo"); |
| EXPECT_FALSE(HostResolverInternalResult::FromValue(bad_type)); |
| } |
| |
| TEST(HostResolverInternalResultTest, DataResult) { |
| auto result = std::make_unique<HostResolverInternalDataResult>( |
| "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)}, |
| std::vector<std::string>{"foo", "bar"}, |
| std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)}); |
| |
| EXPECT_EQ(result->domain_name(), "domain.test"); |
| EXPECT_EQ(result->query_type(), DnsQueryType::AAAA); |
| EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kData); |
| EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kDns); |
| EXPECT_THAT(result->expiration(), Optional(base::TimeTicks())); |
| EXPECT_THAT(result->timed_expiration(), Optional(base::Time())); |
| |
| EXPECT_THAT(result->AsData(), Ref(*result)); |
| |
| EXPECT_THAT(result->endpoints(), |
| ElementsAre(IPEndPoint(IPAddress(2, 2, 2, 2), 46))); |
| EXPECT_THAT(result->strings(), ElementsAre("foo", "bar")); |
| EXPECT_THAT(result->hosts(), |
| ElementsAre(HostPortPair("anotherdomain.test", 112))); |
| } |
| |
| TEST(HostResolverInternalResultTest, RoundtripDataResultThroughSerialization) { |
| auto result = std::make_unique<HostResolverInternalDataResult>( |
| "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)}, |
| std::vector<std::string>{"foo", "bar"}, |
| std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)}); |
| |
| base::Value value = result->ToValue(); |
| auto deserialized = HostResolverInternalResult::FromValue(value); |
| ASSERT_TRUE(deserialized); |
| ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kData); |
| |
| // Expect deserialized result to be the same as the original other than |
| // missing non-timed expiration. |
| EXPECT_EQ(deserialized->AsData(), |
| HostResolverInternalDataResult( |
| result->domain_name(), result->query_type(), |
| /*expiration=*/absl::nullopt, |
| result->timed_expiration().value(), result->source(), |
| result->endpoints(), result->strings(), result->hosts())); |
| } |
| |
| // Expect results to serialize to a consistent base::Value format for |
| // consumption by NetLog and similar. |
| TEST(HostResolverInternalResultTest, SerializepDataResult) { |
| auto result = std::make_unique<HostResolverInternalDataResult>( |
| "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)}, |
| std::vector<std::string>{"foo", "bar"}, |
| std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)}); |
| base::Value value = result->ToValue(); |
| |
| absl::optional<base::Value> expected = base::JSONReader::Read( |
| R"( |
| { |
| "domain_name": "domain.test", |
| "endpoints": [ |
| { |
| "address": "2.2.2.2", |
| "port": 46 |
| } |
| ], |
| "hosts": [ |
| { |
| "host": "anotherdomain.test", |
| "port": 112 |
| } |
| ], |
| "query_type": "AAAA", |
| "source": "dns", |
| "strings": [ |
| "foo", |
| "bar" |
| ], |
| "timed_expiration": "0", |
| "type": "data" |
| } |
| )"); |
| ASSERT_TRUE(expected.has_value()); |
| |
| EXPECT_EQ(value, expected.value()); |
| } |
| |
| TEST(HostResolverInternalResultTest, DeserializeMalformedDataValue) { |
| auto result = std::make_unique<HostResolverInternalDataResult>( |
| "domain.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::vector<IPEndPoint>{IPEndPoint(IPAddress(2, 2, 2, 2), 46)}, |
| std::vector<std::string>{"foo", "bar"}, |
| std::vector<HostPortPair>{HostPortPair("anotherdomain.test", 112)}); |
| base::Value valid_value = result->ToValue(); |
| ASSERT_TRUE(HostResolverInternalDataResult::FromValue(valid_value)); |
| |
| base::Value missing_domain = valid_value.Clone(); |
| ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_domain)); |
| |
| base::Value missing_qtype = valid_value.Clone(); |
| ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_qtype)); |
| base::Value unknown_qtype = valid_value.Clone(); |
| ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(unknown_qtype)); |
| |
| base::Value missing_value_type = valid_value.Clone(); |
| ASSERT_TRUE(missing_value_type.GetDict().Remove("type")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_value_type)); |
| base::Value unknown_value_type = valid_value.Clone(); |
| ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(unknown_value_type)); |
| |
| base::Value missing_source = valid_value.Clone(); |
| ASSERT_TRUE(missing_source.GetDict().Remove("source")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_source)); |
| base::Value unknown_source = valid_value.Clone(); |
| ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(unknown_source)); |
| |
| base::Value missing_expiration = valid_value.Clone(); |
| ASSERT_TRUE(missing_expiration.GetDict().Remove("timed_expiration")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_expiration)); |
| base::Value invalid_expiration = valid_value.Clone(); |
| ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_expiration)); |
| |
| base::Value missing_endpoints = valid_value.Clone(); |
| ASSERT_TRUE(missing_endpoints.GetDict().Remove("endpoints")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_endpoints)); |
| base::Value invalid_endpoint = valid_value.Clone(); |
| invalid_endpoint.GetDict().FindList("endpoints")->front() = |
| base::Value("foo"); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_endpoint)); |
| |
| base::Value missing_strings = valid_value.Clone(); |
| ASSERT_TRUE(missing_strings.GetDict().Remove("strings")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_strings)); |
| base::Value invalid_string = valid_value.Clone(); |
| invalid_string.GetDict().FindList("strings")->front() = base::Value(5); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_string)); |
| |
| base::Value missing_hosts = valid_value.Clone(); |
| ASSERT_TRUE(missing_hosts.GetDict().Remove("hosts")); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(missing_hosts)); |
| base::Value invalid_hosts = valid_value.Clone(); |
| invalid_hosts.GetDict().FindList("hosts")->front() = base::Value("foo"); |
| EXPECT_FALSE(HostResolverInternalDataResult::FromValue(invalid_hosts)); |
| } |
| |
| TEST(HostResolverInternalResultTest, MetadataResult) { |
| const ConnectionEndpointMetadata kMetadata( |
| /*supported_protocol_alpns=*/{"http/1.1", "h3"}, |
| /*ech_config_list=*/{0x01, 0x13}, |
| /*target_name*/ "target.test"); |
| auto result = std::make_unique<HostResolverInternalMetadataResult>( |
| "domain1.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{ |
| {4, kMetadata}}); |
| |
| EXPECT_EQ(result->domain_name(), "domain1.test"); |
| EXPECT_EQ(result->query_type(), DnsQueryType::HTTPS); |
| EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kMetadata); |
| EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kDns); |
| EXPECT_THAT(result->expiration(), Optional(base::TimeTicks())); |
| EXPECT_THAT(result->timed_expiration(), Optional(base::Time())); |
| |
| EXPECT_THAT(result->AsMetadata(), Ref(*result)); |
| |
| EXPECT_THAT(result->metadatas(), ElementsAre(std::make_pair(4, kMetadata))); |
| } |
| |
| TEST(HostResolverInternalResultTest, |
| RoundtripMetadataResultThroughSerialization) { |
| const ConnectionEndpointMetadata kMetadata( |
| /*supported_protocol_alpns=*/{"http/1.1", "h2", "h3"}, |
| /*ech_config_list=*/{0x01, 0x13, 0x15}, |
| /*target_name*/ "target1.test"); |
| auto result = std::make_unique<HostResolverInternalMetadataResult>( |
| "domain2.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{ |
| {2, kMetadata}}); |
| |
| base::Value value = result->ToValue(); |
| auto deserialized = HostResolverInternalResult::FromValue(value); |
| ASSERT_TRUE(deserialized); |
| ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kMetadata); |
| |
| // Expect deserialized result to be the same as the original other than |
| // missing non-timed expiration. |
| EXPECT_EQ( |
| deserialized->AsMetadata(), |
| HostResolverInternalMetadataResult( |
| result->domain_name(), result->query_type(), |
| /*expiration=*/absl::nullopt, result->timed_expiration().value(), |
| result->source(), result->metadatas())); |
| } |
| |
| // Expect results to serialize to a consistent base::Value format for |
| // consumption by NetLog and similar. |
| TEST(HostResolverInternalResultTest, SerializepMetadataResult) { |
| const ConnectionEndpointMetadata kMetadata( |
| /*supported_protocol_alpns=*/{"http/1.1", "h2", "h3"}, |
| /*ech_config_list=*/{0x01, 0x13, 0x15}, |
| /*target_name*/ "target1.test"); |
| auto result = std::make_unique<HostResolverInternalMetadataResult>( |
| "domain2.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{ |
| {2, kMetadata}}); |
| base::Value value = result->ToValue(); |
| |
| // Note that the `ech_config_list` base64 encodes to "ARMV". |
| absl::optional<base::Value> expected = base::JSONReader::Read( |
| R"( |
| { |
| "domain_name": "domain2.test", |
| "metadatas": [ |
| { |
| "metadata_value": |
| { |
| "ech_config_list": "ARMV", |
| "supported_protocol_alpns": ["http/1.1", "h2", "h3"], |
| "target_name": "target1.test" |
| }, |
| "metadata_weight": 2 |
| } |
| ], |
| "query_type": "HTTPS", |
| "source": "dns", |
| "timed_expiration": "0", |
| "type": "metadata" |
| } |
| )"); |
| ASSERT_TRUE(expected.has_value()); |
| |
| EXPECT_EQ(value, expected.value()); |
| } |
| |
| TEST(HostResolverInternalResultTest, DeserializeMalformedMetadataValue) { |
| const ConnectionEndpointMetadata kMetadata( |
| /*supported_protocol_alpns=*/{"http/1.1", "h2", "h3"}, |
| /*ech_config_list=*/{0x01, 0x13, 0x15}, |
| /*target_name*/ "target1.test"); |
| auto result = std::make_unique<HostResolverInternalMetadataResult>( |
| "domain2.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, |
| std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>{ |
| {2, kMetadata}}); |
| base::Value valid_value = result->ToValue(); |
| ASSERT_TRUE(HostResolverInternalMetadataResult::FromValue(valid_value)); |
| |
| base::Value missing_domain = valid_value.Clone(); |
| ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_domain)); |
| |
| base::Value missing_qtype = valid_value.Clone(); |
| ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_qtype)); |
| base::Value unknown_qtype = valid_value.Clone(); |
| ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(unknown_qtype)); |
| |
| base::Value missing_value_type = valid_value.Clone(); |
| ASSERT_TRUE(missing_value_type.GetDict().Remove("type")); |
| EXPECT_FALSE( |
| HostResolverInternalMetadataResult::FromValue(missing_value_type)); |
| base::Value unknown_value_type = valid_value.Clone(); |
| ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo")); |
| EXPECT_FALSE( |
| HostResolverInternalMetadataResult::FromValue(unknown_value_type)); |
| |
| base::Value missing_source = valid_value.Clone(); |
| ASSERT_TRUE(missing_source.GetDict().Remove("source")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_source)); |
| base::Value unknown_source = valid_value.Clone(); |
| ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(unknown_source)); |
| |
| base::Value missing_expiration = valid_value.Clone(); |
| ASSERT_TRUE(missing_expiration.GetDict().Remove("timed_expiration")); |
| EXPECT_FALSE( |
| HostResolverInternalMetadataResult::FromValue(missing_expiration)); |
| base::Value invalid_expiration = valid_value.Clone(); |
| ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo")); |
| EXPECT_FALSE( |
| HostResolverInternalMetadataResult::FromValue(invalid_expiration)); |
| |
| base::Value missing_metadatas = valid_value.Clone(); |
| ASSERT_TRUE(missing_metadatas.GetDict().Remove("metadatas")); |
| EXPECT_FALSE( |
| HostResolverInternalMetadataResult::FromValue(missing_metadatas)); |
| base::Value invalid_metadatas = valid_value.Clone(); |
| *invalid_metadatas.GetDict().Find("metadatas") = base::Value(4); |
| EXPECT_FALSE( |
| HostResolverInternalMetadataResult::FromValue(invalid_metadatas)); |
| |
| base::Value missing_weight = valid_value.Clone(); |
| ASSERT_TRUE(missing_weight.GetDict() |
| .Find("metadatas") |
| ->GetList() |
| .front() |
| .GetDict() |
| .Remove("metadata_weight")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_weight)); |
| base::Value invalid_weight = valid_value.Clone(); |
| *invalid_weight.GetDict() |
| .Find("metadatas") |
| ->GetList() |
| .front() |
| .GetDict() |
| .Find("metadata_weight") = base::Value("foo"); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(invalid_weight)); |
| |
| base::Value missing_value = valid_value.Clone(); |
| ASSERT_TRUE(missing_value.GetDict() |
| .Find("metadatas") |
| ->GetList() |
| .front() |
| .GetDict() |
| .Remove("metadata_value")); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(missing_value)); |
| base::Value invalid_value = valid_value.Clone(); |
| *invalid_value.GetDict() |
| .Find("metadatas") |
| ->GetList() |
| .front() |
| .GetDict() |
| .Find("metadata_value") = base::Value("foo"); |
| EXPECT_FALSE(HostResolverInternalMetadataResult::FromValue(invalid_value)); |
| } |
| |
| TEST(HostResolverInternalResultTest, ErrorResult) { |
| auto result = std::make_unique<HostResolverInternalErrorResult>( |
| "domain3.test", DnsQueryType::PTR, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kUnknown, ERR_NAME_NOT_RESOLVED); |
| |
| EXPECT_EQ(result->domain_name(), "domain3.test"); |
| EXPECT_EQ(result->query_type(), DnsQueryType::PTR); |
| EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kError); |
| EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kUnknown); |
| EXPECT_THAT(result->expiration(), Optional(base::TimeTicks())); |
| EXPECT_THAT(result->timed_expiration(), Optional(base::Time())); |
| |
| EXPECT_THAT(result->AsError(), Ref(*result)); |
| |
| EXPECT_EQ(result->error(), ERR_NAME_NOT_RESOLVED); |
| } |
| |
| TEST(HostResolverInternalResultTest, NoncachableErrorResult) { |
| auto result = std::make_unique<HostResolverInternalErrorResult>( |
| "domain3.test", DnsQueryType::PTR, /*expiration=*/absl::nullopt, |
| /*timed_expiration=*/absl::nullopt, |
| HostResolverInternalResult::Source::kUnknown, ERR_NAME_NOT_RESOLVED); |
| |
| EXPECT_EQ(result->domain_name(), "domain3.test"); |
| EXPECT_EQ(result->query_type(), DnsQueryType::PTR); |
| EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kError); |
| EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kUnknown); |
| EXPECT_FALSE(result->expiration().has_value()); |
| EXPECT_FALSE(result->timed_expiration().has_value()); |
| |
| EXPECT_THAT(result->AsError(), Ref(*result)); |
| |
| EXPECT_EQ(result->error(), ERR_NAME_NOT_RESOLVED); |
| } |
| |
| TEST(HostResolverInternalResultTest, RoundtripErrorResultThroughSerialization) { |
| auto result = std::make_unique<HostResolverInternalErrorResult>( |
| "domain4.test", DnsQueryType::A, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, ERR_DNS_SERVER_FAILED); |
| |
| base::Value value = result->ToValue(); |
| auto deserialized = HostResolverInternalResult::FromValue(value); |
| ASSERT_TRUE(deserialized); |
| ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kError); |
| |
| // Expect deserialized result to be the same as the original other than |
| // missing non-timed expiration. |
| EXPECT_EQ(deserialized->AsError(), |
| HostResolverInternalErrorResult(result->domain_name(), |
| result->query_type(), |
| /*expiration=*/absl::nullopt, |
| result->timed_expiration().value(), |
| result->source(), result->error())); |
| } |
| |
| // Expect results to serialize to a consistent base::Value format for |
| // consumption by NetLog and similar. |
| TEST(HostResolverInternalResultTest, SerializepErrorResult) { |
| auto result = std::make_unique<HostResolverInternalErrorResult>( |
| "domain4.test", DnsQueryType::A, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, ERR_DNS_SERVER_FAILED); |
| base::Value value = result->ToValue(); |
| |
| absl::optional<base::Value> expected = base::JSONReader::Read( |
| R"( |
| { |
| "domain_name": "domain4.test", |
| "error": -802, |
| "query_type": "A", |
| "source": "dns", |
| "timed_expiration": "0", |
| "type": "error" |
| } |
| )"); |
| ASSERT_TRUE(expected.has_value()); |
| |
| EXPECT_EQ(value, expected.value()); |
| } |
| |
| TEST(HostResolverInternalResultTest, DeserializeMalformedErrorValue) { |
| auto result = std::make_unique<HostResolverInternalErrorResult>( |
| "domain4.test", DnsQueryType::A, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, ERR_DNS_SERVER_FAILED); |
| base::Value valid_value = result->ToValue(); |
| ASSERT_TRUE(HostResolverInternalErrorResult::FromValue(valid_value)); |
| |
| base::Value missing_domain = valid_value.Clone(); |
| ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_domain)); |
| |
| base::Value missing_qtype = valid_value.Clone(); |
| ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_qtype)); |
| base::Value unknown_qtype = valid_value.Clone(); |
| ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(unknown_qtype)); |
| |
| base::Value missing_value_type = valid_value.Clone(); |
| ASSERT_TRUE(missing_value_type.GetDict().Remove("type")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_value_type)); |
| base::Value unknown_value_type = valid_value.Clone(); |
| ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(unknown_value_type)); |
| |
| base::Value missing_source = valid_value.Clone(); |
| ASSERT_TRUE(missing_source.GetDict().Remove("source")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_source)); |
| base::Value unknown_source = valid_value.Clone(); |
| ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(unknown_source)); |
| |
| base::Value invalid_expiration = valid_value.Clone(); |
| ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(invalid_expiration)); |
| |
| base::Value missing_error = valid_value.Clone(); |
| ASSERT_TRUE(missing_error.GetDict().Remove("error")); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(missing_error)); |
| base::Value invalid_error = valid_value.Clone(); |
| *invalid_error.GetDict().Find("error") = base::Value("foo"); |
| EXPECT_FALSE(HostResolverInternalErrorResult::FromValue(invalid_error)); |
| } |
| |
| TEST(HostResolverInternalResultTest, AliasResult) { |
| auto result = std::make_unique<HostResolverInternalAliasResult>( |
| "domain5.test", DnsQueryType::HTTPS, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, "alias_target.test"); |
| |
| EXPECT_EQ(result->domain_name(), "domain5.test"); |
| EXPECT_EQ(result->query_type(), DnsQueryType::HTTPS); |
| EXPECT_EQ(result->type(), HostResolverInternalResult::Type::kAlias); |
| EXPECT_EQ(result->source(), HostResolverInternalResult::Source::kDns); |
| EXPECT_THAT(result->expiration(), Optional(base::TimeTicks())); |
| EXPECT_THAT(result->timed_expiration(), Optional(base::Time())); |
| |
| EXPECT_THAT(result->AsAlias(), Ref(*result)); |
| |
| EXPECT_THAT(result->alias_target(), "alias_target.test"); |
| } |
| |
| TEST(HostResolverInternalResultTest, RoundtripAliasResultThroughSerialization) { |
| auto result = std::make_unique<HostResolverInternalAliasResult>( |
| "domain6.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, "alias_target1.test"); |
| |
| base::Value value = result->ToValue(); |
| auto deserialized = HostResolverInternalResult::FromValue(value); |
| ASSERT_TRUE(deserialized); |
| ASSERT_EQ(deserialized->type(), HostResolverInternalResult::Type::kAlias); |
| |
| // Expect deserialized result to be the same as the original other than |
| // missing non-timed expiration. |
| EXPECT_EQ( |
| deserialized->AsAlias(), |
| HostResolverInternalAliasResult( |
| result->domain_name(), result->query_type(), |
| /*expiration=*/absl::nullopt, result->timed_expiration().value(), |
| result->source(), result->alias_target())); |
| } |
| |
| // Expect results to serialize to a consistent base::Value format for |
| // consumption by NetLog and similar. |
| TEST(HostResolverInternalResultTest, SerializepAliasResult) { |
| auto result = std::make_unique<HostResolverInternalAliasResult>( |
| "domain6.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, "alias_target1.test"); |
| base::Value value = result->ToValue(); |
| |
| absl::optional<base::Value> expected = base::JSONReader::Read( |
| R"( |
| { |
| "alias_target": "alias_target1.test", |
| "domain_name": "domain6.test", |
| "query_type": "AAAA", |
| "source": "dns", |
| "timed_expiration": "0", |
| "type": "alias" |
| } |
| )"); |
| ASSERT_TRUE(expected.has_value()); |
| |
| EXPECT_EQ(value, expected.value()); |
| } |
| |
| TEST(HostResolverInternalResultTest, DeserializeMalformedAliasValue) { |
| auto result = std::make_unique<HostResolverInternalAliasResult>( |
| "domain6.test", DnsQueryType::AAAA, base::TimeTicks(), base::Time(), |
| HostResolverInternalResult::Source::kDns, "alias_target1.test"); |
| base::Value valid_value = result->ToValue(); |
| ASSERT_TRUE(HostResolverInternalAliasResult::FromValue(valid_value)); |
| |
| base::Value missing_domain = valid_value.Clone(); |
| ASSERT_TRUE(missing_domain.GetDict().Remove("domain_name")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_domain)); |
| |
| base::Value missing_qtype = valid_value.Clone(); |
| ASSERT_TRUE(missing_qtype.GetDict().Remove("query_type")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_qtype)); |
| base::Value unknown_qtype = valid_value.Clone(); |
| ASSERT_TRUE(unknown_qtype.GetDict().Set("query_type", "foo")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(unknown_qtype)); |
| |
| base::Value missing_value_type = valid_value.Clone(); |
| ASSERT_TRUE(missing_value_type.GetDict().Remove("type")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_value_type)); |
| base::Value unknown_value_type = valid_value.Clone(); |
| ASSERT_TRUE(unknown_value_type.GetDict().Set("type", "foo")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(unknown_value_type)); |
| |
| base::Value missing_source = valid_value.Clone(); |
| ASSERT_TRUE(missing_source.GetDict().Remove("source")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_source)); |
| base::Value unknown_source = valid_value.Clone(); |
| ASSERT_TRUE(unknown_source.GetDict().Set("source", "foo")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(unknown_source)); |
| |
| base::Value missing_expiration = valid_value.Clone(); |
| ASSERT_TRUE(missing_expiration.GetDict().Remove("timed_expiration")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_expiration)); |
| base::Value invalid_expiration = valid_value.Clone(); |
| ASSERT_TRUE(invalid_expiration.GetDict().Set("timed_expiration", "foo")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(invalid_expiration)); |
| |
| base::Value missing_alias = valid_value.Clone(); |
| ASSERT_TRUE(missing_alias.GetDict().Remove("alias_target")); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(missing_alias)); |
| base::Value invalid_alias = valid_value.Clone(); |
| *invalid_alias.GetDict().Find("alias_target") = base::Value(5); |
| EXPECT_FALSE(HostResolverInternalAliasResult::FromValue(invalid_alias)); |
| } |
| |
| } // namespace |
| } // namespace net |