xref: /aosp_15_r20/external/cronet/net/dns/dns_config_service_android_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 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/dns_config_service_android.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/android/build_info.h"
13 #include "base/functional/bind.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/test/task_environment.h"
17 #include "net/android/network_library.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/base/mock_network_change_notifier.h"
20 #include "net/base/network_change_notifier.h"
21 #include "net/dns/dns_config.h"
22 #include "net/test/test_with_task_environment.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace net::internal {
27 namespace {
28 
29 const IPEndPoint kNameserver1(IPAddress(1, 2, 3, 4), 53);
30 const IPEndPoint kNameserver2(IPAddress(1, 2, 3, 8), 53);
31 
32 // DnsConfigServiceAndroid uses a simplified implementation for Android versions
33 // before relevant APIs were added in Android M. Most of these tests are
34 // targeting the logic used in M and beyond.
35 #define SKIP_ANDROID_VERSIONS_BEFORE_M()                              \
36   {                                                                   \
37     if (base::android::BuildInfo::GetInstance()->sdk_int() <          \
38         base::android::SDK_VERSION_MARSHMALLOW) {                     \
39       GTEST_SKIP() << "Test not necessary or compatible with pre-M."; \
40     }                                                                 \
41   }
42 
43 // RefCountedThreadSafe to allow safe usage and reference storage in
44 // DnsConfigServiceAndroid's off-sequence utility classes.
45 class MockDnsServerGetter
46     : public base::RefCountedThreadSafe<MockDnsServerGetter> {
47  public:
set_retval(bool retval)48   void set_retval(bool retval) { retval_ = retval; }
49 
set_dns_servers(std::vector<IPEndPoint> dns_servers)50   void set_dns_servers(std::vector<IPEndPoint> dns_servers) {
51     dns_servers_ = std::move(dns_servers);
52   }
53 
set_dns_over_tls_active(bool dns_over_tls_active)54   void set_dns_over_tls_active(bool dns_over_tls_active) {
55     dns_over_tls_active_ = dns_over_tls_active;
56   }
57 
set_dns_over_tls_hostname(std::string dns_over_tls_hostname)58   void set_dns_over_tls_hostname(std::string dns_over_tls_hostname) {
59     dns_over_tls_hostname_ = std::move(dns_over_tls_hostname);
60   }
61 
set_search_suffixes(std::vector<std::string> search_suffixes)62   void set_search_suffixes(std::vector<std::string> search_suffixes) {
63     search_suffixes_ = std::move(search_suffixes);
64   }
65 
ConstructGetter()66   android::DnsServerGetter ConstructGetter() {
67     return base::BindRepeating(&MockDnsServerGetter::GetDnsServers, this);
68   }
69 
70  private:
71   friend base::RefCountedThreadSafe<MockDnsServerGetter>;
72   ~MockDnsServerGetter() = default;
73 
GetDnsServers(std::vector<IPEndPoint> * dns_servers,bool * dns_over_tls_active,std::string * dns_over_tls_hostname,std::vector<std::string> * search_suffixes)74   bool GetDnsServers(std::vector<IPEndPoint>* dns_servers,
75                      bool* dns_over_tls_active,
76                      std::string* dns_over_tls_hostname,
77                      std::vector<std::string>* search_suffixes) {
78     if (retval_) {
79       *dns_servers = dns_servers_;
80       *dns_over_tls_active = dns_over_tls_active_;
81       *dns_over_tls_hostname = dns_over_tls_hostname_;
82       *search_suffixes = search_suffixes_;
83     }
84     return retval_;
85   }
86 
87   bool retval_ = false;
88   std::vector<IPEndPoint> dns_servers_;
89   bool dns_over_tls_active_ = false;
90   std::string dns_over_tls_hostname_;
91   std::vector<std::string> search_suffixes_;
92 };
93 
94 class DnsConfigServiceAndroidTest : public testing::Test,
95                                     public WithTaskEnvironment {
96  public:
DnsConfigServiceAndroidTest()97   DnsConfigServiceAndroidTest()
98       : WithTaskEnvironment(
99             base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
100     service_->set_dns_server_getter_for_testing(
101         mock_dns_server_getter_->ConstructGetter());
102   }
103   ~DnsConfigServiceAndroidTest() override = default;
104 
OnConfigChanged(const DnsConfig & config)105   void OnConfigChanged(const DnsConfig& config) {
106     EXPECT_TRUE(config.IsValid());
107     seen_config_ = true;
108     real_config_ = config;
109   }
110 
111  protected:
112   bool seen_config_ = false;
113   std::unique_ptr<DnsConfigServiceAndroid> service_ =
114       std::make_unique<DnsConfigServiceAndroid>();
115   DnsConfig real_config_;
116 
117   scoped_refptr<MockDnsServerGetter> mock_dns_server_getter_ =
118       base::MakeRefCounted<MockDnsServerGetter>();
119   test::ScopedMockNetworkChangeNotifier mock_notifier_;
120 };
121 
TEST_F(DnsConfigServiceAndroidTest,HandlesNetworkChangeNotifications)122 TEST_F(DnsConfigServiceAndroidTest, HandlesNetworkChangeNotifications) {
123   service_->WatchConfig(base::BindRepeating(
124       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
125   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
126   RunUntilIdle();
127 
128   // Cannot validate any behavior other than not crashing because this test runs
129   // on Android versions with unmocked behavior.
130 }
131 
TEST_F(DnsConfigServiceAndroidTest,NewConfigReadOnNetworkChange)132 TEST_F(DnsConfigServiceAndroidTest, NewConfigReadOnNetworkChange) {
133   SKIP_ANDROID_VERSIONS_BEFORE_M();
134 
135   mock_dns_server_getter_->set_retval(true);
136   mock_dns_server_getter_->set_dns_servers({kNameserver1});
137 
138   service_->WatchConfig(base::BindRepeating(
139       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
140   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
141   RunUntilIdle();
142   ASSERT_TRUE(seen_config_);
143   EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
144 
145   mock_dns_server_getter_->set_dns_servers({kNameserver2});
146 
147   seen_config_ = false;
148   NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
149       NetworkChangeNotifier::CONNECTION_WIFI);
150   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
151   RunUntilIdle();
152   ASSERT_TRUE(seen_config_);
153   EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver2));
154 }
155 
TEST_F(DnsConfigServiceAndroidTest,NoConfigNotificationWhenUnchanged)156 TEST_F(DnsConfigServiceAndroidTest, NoConfigNotificationWhenUnchanged) {
157   SKIP_ANDROID_VERSIONS_BEFORE_M();
158 
159   mock_dns_server_getter_->set_retval(true);
160   mock_dns_server_getter_->set_dns_servers({kNameserver1});
161 
162   service_->WatchConfig(base::BindRepeating(
163       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
164   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
165   RunUntilIdle();
166   ASSERT_TRUE(seen_config_);
167   EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
168 
169   seen_config_ = false;
170   NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
171       NetworkChangeNotifier::CONNECTION_WIFI);
172   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
173   RunUntilIdle();
174 
175   // Because the DNS config hasn't changed, no new config should be seen.
176   EXPECT_FALSE(seen_config_);
177 }
178 
TEST_F(DnsConfigServiceAndroidTest,IgnoresConnectionNoneChangeNotifications)179 TEST_F(DnsConfigServiceAndroidTest, IgnoresConnectionNoneChangeNotifications) {
180   SKIP_ANDROID_VERSIONS_BEFORE_M();
181 
182   mock_dns_server_getter_->set_retval(true);
183   mock_dns_server_getter_->set_dns_servers({kNameserver1});
184 
185   service_->WatchConfig(base::BindRepeating(
186       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
187   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
188   RunUntilIdle();
189   ASSERT_TRUE(seen_config_);
190   EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
191 
192   // Change the DNS config to ensure the lack of notification is due to not
193   // being checked for.
194   mock_dns_server_getter_->set_dns_servers({kNameserver2});
195 
196   seen_config_ = false;
197   NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
198       NetworkChangeNotifier::CONNECTION_NONE);
199   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
200   RunUntilIdle();
201 
202   // Expect no new config read for network change to NONE.
203   EXPECT_FALSE(seen_config_);
204 }
205 
206 // Regression test for https://crbug.com/704662.
TEST_F(DnsConfigServiceAndroidTest,ChangeConfigMultipleTimes)207 TEST_F(DnsConfigServiceAndroidTest, ChangeConfigMultipleTimes) {
208   SKIP_ANDROID_VERSIONS_BEFORE_M();
209 
210   mock_dns_server_getter_->set_retval(true);
211   mock_dns_server_getter_->set_dns_servers({kNameserver1});
212 
213   service_->WatchConfig(base::BindRepeating(
214       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
215   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
216   RunUntilIdle();
217   ASSERT_TRUE(seen_config_);
218   EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
219 
220   for (int i = 0; i < 5; i++) {
221     mock_dns_server_getter_->set_dns_servers({kNameserver2});
222 
223     seen_config_ = false;
224     NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
225         NetworkChangeNotifier::CONNECTION_WIFI);
226     FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
227     RunUntilIdle();
228     ASSERT_TRUE(seen_config_);
229     EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver2));
230 
231     mock_dns_server_getter_->set_dns_servers({kNameserver1});
232 
233     seen_config_ = false;
234     NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
235         NetworkChangeNotifier::CONNECTION_WIFI);
236     FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
237     RunUntilIdle();
238     ASSERT_TRUE(seen_config_);
239     EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
240   }
241 }
242 
TEST_F(DnsConfigServiceAndroidTest,ReadsSearchSuffixes)243 TEST_F(DnsConfigServiceAndroidTest, ReadsSearchSuffixes) {
244   SKIP_ANDROID_VERSIONS_BEFORE_M();
245 
246   const std::vector<std::string> kSuffixes{"name1.test", "name2.test"};
247 
248   mock_dns_server_getter_->set_retval(true);
249   mock_dns_server_getter_->set_dns_servers({kNameserver1});
250   mock_dns_server_getter_->set_search_suffixes(kSuffixes);
251 
252   service_->ReadConfig(base::BindRepeating(
253       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
254   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
255   RunUntilIdle();
256   ASSERT_TRUE(seen_config_);
257   EXPECT_EQ(real_config_.search, kSuffixes);
258 }
259 
TEST_F(DnsConfigServiceAndroidTest,ReadsEmptySearchSuffixes)260 TEST_F(DnsConfigServiceAndroidTest, ReadsEmptySearchSuffixes) {
261   SKIP_ANDROID_VERSIONS_BEFORE_M();
262 
263   mock_dns_server_getter_->set_retval(true);
264   mock_dns_server_getter_->set_dns_servers({kNameserver1});
265 
266   service_->ReadConfig(base::BindRepeating(
267       &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
268   FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
269   RunUntilIdle();
270   ASSERT_TRUE(seen_config_);
271   EXPECT_TRUE(real_config_.search.empty());
272 }
273 
274 }  // namespace
275 }  // namespace net::internal
276