xref: /aosp_15_r20/external/cronet/net/base/network_change_notifier_apple_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2024 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/base/network_change_notifier_apple.h"
6 
7 #include <optional>
8 #include <string>
9 
10 #include "base/apple/scoped_cftyperef.h"
11 #include "base/location.h"
12 #include "base/test/bind.h"
13 #include "base/test/scoped_feature_list.h"
14 #include "base/threading/thread.h"
15 #include "net/base/features.h"
16 #include "net/base/network_change_notifier.h"
17 #include "net/base/network_config_watcher_apple.h"
18 #include "net/test/test_with_task_environment.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace net {
23 namespace {
24 
25 static const char kIPv4PrivateAddrString1[] = "192.168.0.1";
26 static const char kIPv4PrivateAddrString2[] = "192.168.0.2";
27 
28 static const char kIPv6PublicAddrString1[] =
29     "2401:fa00:4:1000:be30:5b30:50e5:c0";
30 static const char kIPv6PublicAddrString2[] =
31     "2401:fa00:4:1000:be30:5b30:50e5:c1";
32 static const char kIPv6LinkLocalAddrString1[] = "fe80::0:1:1:1";
33 static const char kIPv6LinkLocalAddrString2[] = "fe80::0:2:2:2";
34 
35 class TestIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
36  public:
TestIPAddressObserver()37   TestIPAddressObserver() { NetworkChangeNotifier::AddIPAddressObserver(this); }
38 
39   TestIPAddressObserver(const TestIPAddressObserver&) = delete;
40   TestIPAddressObserver& operator=(const TestIPAddressObserver&) = delete;
41 
~TestIPAddressObserver()42   ~TestIPAddressObserver() override {
43     NetworkChangeNotifier::RemoveIPAddressObserver(this);
44   }
45 
46   // Implements NetworkChangeNotifier::IPAddressObserver:
OnIPAddressChanged()47   void OnIPAddressChanged() override { ip_address_changed_ = true; }
48 
ip_address_changed() const49   bool ip_address_changed() const { return ip_address_changed_; }
50 
51  private:
52   bool ip_address_changed_ = false;
53 };
54 
55 }  // namespace
56 
57 class NetworkChangeNotifierAppleTest : public WithTaskEnvironment,
58                                        public ::testing::TestWithParam<bool> {
59  public:
NetworkChangeNotifierAppleTest()60   NetworkChangeNotifierAppleTest() {
61     if (ReduceIPAddressChangeNotificationEnabled()) {
62       feature_list_.InitWithFeatures(
63           /*enabled_features=*/{features::kReduceIPAddressChangeNotification},
64           /*disabled_features=*/{});
65     } else {
66       feature_list_.InitWithFeatures(
67           /*enabled_features=*/{},
68           /*disabled_features=*/{features::kReduceIPAddressChangeNotification});
69     }
70   }
71   NetworkChangeNotifierAppleTest(const NetworkChangeNotifierAppleTest&) =
72       delete;
73   NetworkChangeNotifierAppleTest& operator=(
74       const NetworkChangeNotifierAppleTest&) = delete;
75   ~NetworkChangeNotifierAppleTest() override = default;
76 
TearDown()77   void TearDown() override { RunUntilIdle(); }
78 
79  protected:
ReduceIPAddressChangeNotificationEnabled() const80   bool ReduceIPAddressChangeNotificationEnabled() const { return GetParam(); }
81 
82   std::unique_ptr<NetworkChangeNotifierApple>
CreateNetworkChangeNotifierApple()83   CreateNetworkChangeNotifierApple() {
84     auto notifier = std::make_unique<NetworkChangeNotifierApple>();
85     base::RunLoop run_loop;
86     notifier->SetCallbacksForTest(
87         run_loop.QuitClosure(),
88         base::BindRepeating(
89             [](std::optional<NetworkInterfaceList>* network_interface_list,
90                NetworkInterfaceList* list_out, int) {
91               if (!network_interface_list->has_value()) {
92                 return false;
93               }
94               *list_out = **network_interface_list;
95               return true;
96             },
97             &network_interface_list_),
98         base::BindRepeating(
99             [](std::string* ipv6_primary_interface_name, SCDynamicStoreRef)
100                 -> std::string { return *ipv6_primary_interface_name; },
101             &ipv6_primary_interface_name_));
102     run_loop.Run();
103     return notifier;
104   }
105 
SimulateDynamicStoreCallback(NetworkChangeNotifierApple & notifier,CFStringRef entity)106   void SimulateDynamicStoreCallback(NetworkChangeNotifierApple& notifier,
107                                     CFStringRef entity) {
108     base::RunLoop run_loop;
109     notifier.config_watcher_->GetNotifierThreadForTest()
110         ->task_runner()
111         ->PostTask(
112             FROM_HERE, base::BindLambdaForTesting([&]() {
113               base::apple::ScopedCFTypeRef<CFMutableArrayRef> array(
114                   CFArrayCreateMutable(nullptr,
115                                        /*capacity=*/0, &kCFTypeArrayCallBacks));
116               base::apple::ScopedCFTypeRef<CFStringRef> entry_key(
117                   SCDynamicStoreKeyCreateNetworkGlobalEntity(
118                       nullptr, kSCDynamicStoreDomainState, entity));
119               CFArrayAppendValue(array.get(), entry_key.get());
120               notifier.OnNetworkConfigChange(array.get());
121               run_loop.Quit();
122             }));
123     run_loop.Run();
124   }
125 
126  protected:
127   std::optional<NetworkInterfaceList> network_interface_list_ =
128       NetworkInterfaceList();
129   std::string ipv6_primary_interface_name_ = "en0";
130 
131  private:
132   // Allows us to allocate our own NetworkChangeNotifier for unit testing.
133   NetworkChangeNotifier::DisableForTest disable_for_test_;
134   base::test::ScopedFeatureList feature_list_;
135 };
136 
137 INSTANTIATE_TEST_SUITE_P(
138     All,
139     NetworkChangeNotifierAppleTest,
140     ::testing::Values(true, false),
__anone36180530502(const testing::TestParamInfo<bool>& info) 141     [](const testing::TestParamInfo<bool>& info) {
142       return info.param ? "ReduceIPAddressChangeNotificationEnabled"
143                         : "ReduceIPAddressChangeNotificationDisabled";
144     });
145 
TEST_P(NetworkChangeNotifierAppleTest,NoInterfaceChange)146 TEST_P(NetworkChangeNotifierAppleTest, NoInterfaceChange) {
147   net::IPAddress ip_address;
148   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv4PrivateAddrString1));
149   network_interface_list_->push_back(net::NetworkInterface(
150       "en0", "en0", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
151       ip_address, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
152 
153   std::unique_ptr<NetworkChangeNotifierApple> notifier =
154       CreateNetworkChangeNotifierApple();
155 
156   // Simulate OnNetworkConfigChange callback without any change in
157   // NetworkInterfaceList
158   TestIPAddressObserver observer;
159   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
160   RunUntilIdle();
161   // When kReduceIPAddressChangeNotification feature is enabled, we ignores
162   // the OnNetworkConfigChange callback without any network interface change.
163   EXPECT_EQ(observer.ip_address_changed(),
164             !ReduceIPAddressChangeNotificationEnabled());
165 }
166 
TEST_P(NetworkChangeNotifierAppleTest,IPv4AddressChange)167 TEST_P(NetworkChangeNotifierAppleTest, IPv4AddressChange) {
168   net::IPAddress ip_address;
169   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv4PrivateAddrString1));
170   network_interface_list_->push_back(net::NetworkInterface(
171       "en0", "en0", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
172       ip_address, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
173 
174   std::unique_ptr<NetworkChangeNotifierApple> notifier =
175       CreateNetworkChangeNotifierApple();
176 
177   // Simulate OnNetworkConfigChange callback with IPv4 address change.
178   EXPECT_TRUE((*network_interface_list_)[0].address.AssignFromIPLiteral(
179       kIPv4PrivateAddrString2));
180   TestIPAddressObserver observer;
181   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
182   RunUntilIdle();
183   EXPECT_TRUE(observer.ip_address_changed());
184 }
185 
TEST_P(NetworkChangeNotifierAppleTest,PublicIPv6AddressChange)186 TEST_P(NetworkChangeNotifierAppleTest, PublicIPv6AddressChange) {
187   net::IPAddress ip_address;
188   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv6PublicAddrString1));
189   network_interface_list_->push_back(net::NetworkInterface(
190       "en0", "en0", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
191       ip_address, 64, net::IP_ADDRESS_ATTRIBUTE_NONE));
192 
193   std::unique_ptr<NetworkChangeNotifierApple> notifier =
194       CreateNetworkChangeNotifierApple();
195 
196   // Simulate OnNetworkConfigChange callback with a public IPv6 address change.
197   EXPECT_TRUE((*network_interface_list_)[0].address.AssignFromIPLiteral(
198       kIPv6PublicAddrString2));
199   TestIPAddressObserver observer;
200   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv6);
201   RunUntilIdle();
202   EXPECT_TRUE(observer.ip_address_changed());
203 }
204 
TEST_P(NetworkChangeNotifierAppleTest,LinkLocalIPv6AddressChangeOnPrimaryInterface)205 TEST_P(NetworkChangeNotifierAppleTest,
206        LinkLocalIPv6AddressChangeOnPrimaryInterface) {
207   net::IPAddress ip_address;
208   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv6LinkLocalAddrString1));
209   network_interface_list_->push_back(net::NetworkInterface(
210       "en0", "en0", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
211       ip_address, 64, net::IP_ADDRESS_ATTRIBUTE_NONE));
212 
213   std::unique_ptr<NetworkChangeNotifierApple> notifier =
214       CreateNetworkChangeNotifierApple();
215 
216   // Simulate OnNetworkConfigChange callback with a link local IPv6 address
217   // change on the primary interface "en0".
218   EXPECT_TRUE((*network_interface_list_)[0].address.AssignFromIPLiteral(
219       kIPv6LinkLocalAddrString2));
220   TestIPAddressObserver observer;
221   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
222   RunUntilIdle();
223   EXPECT_TRUE(observer.ip_address_changed());
224 }
225 
TEST_P(NetworkChangeNotifierAppleTest,LinkLocalIPv6AddressChangeOnNonPrimaryInterface)226 TEST_P(NetworkChangeNotifierAppleTest,
227        LinkLocalIPv6AddressChangeOnNonPrimaryInterface) {
228   net::IPAddress ip_address1;
229   EXPECT_TRUE(ip_address1.AssignFromIPLiteral(kIPv4PrivateAddrString1));
230   network_interface_list_->push_back(net::NetworkInterface(
231       "en0", "en0", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
232       ip_address1, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
233 
234   net::IPAddress ip_address2;
235   EXPECT_TRUE(ip_address2.AssignFromIPLiteral(kIPv6LinkLocalAddrString1));
236   network_interface_list_->push_back(net::NetworkInterface(
237       "en1", "en1", 2, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
238       ip_address2, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
239 
240   std::unique_ptr<NetworkChangeNotifierApple> notifier =
241       CreateNetworkChangeNotifierApple();
242 
243   // Simulate OnNetworkConfigChange callback with a link local IPv6 address
244   // change on the non-primary interface "en1".
245   EXPECT_TRUE((*network_interface_list_)[1].address.AssignFromIPLiteral(
246       kIPv6LinkLocalAddrString2));
247   TestIPAddressObserver observer;
248   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
249   RunUntilIdle();
250   // When kReduceIPAddressChangeNotification feature is enabled, we ignores
251   // the link local IPv6 address change on the non-primary interface.
252   EXPECT_EQ(observer.ip_address_changed(),
253             !ReduceIPAddressChangeNotificationEnabled());
254 }
255 
TEST_P(NetworkChangeNotifierAppleTest,NewInterfaceWithIpV4)256 TEST_P(NetworkChangeNotifierAppleTest, NewInterfaceWithIpV4) {
257   net::IPAddress ip_address;
258   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv4PrivateAddrString1));
259   network_interface_list_->push_back(net::NetworkInterface(
260       "en0", "en0", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
261       ip_address, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
262 
263   std::unique_ptr<NetworkChangeNotifierApple> notifier =
264       CreateNetworkChangeNotifierApple();
265 
266   // Simulate OnNetworkConfigChange callback with a new interface with a IPv4
267   // address.
268   net::IPAddress ip_address2;
269   EXPECT_TRUE(ip_address2.AssignFromIPLiteral(kIPv4PrivateAddrString2));
270   network_interface_list_->push_back(net::NetworkInterface(
271       "en1", "en1", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
272       ip_address2, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
273 
274   TestIPAddressObserver observer;
275   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
276   RunUntilIdle();
277   EXPECT_TRUE(observer.ip_address_changed());
278 }
279 
TEST_P(NetworkChangeNotifierAppleTest,NewInterfaceWithLinkLocalIpV6)280 TEST_P(NetworkChangeNotifierAppleTest, NewInterfaceWithLinkLocalIpV6) {
281   net::IPAddress ip_address;
282   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv4PrivateAddrString1));
283   network_interface_list_->push_back(net::NetworkInterface(
284       "en0", "en0", 2, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
285       ip_address, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
286 
287   std::unique_ptr<NetworkChangeNotifierApple> notifier =
288       CreateNetworkChangeNotifierApple();
289 
290   // Simulate OnNetworkConfigChange callback with a new interface with a link
291   // local IPv6 address.
292   net::IPAddress ip_address2;
293   EXPECT_TRUE(ip_address2.AssignFromIPLiteral(kIPv6LinkLocalAddrString1));
294   EXPECT_FALSE(ip_address2.IsPubliclyRoutable());
295   network_interface_list_->push_back(net::NetworkInterface(
296       "en1", "en1", 1, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
297       ip_address2, 64, net::IP_ADDRESS_ATTRIBUTE_NONE));
298 
299   TestIPAddressObserver observer;
300   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
301   RunUntilIdle();
302   // When kReduceIPAddressChangeNotification feature is enabled, we ignores
303   // the new link local IPv6 interface.
304   EXPECT_EQ(observer.ip_address_changed(),
305             !ReduceIPAddressChangeNotificationEnabled());
306 }
307 
TEST_P(NetworkChangeNotifierAppleTest,NewInterfaceWithPublicIpV6)308 TEST_P(NetworkChangeNotifierAppleTest, NewInterfaceWithPublicIpV6) {
309   net::IPAddress ip_address;
310   EXPECT_TRUE(ip_address.AssignFromIPLiteral(kIPv4PrivateAddrString1));
311   network_interface_list_->push_back(net::NetworkInterface(
312       "en0", "en0", 2, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
313       ip_address, 0, net::IP_ADDRESS_ATTRIBUTE_NONE));
314 
315   std::unique_ptr<NetworkChangeNotifierApple> notifier =
316       CreateNetworkChangeNotifierApple();
317 
318   // Simulate OnNetworkConfigChange callback with a new interface with a
319   // public IPv6 address.
320   net::IPAddress ip_address2;
321   EXPECT_TRUE(ip_address2.AssignFromIPLiteral(kIPv6PublicAddrString1));
322   EXPECT_TRUE(ip_address2.IsPubliclyRoutable());
323   network_interface_list_->push_back(net::NetworkInterface(
324       "en1", "en1", 2, net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
325       ip_address2, 64, net::IP_ADDRESS_ATTRIBUTE_NONE));
326 
327   TestIPAddressObserver observer;
328   SimulateDynamicStoreCallback(*notifier, kSCEntNetIPv4);
329   RunUntilIdle();
330   EXPECT_TRUE(observer.ip_address_changed());
331 }
332 
333 }  // namespace net
334