| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/settings/settings_secure_dns_handler.h" |
| |
| #include "base/test/metrics/histogram_tester.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/net/dns_probe_test_util.h" |
| #include "chrome/browser/net/secure_dns_config.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "components/country_codes/country_codes.h" |
| #include "components/policy/core/browser/browser_policy_connector.h" |
| #include "components/policy/core/common/mock_configuration_policy_provider.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/test_web_ui.h" |
| #include "net/dns/public/resolve_error_info.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #if defined(OS_WIN) |
| #include "base/win/win_util.h" |
| #endif |
| |
| using testing::_; |
| using testing::IsEmpty; |
| using testing::Return; |
| |
| namespace settings { |
| |
| namespace { |
| |
| constexpr char kGetSecureDnsResolverList[] = "getSecureDnsResolverList"; |
| constexpr char kParseCustomDnsEntry[] = "parseCustomDnsEntry"; |
| constexpr char kProbeCustomDnsTemplate[] = "probeCustomDnsTemplate"; |
| constexpr char kRecordUserDropdownInteraction[] = |
| "recordUserDropdownInteraction"; |
| constexpr char kWebUiFunctionName[] = "webUiCallbackName"; |
| |
| net::DohProviderEntry::List GetDohProviderListForTesting() { |
| static const auto global1 = net::DohProviderEntry::ConstructForTesting( |
| "Provider_Global1", net::DohProviderIdForHistogram(-1), {} /*ip_strs */, |
| {} /* dot_hostnames */, "https://global1.provider/dns-query{?dns}", |
| "Global Provider 1" /* ui_name */, |
| "https://global1.provider/privacy_policy/" /* privacy_policy */, |
| true /* display_globally */, {} /* display_countries */); |
| static const auto no_display = net::DohProviderEntry::ConstructForTesting( |
| "Provider_NoDisplay", net::DohProviderIdForHistogram(-2), {} /*ip_strs */, |
| {} /* dot_hostnames */, "https://nodisplay.provider/dns-query{?dns}", |
| "No Display Provider" /* ui_name */, |
| "https://nodisplay.provider/privacy_policy/" /* privacy_policy */, |
| false /* display_globally */, {} /* display_countries */); |
| static const auto ee_fr = net::DohProviderEntry::ConstructForTesting( |
| "Provider_EE_FR", net::DohProviderIdForHistogram(-3), {} /*ip_strs */, |
| {} /* dot_hostnames */, "https://ee.fr.provider/dns-query{?dns}", |
| "EE/FR Provider" /* ui_name */, |
| "https://ee.fr.provider/privacy_policy/" /* privacy_policy */, |
| false /* display_globally */, {"EE", "FR"} /* display_countries */); |
| static const auto fr = net::DohProviderEntry::ConstructForTesting( |
| "Provider_FR", net::DohProviderIdForHistogram(-4), {} /*ip_strs */, |
| {} /* dot_hostnames */, "https://fr.provider/dns-query{?dns}", |
| "FR Provider" /* ui_name */, |
| "https://fr.provider/privacy_policy/" /* privacy_policy */, |
| false /* display_globally */, {"FR"} /* display_countries */); |
| static const auto global2 = net::DohProviderEntry::ConstructForTesting( |
| "Provider_Global2", net::DohProviderIdForHistogram(-5), {} /*ip_strs */, |
| {} /* dot_hostnames */, "https://global2.provider/dns-query{?dns}", |
| "Global Provider 2" /* ui_name */, |
| "https://global2.provider/privacy_policy/" /* privacy_policy */, |
| true /* display_globally */, {} /* display_countries */); |
| return {&global1, &no_display, &ee_fr, &fr, &global2}; |
| } |
| |
| bool FindDropdownItem(const base::Value& resolvers, |
| const std::string& name, |
| const std::string& value, |
| const std::string& policy) { |
| base::Value dict(base::Value::Type::DICTIONARY); |
| dict.SetKey("name", base::Value(name)); |
| dict.SetKey("value", base::Value(value)); |
| dict.SetKey("policy", base::Value(policy)); |
| |
| return std::find(resolvers.GetList().begin(), resolvers.GetList().end(), |
| dict) != resolvers.GetList().end(); |
| } |
| |
| } // namespace |
| |
| class TestSecureDnsHandler : public SecureDnsHandler { |
| public: |
| // Pull WebUIMessageHandler::set_web_ui() into public so tests can call it. |
| using SecureDnsHandler::set_web_ui; |
| }; |
| |
| class SecureDnsHandlerTest : public InProcessBrowserTest { |
| protected: |
| #if defined(OS_WIN) |
| SecureDnsHandlerTest() |
| // Mark as not enterprise managed to prevent the secure DNS mode from |
| // being downgraded to off. |
| : scoped_domain_(false) {} |
| #else |
| SecureDnsHandlerTest() = default; |
| #endif |
| ~SecureDnsHandlerTest() override = default; |
| |
| // InProcessBrowserTest: |
| void SetUpInProcessBrowserTestFixture() override { |
| // Initialize user policy. |
| ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true)); |
| policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); |
| } |
| |
| void SetUpOnMainThread() override { |
| handler_ = std::make_unique<TestSecureDnsHandler>(); |
| handler_->set_web_ui(&web_ui_); |
| handler_->RegisterMessages(); |
| handler_->AllowJavascriptForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void TearDownOnMainThread() override { handler_.reset(); } |
| |
| // Updates out-params from the last message sent to WebUI about a secure DNS |
| // change. Returns false if the message was invalid or not found. |
| bool GetLastSettingsChangedMessage( |
| std::string* secure_dns_mode, |
| std::vector<std::string>* secure_dns_templates, |
| int* management_mode) { |
| for (auto it = web_ui_.call_data().rbegin(); |
| it != web_ui_.call_data().rend(); ++it) { |
| const content::TestWebUI::CallData* data = it->get(); |
| if (data->function_name() != "cr.webUIListenerCallback" || |
| !data->arg1()->is_string() || |
| data->arg1()->GetString() != "secure-dns-setting-changed") { |
| continue; |
| } |
| |
| const base::DictionaryValue* dict = nullptr; |
| if (!data->arg2()->GetAsDictionary(&dict)) |
| return false; |
| |
| // Get the secure DNS mode. |
| if (!dict->FindStringPath("mode")) |
| return false; |
| *secure_dns_mode = *dict->FindStringPath("mode"); |
| |
| // Get the secure DNS templates. |
| if (!dict->FindListPath("templates")) |
| return false; |
| secure_dns_templates->clear(); |
| for (const auto& template_str : |
| dict->FindListPath("templates")->GetList()) { |
| if (!template_str.is_string()) |
| return false; |
| secure_dns_templates->push_back(template_str.GetString()); |
| } |
| |
| // Get the forced management description. |
| if (!dict->FindIntPath("managementMode")) |
| return false; |
| *management_mode = *dict->FindIntPath("managementMode"); |
| |
| return true; |
| } |
| return false; |
| } |
| |
| // Sets a policy update which will cause power pref managed change. |
| void SetPolicyForPolicyKey(policy::PolicyMap* policy_map, |
| const std::string& policy_key, |
| std::unique_ptr<base::Value> value) { |
| policy_map->Set(policy_key, policy::POLICY_LEVEL_MANDATORY, |
| policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, |
| std::move(value), nullptr); |
| provider_.UpdateChromePolicy(*policy_map); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| std::unique_ptr<TestSecureDnsHandler> handler_; |
| content::TestWebUI web_ui_; |
| policy::MockConfigurationPolicyProvider provider_; |
| |
| private: |
| #if defined(OS_WIN) |
| base::win::ScopedDomainStateForTesting scoped_domain_; |
| #endif |
| |
| DISALLOW_COPY_AND_ASSIGN(SecureDnsHandlerTest); |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsModes) { |
| PrefService* local_state = g_browser_process->local_state(); |
| std::string secure_dns_mode; |
| std::vector<std::string> secure_dns_templates; |
| int management_mode; |
| |
| local_state->SetString(prefs::kDnsOverHttpsMode, SecureDnsConfig::kModeOff); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode); |
| |
| local_state->SetString(prefs::kDnsOverHttpsMode, |
| SecureDnsConfig::kModeAutomatic); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeAutomatic, secure_dns_mode); |
| |
| local_state->SetString(prefs::kDnsOverHttpsMode, |
| SecureDnsConfig::kModeSecure); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeSecure, secure_dns_mode); |
| |
| local_state->SetString(prefs::kDnsOverHttpsMode, "unknown"); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsPolicy) { |
| policy::PolicyMap policy_map; |
| SetPolicyForPolicyKey( |
| &policy_map, policy::key::kDnsOverHttpsMode, |
| std::make_unique<base::Value>(SecureDnsConfig::kModeAutomatic)); |
| |
| PrefService* local_state = g_browser_process->local_state(); |
| local_state->SetString(prefs::kDnsOverHttpsMode, |
| SecureDnsConfig::kModeSecure); |
| |
| std::string secure_dns_mode; |
| std::vector<std::string> secure_dns_templates; |
| int management_mode; |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeAutomatic, secure_dns_mode); |
| EXPECT_EQ(static_cast<int>(SecureDnsConfig::ManagementMode::kNoOverride), |
| management_mode); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsPolicyChange) { |
| policy::PolicyMap policy_map; |
| SetPolicyForPolicyKey( |
| &policy_map, policy::key::kDnsOverHttpsMode, |
| std::make_unique<base::Value>(SecureDnsConfig::kModeAutomatic)); |
| |
| std::string secure_dns_mode; |
| std::vector<std::string> secure_dns_templates; |
| int management_mode; |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeAutomatic, secure_dns_mode); |
| EXPECT_EQ(static_cast<int>(SecureDnsConfig::ManagementMode::kNoOverride), |
| management_mode); |
| |
| SetPolicyForPolicyKey( |
| &policy_map, policy::key::kDnsOverHttpsMode, |
| std::make_unique<base::Value>(SecureDnsConfig::kModeOff)); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode); |
| EXPECT_EQ(static_cast<int>(SecureDnsConfig::ManagementMode::kNoOverride), |
| management_mode); |
| } |
| |
| // On platforms where enterprise policies do not have default values, test |
| // that DoH is disabled when non-DoH policies are set. |
| #if !defined(OS_CHROMEOS) |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, OtherPoliciesSet) { |
| policy::PolicyMap policy_map; |
| SetPolicyForPolicyKey(&policy_map, policy::key::kIncognitoModeAvailability, |
| std::make_unique<base::Value>(1)); |
| |
| PrefService* local_state = g_browser_process->local_state(); |
| local_state->SetString(prefs::kDnsOverHttpsMode, |
| SecureDnsConfig::kModeSecure); |
| |
| std::string secure_dns_mode; |
| std::vector<std::string> secure_dns_templates; |
| int management_mode; |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode); |
| EXPECT_EQ(static_cast<int>(SecureDnsConfig::ManagementMode::kDisabledManaged), |
| management_mode); |
| } |
| #endif |
| |
| // This test makes no assumptions about the country or underlying resolver list. |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, DropdownList) { |
| base::ListValue args; |
| args.AppendString(kWebUiFunctionName); |
| |
| web_ui_.HandleReceivedMessage(kGetSecureDnsResolverList, &args); |
| const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); |
| ASSERT_TRUE(call_data.arg2()->GetBool()); |
| |
| // Check results. |
| base::Value::ConstListView resolver_list = call_data.arg3()->GetList(); |
| ASSERT_GE(resolver_list.size(), 1U); |
| EXPECT_TRUE(resolver_list[0].FindKey("value")->GetString().empty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, DropdownListContents) { |
| const auto entries = GetDohProviderListForTesting(); |
| handler_->SetProvidersForTesting(entries); |
| const base::Value resolver_list = handler_->GetSecureDnsResolverList(); |
| |
| EXPECT_EQ(entries.size() + 1, resolver_list.GetList().size()); |
| EXPECT_TRUE(resolver_list.GetList()[0].FindKey("value")->GetString().empty()); |
| for (const auto* entry : entries) { |
| EXPECT_TRUE(FindDropdownItem(resolver_list, entry->ui_name, |
| entry->dns_over_https_template, |
| entry->privacy_policy)); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, DropdownListChange) { |
| handler_->SetProvidersForTesting(GetDohProviderListForTesting()); |
| |
| base::HistogramTester histograms; |
| base::ListValue args; |
| args.AppendString(std::string() /* old_provider */); |
| args.AppendString( |
| "https://global1.provider/dns-query{?dns}" /* new_provider */); |
| web_ui_.HandleReceivedMessage(kRecordUserDropdownInteraction, &args); |
| |
| const std::string kUmaBase = "Net.DNS.UI.DropdownSelectionEvent"; |
| histograms.ExpectTotalCount(kUmaBase + ".Ignored", 4u); |
| histograms.ExpectTotalCount(kUmaBase + ".Selected", 1u); |
| histograms.ExpectTotalCount(kUmaBase + ".Unselected", 1u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsTemplates) { |
| std::string good_post_template = "https://foo.test/"; |
| std::string good_get_template = "https://bar.test/dns-query{?dns}"; |
| std::string bad_template = "dns-query{?dns}"; |
| |
| std::string secure_dns_mode; |
| std::vector<std::string> secure_dns_templates; |
| int management_mode; |
| PrefService* local_state = g_browser_process->local_state(); |
| local_state->SetString(prefs::kDnsOverHttpsMode, |
| SecureDnsConfig::kModeAutomatic); |
| local_state->SetString(prefs::kDnsOverHttpsTemplates, good_post_template); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(1u, secure_dns_templates.size()); |
| EXPECT_EQ(good_post_template, secure_dns_templates[0]); |
| |
| local_state->SetString(prefs::kDnsOverHttpsTemplates, |
| good_post_template + " " + good_get_template); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(2u, secure_dns_templates.size()); |
| EXPECT_EQ(good_post_template, secure_dns_templates[0]); |
| EXPECT_EQ(good_get_template, secure_dns_templates[1]); |
| |
| local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_template); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(0u, secure_dns_templates.size()); |
| |
| local_state->SetString(prefs::kDnsOverHttpsTemplates, |
| bad_template + " " + good_post_template); |
| EXPECT_TRUE(GetLastSettingsChangedMessage( |
| &secure_dns_mode, &secure_dns_templates, &management_mode)); |
| EXPECT_EQ(1u, secure_dns_templates.size()); |
| EXPECT_EQ(good_post_template, secure_dns_templates[0]); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateValid) { |
| base::ListValue args; |
| args.AppendString(kWebUiFunctionName); |
| args.AppendString("https://example.template/dns-query"); |
| |
| base::HistogramTester histograms; |
| web_ui_.HandleReceivedMessage(kParseCustomDnsEntry, &args); |
| const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); |
| // The request should be successful. |
| ASSERT_TRUE(call_data.arg2()->GetBool()); |
| // The template should be valid. |
| auto result = call_data.arg3()->GetList(); |
| ASSERT_EQ(1u, result.size()); |
| EXPECT_EQ(result[0].GetString(), "https://example.template/dns-query"); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 0); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateInvalid) { |
| base::ListValue args; |
| args.AppendString(kWebUiFunctionName); |
| args.AppendString("invalid_template"); |
| |
| base::HistogramTester histograms; |
| web_ui_.HandleReceivedMessage(kParseCustomDnsEntry, &args); |
| const content::TestWebUI::CallData& call_data = *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data.arg1()->GetString()); |
| // The request should be successful. |
| ASSERT_TRUE(call_data.arg2()->GetBool()); |
| // The template should be invalid. |
| EXPECT_THAT(call_data.arg3()->GetList(), IsEmpty()); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 1); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 0); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, MultipleTemplates) { |
| base::HistogramTester histograms; |
| base::ListValue args_valid; |
| args_valid.AppendString(kWebUiFunctionName); |
| args_valid.AppendString( |
| "https://example1.template/dns https://example2.template/dns-query"); |
| web_ui_.HandleReceivedMessage(kParseCustomDnsEntry, &args_valid); |
| const content::TestWebUI::CallData& call_data_valid = |
| *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data_valid.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data_valid.arg1()->GetString()); |
| // The request should be successful. |
| ASSERT_TRUE(call_data_valid.arg2()->GetBool()); |
| // Both templates should be valid. |
| auto result = call_data_valid.arg3()->GetList(); |
| ASSERT_EQ(2u, result.size()); |
| EXPECT_EQ(result[0].GetString(), "https://example1.template/dns"); |
| EXPECT_EQ(result[1].GetString(), "https://example2.template/dns-query"); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 0); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 1); |
| |
| base::ListValue args_invalid; |
| args_invalid.AppendString(kWebUiFunctionName); |
| args_invalid.AppendString("invalid_template https://example.template/dns"); |
| web_ui_.HandleReceivedMessage(kParseCustomDnsEntry, &args_invalid); |
| const content::TestWebUI::CallData& call_data_invalid = |
| *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data_invalid.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data_invalid.arg1()->GetString()); |
| // The request should be successful. |
| ASSERT_TRUE(call_data_invalid.arg2()->GetBool()); |
| // The entry should be invalid. |
| EXPECT_THAT(call_data_invalid.arg3()->GetList(), IsEmpty()); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", false, 1); |
| histograms.ExpectBucketCount("Net.DNS.UI.ValidationAttemptSuccess", true, 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateProbeSuccess) { |
| auto network_context_ = |
| std::make_unique<chrome_browser_net::FakeHostResolverNetworkContext>( |
| std::vector<chrome_browser_net::FakeHostResolver::SingleResult>( |
| {chrome_browser_net::FakeHostResolver::SingleResult( |
| net::OK, net::ResolveErrorInfo(net::OK), |
| chrome_browser_net::FakeHostResolver:: |
| kOneAddressResponse)}) /* current_config_result_list */, |
| std::vector<chrome_browser_net::FakeHostResolver:: |
| SingleResult>() /* google_config_result_list */); |
| handler_->SetNetworkContextForTesting(network_context_.get()); |
| base::HistogramTester histograms; |
| base::ListValue args_valid; |
| args_valid.AppendString(kWebUiFunctionName); |
| args_valid.AppendString("https://example.template/dns-query"); |
| web_ui_.HandleReceivedMessage(kProbeCustomDnsTemplate, &args_valid); |
| base::RunLoop().RunUntilIdle(); |
| |
| const content::TestWebUI::CallData& call_data_valid = |
| *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data_valid.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data_valid.arg1()->GetString()); |
| // The request should be successful. |
| ASSERT_TRUE(call_data_valid.arg2()->GetBool()); |
| // The probe query should have succeeded. |
| ASSERT_TRUE(call_data_valid.arg3()->GetBool()); |
| histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", false, 0); |
| histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", true, 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateProbeFailure) { |
| auto network_context_ = |
| std::make_unique<chrome_browser_net::FakeHostResolverNetworkContext>( |
| std::vector<chrome_browser_net::FakeHostResolver::SingleResult>( |
| {chrome_browser_net::FakeHostResolver::SingleResult( |
| net::ERR_NAME_NOT_RESOLVED, |
| net::ResolveErrorInfo(net::ERR_DNS_MALFORMED_RESPONSE), |
| chrome_browser_net::FakeHostResolver:: |
| kNoResponse)}) /* current_config_result_list */, |
| std::vector<chrome_browser_net::FakeHostResolver:: |
| SingleResult>() /* google_config_result_list */); |
| handler_->SetNetworkContextForTesting(network_context_.get()); |
| base::HistogramTester histograms; |
| base::ListValue args_valid; |
| args_valid.AppendString(kWebUiFunctionName); |
| args_valid.AppendString("https://example.template/dns-query"); |
| web_ui_.HandleReceivedMessage(kProbeCustomDnsTemplate, &args_valid); |
| base::RunLoop().RunUntilIdle(); |
| |
| const content::TestWebUI::CallData& call_data_valid = |
| *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", call_data_valid.function_name()); |
| EXPECT_EQ(kWebUiFunctionName, call_data_valid.arg1()->GetString()); |
| // The request should be successful. |
| ASSERT_TRUE(call_data_valid.arg2()->GetBool()); |
| // The probe query should have failed. |
| ASSERT_FALSE(call_data_valid.arg3()->GetBool()); |
| histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", false, 1); |
| histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", true, 0); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, TemplateProbeDebounce) { |
| auto network_context_hang = |
| std::make_unique<chrome_browser_net::HangingHostResolverNetworkContext>(); |
| auto network_context_fail = |
| std::make_unique<chrome_browser_net::FakeHostResolverNetworkContext>( |
| std::vector<chrome_browser_net::FakeHostResolver::SingleResult>( |
| {chrome_browser_net::FakeHostResolver::SingleResult( |
| net::ERR_NAME_NOT_RESOLVED, |
| net::ResolveErrorInfo(net::ERR_DNS_MALFORMED_RESPONSE), |
| chrome_browser_net::FakeHostResolver:: |
| kNoResponse)}) /* current_config_result_list */, |
| std::vector<chrome_browser_net::FakeHostResolver:: |
| SingleResult>() /* google_config_result_list */); |
| base::HistogramTester histograms; |
| base::ListValue args_valid; |
| args_valid.AppendString(kWebUiFunctionName); |
| args_valid.AppendString("https://example.template/dns-query"); |
| // Request a probe that will hang. |
| handler_->SetNetworkContextForTesting(network_context_hang.get()); |
| web_ui_.HandleReceivedMessage(kProbeCustomDnsTemplate, &args_valid); |
| size_t responses = web_ui_.call_data().size(); |
| base::RunLoop().RunUntilIdle(); |
| // No response yet from the hanging probe. |
| EXPECT_EQ(responses, web_ui_.call_data().size()); |
| |
| // Request a probe that will fail. |
| handler_->SetNetworkContextForTesting(network_context_fail.get()); |
| web_ui_.HandleReceivedMessage(kProbeCustomDnsTemplate, &args_valid); |
| // The hanging response should now have arrived. |
| EXPECT_EQ(responses + 1, web_ui_.call_data().size()); |
| const content::TestWebUI::CallData& first_response = |
| *web_ui_.call_data().back(); |
| ASSERT_EQ("cr.webUIResponse", first_response.function_name()); |
| ASSERT_EQ(kWebUiFunctionName, first_response.arg1()->GetString()); |
| // The cancelled probe should indicate no error. |
| ASSERT_TRUE(first_response.arg2()->GetBool()); |
| EXPECT_TRUE(first_response.arg3()->GetBool()); |
| |
| // Wait for the second response. |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(responses + 2, web_ui_.call_data().size()); |
| const content::TestWebUI::CallData& second_response = |
| *web_ui_.call_data().back(); |
| ASSERT_EQ("cr.webUIResponse", second_response.function_name()); |
| ASSERT_EQ(kWebUiFunctionName, second_response.arg1()->GetString()); |
| // The second request should have resolved with a failure indication. |
| ASSERT_TRUE(second_response.arg2()->GetBool()); |
| EXPECT_FALSE(second_response.arg3()->GetBool()); |
| // Only the second response should be counted in the histograms. |
| histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", false, 1); |
| histograms.ExpectBucketCount("Net.DNS.UI.ProbeAttemptSuccess", true, 0); |
| } |
| |
| } // namespace settings |