276 lines
9.7 KiB
C++
276 lines
9.7 KiB
C++
// Copyright 2021 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/dns_config_service_android.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "base/android/build_info.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/memory/scoped_refptr.h"
|
|
#include "base/test/task_environment.h"
|
|
#include "net/android/network_library.h"
|
|
#include "net/base/ip_endpoint.h"
|
|
#include "net/base/mock_network_change_notifier.h"
|
|
#include "net/base/network_change_notifier.h"
|
|
#include "net/dns/dns_config.h"
|
|
#include "net/test/test_with_task_environment.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace net::internal {
|
|
namespace {
|
|
|
|
const IPEndPoint kNameserver1(IPAddress(1, 2, 3, 4), 53);
|
|
const IPEndPoint kNameserver2(IPAddress(1, 2, 3, 8), 53);
|
|
|
|
// DnsConfigServiceAndroid uses a simplified implementation for Android versions
|
|
// before relevant APIs were added in Android M. Most of these tests are
|
|
// targeting the logic used in M and beyond.
|
|
#define SKIP_ANDROID_VERSIONS_BEFORE_M() \
|
|
{ \
|
|
if (base::android::BuildInfo::GetInstance()->sdk_int() < \
|
|
base::android::SDK_VERSION_MARSHMALLOW) { \
|
|
GTEST_SKIP() << "Test not necessary or compatible with pre-M."; \
|
|
} \
|
|
}
|
|
|
|
// RefCountedThreadSafe to allow safe usage and reference storage in
|
|
// DnsConfigServiceAndroid's off-sequence utility classes.
|
|
class MockDnsServerGetter
|
|
: public base::RefCountedThreadSafe<MockDnsServerGetter> {
|
|
public:
|
|
void set_retval(bool retval) { retval_ = retval; }
|
|
|
|
void set_dns_servers(std::vector<IPEndPoint> dns_servers) {
|
|
dns_servers_ = std::move(dns_servers);
|
|
}
|
|
|
|
void set_dns_over_tls_active(bool dns_over_tls_active) {
|
|
dns_over_tls_active_ = dns_over_tls_active;
|
|
}
|
|
|
|
void set_dns_over_tls_hostname(std::string dns_over_tls_hostname) {
|
|
dns_over_tls_hostname_ = std::move(dns_over_tls_hostname);
|
|
}
|
|
|
|
void set_search_suffixes(std::vector<std::string> search_suffixes) {
|
|
search_suffixes_ = std::move(search_suffixes);
|
|
}
|
|
|
|
android::DnsServerGetter ConstructGetter() {
|
|
return base::BindRepeating(&MockDnsServerGetter::GetDnsServers, this);
|
|
}
|
|
|
|
private:
|
|
friend base::RefCountedThreadSafe<MockDnsServerGetter>;
|
|
~MockDnsServerGetter() = default;
|
|
|
|
bool GetDnsServers(std::vector<IPEndPoint>* dns_servers,
|
|
bool* dns_over_tls_active,
|
|
std::string* dns_over_tls_hostname,
|
|
std::vector<std::string>* search_suffixes) {
|
|
if (retval_) {
|
|
*dns_servers = dns_servers_;
|
|
*dns_over_tls_active = dns_over_tls_active_;
|
|
*dns_over_tls_hostname = dns_over_tls_hostname_;
|
|
*search_suffixes = search_suffixes_;
|
|
}
|
|
return retval_;
|
|
}
|
|
|
|
bool retval_ = false;
|
|
std::vector<IPEndPoint> dns_servers_;
|
|
bool dns_over_tls_active_ = false;
|
|
std::string dns_over_tls_hostname_;
|
|
std::vector<std::string> search_suffixes_;
|
|
};
|
|
|
|
class DnsConfigServiceAndroidTest : public testing::Test,
|
|
public WithTaskEnvironment {
|
|
public:
|
|
DnsConfigServiceAndroidTest()
|
|
: WithTaskEnvironment(
|
|
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
|
|
service_->set_dns_server_getter_for_testing(
|
|
mock_dns_server_getter_->ConstructGetter());
|
|
}
|
|
~DnsConfigServiceAndroidTest() override = default;
|
|
|
|
void OnConfigChanged(const DnsConfig& config) {
|
|
EXPECT_TRUE(config.IsValid());
|
|
seen_config_ = true;
|
|
real_config_ = config;
|
|
}
|
|
|
|
protected:
|
|
bool seen_config_ = false;
|
|
std::unique_ptr<DnsConfigServiceAndroid> service_ =
|
|
std::make_unique<DnsConfigServiceAndroid>();
|
|
DnsConfig real_config_;
|
|
|
|
scoped_refptr<MockDnsServerGetter> mock_dns_server_getter_ =
|
|
base::MakeRefCounted<MockDnsServerGetter>();
|
|
test::ScopedMockNetworkChangeNotifier mock_notifier_;
|
|
};
|
|
|
|
TEST_F(DnsConfigServiceAndroidTest, HandlesNetworkChangeNotifications) {
|
|
service_->WatchConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
|
|
// Cannot validate any behavior other than not crashing because this test runs
|
|
// on Android versions with unmocked behavior.
|
|
}
|
|
|
|
TEST_F(DnsConfigServiceAndroidTest, NewConfigReadOnNetworkChange) {
|
|
SKIP_ANDROID_VERSIONS_BEFORE_M();
|
|
|
|
mock_dns_server_getter_->set_retval(true);
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
|
|
service_->WatchConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
|
|
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver2});
|
|
|
|
seen_config_ = false;
|
|
NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
|
|
NetworkChangeNotifier::CONNECTION_WIFI);
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver2));
|
|
}
|
|
|
|
TEST_F(DnsConfigServiceAndroidTest, NoConfigNotificationWhenUnchanged) {
|
|
SKIP_ANDROID_VERSIONS_BEFORE_M();
|
|
|
|
mock_dns_server_getter_->set_retval(true);
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
|
|
service_->WatchConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
|
|
|
|
seen_config_ = false;
|
|
NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
|
|
NetworkChangeNotifier::CONNECTION_WIFI);
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
|
|
// Because the DNS config hasn't changed, no new config should be seen.
|
|
EXPECT_FALSE(seen_config_);
|
|
}
|
|
|
|
TEST_F(DnsConfigServiceAndroidTest, IgnoresConnectionNoneChangeNotifications) {
|
|
SKIP_ANDROID_VERSIONS_BEFORE_M();
|
|
|
|
mock_dns_server_getter_->set_retval(true);
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
|
|
service_->WatchConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
|
|
|
|
// Change the DNS config to ensure the lack of notification is due to not
|
|
// being checked for.
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver2});
|
|
|
|
seen_config_ = false;
|
|
NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
|
|
NetworkChangeNotifier::CONNECTION_NONE);
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
|
|
// Expect no new config read for network change to NONE.
|
|
EXPECT_FALSE(seen_config_);
|
|
}
|
|
|
|
// Regression test for https://crbug.com/704662.
|
|
TEST_F(DnsConfigServiceAndroidTest, ChangeConfigMultipleTimes) {
|
|
SKIP_ANDROID_VERSIONS_BEFORE_M();
|
|
|
|
mock_dns_server_getter_->set_retval(true);
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
|
|
service_->WatchConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver2});
|
|
|
|
seen_config_ = false;
|
|
NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
|
|
NetworkChangeNotifier::CONNECTION_WIFI);
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver2));
|
|
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
|
|
seen_config_ = false;
|
|
NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
|
|
NetworkChangeNotifier::CONNECTION_WIFI);
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
|
|
}
|
|
}
|
|
|
|
TEST_F(DnsConfigServiceAndroidTest, ReadsSearchSuffixes) {
|
|
SKIP_ANDROID_VERSIONS_BEFORE_M();
|
|
|
|
const std::vector<std::string> kSuffixes{"name1.test", "name2.test"};
|
|
|
|
mock_dns_server_getter_->set_retval(true);
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
mock_dns_server_getter_->set_search_suffixes(kSuffixes);
|
|
|
|
service_->ReadConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_EQ(real_config_.search, kSuffixes);
|
|
}
|
|
|
|
TEST_F(DnsConfigServiceAndroidTest, ReadsEmptySearchSuffixes) {
|
|
SKIP_ANDROID_VERSIONS_BEFORE_M();
|
|
|
|
mock_dns_server_getter_->set_retval(true);
|
|
mock_dns_server_getter_->set_dns_servers({kNameserver1});
|
|
|
|
service_->ReadConfig(base::BindRepeating(
|
|
&DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
|
|
FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
|
|
RunUntilIdle();
|
|
ASSERT_TRUE(seen_config_);
|
|
EXPECT_TRUE(real_config_.search.empty());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace net::internal
|