| // 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/net/secure_dns_util.h" |
| |
| #include <memory> |
| |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "chrome/common/chrome_features.h" |
| #include "components/country_codes/country_codes.h" |
| #include "components/embedder_support/pref_names.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "net/dns/public/dns_config_overrides.h" |
| #include "net/dns/public/doh_provider_entry.h" |
| #include "testing/gmock/include/gmock/gmock-matchers.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::ElementsAre; |
| |
| namespace chrome_browser_net { |
| |
| namespace secure_dns { |
| |
| class SecureDnsUtilTest : public testing::Test {}; |
| |
| TEST_F(SecureDnsUtilTest, MigrateProbesPrefForwardDefault) { |
| #if defined(OS_ANDROID) |
| base::test::ScopedFeatureList scoped_features; |
| scoped_features.InitAndEnableFeature(features::kLinkDoctorDeprecationAndroid); |
| #endif // defined(OS_ANDROID) |
| const char kAlternateErrorPagesBackup[] = "alternate_error_pages.backup"; |
| TestingPrefServiceSimple prefs; |
| prefs.registry()->RegisterBooleanPref( |
| embedder_support::kAlternateErrorPagesEnabled, true); |
| prefs.registry()->RegisterBooleanPref(kAlternateErrorPagesBackup, true); |
| |
| const PrefService::Preference* current_pref = |
| prefs.FindPreference(embedder_support::kAlternateErrorPagesEnabled); |
| const PrefService::Preference* backup_pref = |
| prefs.FindPreference(kAlternateErrorPagesBackup); |
| |
| EXPECT_FALSE(current_pref->HasUserSetting()); |
| EXPECT_FALSE(backup_pref->HasUserSetting()); |
| |
| MigrateProbesSettingToOrFromBackup(&prefs); |
| EXPECT_FALSE(current_pref->HasUserSetting()); |
| EXPECT_TRUE(backup_pref->HasUserSetting()); |
| EXPECT_TRUE(prefs.GetBoolean(kAlternateErrorPagesBackup)); |
| } |
| |
| // The following test verifies the lack of forward migration when the flag is |
| // disabled, which can only happen on Android. |
| // TODO(crbug.com/1177778): remove once the migration is fully rolled out. |
| #if defined(OS_ANDROID) |
| TEST_F(SecureDnsUtilTest, MigrateProbesPrefForwardNoMigration) { |
| base::test::ScopedFeatureList scoped_features; |
| scoped_features.InitAndDisableFeature( |
| features::kLinkDoctorDeprecationAndroid); |
| const char kAlternateErrorPagesBackup[] = "alternate_error_pages.backup"; |
| TestingPrefServiceSimple prefs; |
| prefs.registry()->RegisterBooleanPref( |
| embedder_support::kAlternateErrorPagesEnabled, true); |
| prefs.registry()->RegisterBooleanPref(kAlternateErrorPagesBackup, true); |
| |
| prefs.SetBoolean(embedder_support::kAlternateErrorPagesEnabled, true); |
| |
| const PrefService::Preference* current_pref = |
| prefs.FindPreference(embedder_support::kAlternateErrorPagesEnabled); |
| const PrefService::Preference* backup_pref = |
| prefs.FindPreference(kAlternateErrorPagesBackup); |
| |
| EXPECT_TRUE(current_pref->HasUserSetting()); |
| EXPECT_FALSE(backup_pref->HasUserSetting()); |
| |
| MigrateProbesSettingToOrFromBackup(&prefs); |
| EXPECT_TRUE(current_pref->HasUserSetting()); |
| EXPECT_FALSE(backup_pref->HasUserSetting()); |
| EXPECT_TRUE(prefs.GetBoolean(embedder_support::kAlternateErrorPagesEnabled)); |
| } |
| #endif // defined(OS_ANDROID) |
| |
| TEST_F(SecureDnsUtilTest, MigrateProbesPrefForwardCustomDisabled) { |
| #if defined(OS_ANDROID) |
| base::test::ScopedFeatureList scoped_features; |
| scoped_features.InitAndEnableFeature(features::kLinkDoctorDeprecationAndroid); |
| #endif // defined(OS_ANDROID) |
| const char kAlternateErrorPagesBackup[] = "alternate_error_pages.backup"; |
| TestingPrefServiceSimple prefs; |
| prefs.registry()->RegisterBooleanPref( |
| embedder_support::kAlternateErrorPagesEnabled, true); |
| prefs.registry()->RegisterBooleanPref(kAlternateErrorPagesBackup, true); |
| |
| prefs.SetBoolean(embedder_support::kAlternateErrorPagesEnabled, false); |
| |
| const PrefService::Preference* current_pref = |
| prefs.FindPreference(embedder_support::kAlternateErrorPagesEnabled); |
| const PrefService::Preference* backup_pref = |
| prefs.FindPreference(kAlternateErrorPagesBackup); |
| |
| EXPECT_TRUE(current_pref->HasUserSetting()); |
| EXPECT_FALSE(backup_pref->HasUserSetting()); |
| |
| MigrateProbesSettingToOrFromBackup(&prefs); |
| EXPECT_FALSE(current_pref->HasUserSetting()); |
| EXPECT_TRUE(backup_pref->HasUserSetting()); |
| EXPECT_FALSE(prefs.GetBoolean(kAlternateErrorPagesBackup)); |
| } |
| |
| // The following test verifies the backward migration, which can only happen on |
| // Android. |
| // TODO(crbug.com/1177778): remove once the migration is fully rolled out. |
| #if defined(OS_ANDROID) |
| TEST_F(SecureDnsUtilTest, MigrateProbesPrefBackward) { |
| base::test::ScopedFeatureList scoped_features; |
| scoped_features.InitAndDisableFeature( |
| features::kLinkDoctorDeprecationAndroid); |
| const char kAlternateErrorPagesBackup[] = "alternate_error_pages.backup"; |
| TestingPrefServiceSimple prefs; |
| prefs.registry()->RegisterBooleanPref( |
| embedder_support::kAlternateErrorPagesEnabled, true); |
| prefs.registry()->RegisterBooleanPref(kAlternateErrorPagesBackup, true); |
| |
| prefs.SetBoolean(kAlternateErrorPagesBackup, true); |
| |
| const PrefService::Preference* current_pref = |
| prefs.FindPreference(embedder_support::kAlternateErrorPagesEnabled); |
| const PrefService::Preference* backup_pref = |
| prefs.FindPreference(kAlternateErrorPagesBackup); |
| |
| EXPECT_FALSE(current_pref->HasUserSetting()); |
| EXPECT_TRUE(backup_pref->HasUserSetting()); |
| |
| MigrateProbesSettingToOrFromBackup(&prefs); |
| EXPECT_TRUE(current_pref->HasUserSetting()); |
| EXPECT_FALSE(backup_pref->HasUserSetting()); |
| EXPECT_TRUE(prefs.GetBoolean(embedder_support::kAlternateErrorPagesEnabled)); |
| } |
| #endif // defined(OS_ANDROID) |
| |
| TEST(SecureDnsUtil, SplitGroup) { |
| EXPECT_THAT(SplitGroup("a"), ElementsAre("a")); |
| EXPECT_THAT(SplitGroup("a b"), ElementsAre("a", "b")); |
| EXPECT_THAT(SplitGroup("a \tb\nc"), ElementsAre("a", "b\nc")); |
| EXPECT_THAT(SplitGroup(" \ta b\n"), ElementsAre("a", "b")); |
| } |
| |
| TEST(SecureDnsUtil, IsValidGroup) { |
| EXPECT_TRUE(IsValidGroup("")); |
| EXPECT_TRUE(IsValidGroup("https://valid")); |
| EXPECT_TRUE(IsValidGroup("https://valid https://valid2")); |
| |
| EXPECT_FALSE(IsValidGroup("https://valid invalid")); |
| EXPECT_FALSE(IsValidGroup("invalid https://valid")); |
| EXPECT_FALSE(IsValidGroup("invalid")); |
| EXPECT_FALSE(IsValidGroup("invalid invalid2")); |
| } |
| |
| TEST(SecureDnsUtil, ApplyDohTemplatePost) { |
| std::string post_template("https://valid"); |
| net::DnsConfigOverrides overrides; |
| ApplyTemplate(&overrides, post_template); |
| |
| EXPECT_THAT(overrides.dns_over_https_servers, |
| testing::Optional(ElementsAre(net::DnsOverHttpsServerConfig( |
| {post_template, true /* use_post */})))); |
| } |
| |
| TEST(SecureDnsUtil, ApplyDohTemplateGet) { |
| std::string get_template("https://valid/{?dns}"); |
| net::DnsConfigOverrides overrides; |
| ApplyTemplate(&overrides, get_template); |
| |
| EXPECT_THAT(overrides.dns_over_https_servers, |
| testing::Optional(ElementsAre(net::DnsOverHttpsServerConfig( |
| {get_template, false /* use_post */})))); |
| } |
| |
| net::DohProviderEntry::List GetProvidersForTesting() { |
| 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}; |
| } |
| |
| TEST(SecureDnsUtil, LocalProviders) { |
| const auto providers = GetProvidersForTesting(); |
| |
| const auto fr_providers = ProvidersForCountry( |
| providers, country_codes::CountryStringToCountryID("FR")); |
| EXPECT_THAT(fr_providers, ElementsAre(providers[0], providers[2], |
| providers[3], providers[4])); |
| |
| const auto ee_providers = ProvidersForCountry( |
| providers, country_codes::CountryStringToCountryID("EE")); |
| EXPECT_THAT(ee_providers, |
| ElementsAre(providers[0], providers[2], providers[4])); |
| |
| const auto us_providers = ProvidersForCountry( |
| providers, country_codes::CountryStringToCountryID("US")); |
| EXPECT_THAT(us_providers, ElementsAre(providers[0], providers[4])); |
| |
| const auto unknown_providers = |
| ProvidersForCountry(providers, country_codes::kCountryIDUnknown); |
| EXPECT_THAT(unknown_providers, ElementsAre(providers[0], providers[4])); |
| } |
| |
| TEST(SecureDnsUtil, DisabledProviders) { |
| base::test::ScopedFeatureList scoped_features; |
| scoped_features.InitAndEnableFeatureWithParameters( |
| features::kDnsOverHttps, |
| {{"DisabledProviders", "Provider_Global2, , Provider_EE_FR,Unexpected"}}); |
| EXPECT_THAT(GetDisabledProviders(), |
| ElementsAre("Provider_Global2", "Provider_EE_FR", "Unexpected")); |
| } |
| |
| TEST(SecureDnsUtil, RemoveDisabled) { |
| const auto providers = GetProvidersForTesting(); |
| const auto filtered_providers = RemoveDisabledProviders( |
| providers, {"Provider_Global2", "", "Provider_EE_FR", "Unexpected"}); |
| EXPECT_THAT(filtered_providers, |
| ElementsAre(providers[0], providers[1], providers[3])); |
| } |
| |
| TEST(SecureDnsUtil, UpdateDropdownHistograms) { |
| base::HistogramTester histograms; |
| |
| const auto providers = GetProvidersForTesting(); |
| UpdateDropdownHistograms(providers, providers[4]->dns_over_https_template, |
| providers[0]->dns_over_https_template); |
| |
| const std::string kUmaBase = "Net.DNS.UI.DropdownSelectionEvent"; |
| histograms.ExpectTotalCount(kUmaBase + ".Ignored", 4u); |
| histograms.ExpectTotalCount(kUmaBase + ".Selected", 1u); |
| histograms.ExpectTotalCount(kUmaBase + ".Unselected", 1u); |
| } |
| |
| TEST(SecureDnsUtil, UpdateDropdownHistogramsCustom) { |
| base::HistogramTester histograms; |
| |
| const auto providers = GetProvidersForTesting(); |
| UpdateDropdownHistograms(providers, std::string(), |
| providers[2]->dns_over_https_template); |
| |
| const std::string kUmaBase = "Net.DNS.UI.DropdownSelectionEvent"; |
| histograms.ExpectTotalCount(kUmaBase + ".Ignored", 4u); |
| histograms.ExpectTotalCount(kUmaBase + ".Selected", 1u); |
| histograms.ExpectTotalCount(kUmaBase + ".Unselected", 1u); |
| } |
| |
| } // namespace secure_dns |
| |
| } // namespace chrome_browser_net |