1 // Copyright 2014 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.h"
6
7 #include "base/run_loop.h"
8 #include "build/build_config.h"
9 #include "net/base/mock_network_change_notifier.h"
10 #include "net/base/network_interfaces.h"
11 #include "net/test/test_connection_cost_observer.h"
12 #include "net/test/test_with_task_environment.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace net {
16
17 // Note: This test is subject to the host's OS and network connection. This test
18 // is not future-proof. New standards will come about necessitating the need to
19 // alter the ranges of these tests.
TEST(NetworkChangeNotifierTest,NetMaxBandwidthRange)20 TEST(NetworkChangeNotifierTest, NetMaxBandwidthRange) {
21 NetworkChangeNotifier::ConnectionType connection_type =
22 NetworkChangeNotifier::CONNECTION_NONE;
23 double max_bandwidth = 0.0;
24 NetworkChangeNotifier::GetMaxBandwidthAndConnectionType(&max_bandwidth,
25 &connection_type);
26
27 // Always accept infinity as it's the default value if the bandwidth is
28 // unknown.
29 if (max_bandwidth == std::numeric_limits<double>::infinity()) {
30 EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE, connection_type);
31 return;
32 }
33
34 switch (connection_type) {
35 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
36 EXPECT_EQ(std::numeric_limits<double>::infinity(), max_bandwidth);
37 break;
38 case NetworkChangeNotifier::CONNECTION_ETHERNET:
39 EXPECT_GE(10.0, max_bandwidth);
40 EXPECT_LE(10000.0, max_bandwidth);
41 break;
42 case NetworkChangeNotifier::CONNECTION_WIFI:
43 EXPECT_GE(1.0, max_bandwidth);
44 EXPECT_LE(7000.0, max_bandwidth);
45 break;
46 case NetworkChangeNotifier::CONNECTION_2G:
47 EXPECT_GE(0.01, max_bandwidth);
48 EXPECT_LE(0.384, max_bandwidth);
49 break;
50 case NetworkChangeNotifier::CONNECTION_3G:
51 EXPECT_GE(2.0, max_bandwidth);
52 EXPECT_LE(42.0, max_bandwidth);
53 break;
54 case NetworkChangeNotifier::CONNECTION_4G:
55 EXPECT_GE(100.0, max_bandwidth);
56 EXPECT_LE(100.0, max_bandwidth);
57 break;
58 case NetworkChangeNotifier::CONNECTION_5G:
59 // TODO(crbug.com/40148439): Expect proper bounds once we have introduced
60 // subtypes for 5G connections.
61 EXPECT_EQ(std::numeric_limits<double>::infinity(), max_bandwidth);
62 break;
63 case NetworkChangeNotifier::CONNECTION_NONE:
64 EXPECT_EQ(0.0, max_bandwidth);
65 break;
66 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
67 EXPECT_GE(1.0, max_bandwidth);
68 EXPECT_LE(24.0, max_bandwidth);
69 break;
70 }
71 }
72
TEST(NetworkChangeNotifierTest,ConnectionTypeFromInterfaceList)73 TEST(NetworkChangeNotifierTest, ConnectionTypeFromInterfaceList) {
74 NetworkInterfaceList list;
75
76 // Test empty list.
77 EXPECT_EQ(NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list),
78 NetworkChangeNotifier::CONNECTION_NONE);
79
80 for (int i = NetworkChangeNotifier::CONNECTION_UNKNOWN;
81 i <= NetworkChangeNotifier::CONNECTION_LAST; i++) {
82 // Check individual types.
83 NetworkInterface interface;
84 interface.type = static_cast<NetworkChangeNotifier::ConnectionType>(i);
85 list.clear();
86 list.push_back(interface);
87 EXPECT_EQ(NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list), i);
88 // Check two types.
89 for (int j = NetworkChangeNotifier::CONNECTION_UNKNOWN;
90 j <= NetworkChangeNotifier::CONNECTION_LAST; j++) {
91 list.clear();
92 interface.type = static_cast<NetworkChangeNotifier::ConnectionType>(i);
93 list.push_back(interface);
94 interface.type = static_cast<NetworkChangeNotifier::ConnectionType>(j);
95 list.push_back(interface);
96 EXPECT_EQ(NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list),
97 i == j ? i : NetworkChangeNotifier::CONNECTION_UNKNOWN);
98 }
99 }
100 }
101
TEST(NetworkChangeNotifierTest,IgnoreTeredoOnWindows)102 TEST(NetworkChangeNotifierTest, IgnoreTeredoOnWindows) {
103 NetworkInterfaceList list;
104 NetworkInterface interface_teredo;
105 interface_teredo.type = NetworkChangeNotifier::CONNECTION_ETHERNET;
106 interface_teredo.friendly_name = "Teredo Tunneling Pseudo-Interface";
107 list.push_back(interface_teredo);
108
109 #if BUILDFLAG(IS_WIN)
110 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
111 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
112 #else
113 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_ETHERNET,
114 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
115 #endif
116 }
117
TEST(NetworkChangeNotifierTest,IgnoreAirdropOnMac)118 TEST(NetworkChangeNotifierTest, IgnoreAirdropOnMac) {
119 NetworkInterfaceList list;
120 NetworkInterface interface_airdrop;
121 interface_airdrop.type = NetworkChangeNotifier::CONNECTION_ETHERNET;
122 interface_airdrop.name = "awdl0";
123 interface_airdrop.friendly_name = "awdl0";
124 interface_airdrop.address =
125 // Link-local IPv6 address
126 IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4);
127 list.push_back(interface_airdrop);
128
129 #if BUILDFLAG(IS_APPLE)
130 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
131 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
132 #else
133 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_ETHERNET,
134 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
135 #endif
136 }
137
TEST(NetworkChangeNotifierTest,IgnoreTunnelsOnMac)138 TEST(NetworkChangeNotifierTest, IgnoreTunnelsOnMac) {
139 NetworkInterfaceList list;
140 NetworkInterface interface_tunnel;
141 interface_tunnel.type = NetworkChangeNotifier::CONNECTION_ETHERNET;
142 interface_tunnel.name = "utun0";
143 interface_tunnel.friendly_name = "utun0";
144 interface_tunnel.address =
145 // Link-local IPv6 address
146 IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 3, 2, 1);
147 list.push_back(interface_tunnel);
148
149 #if BUILDFLAG(IS_APPLE)
150 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
151 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
152 #else
153 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_ETHERNET,
154 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
155 #endif
156 }
157
TEST(NetworkChangeNotifierTest,IgnoreDisconnectedEthernetOnMac)158 TEST(NetworkChangeNotifierTest, IgnoreDisconnectedEthernetOnMac) {
159 NetworkInterfaceList list;
160 NetworkInterface interface_ethernet;
161 interface_ethernet.type = NetworkChangeNotifier::CONNECTION_ETHERNET;
162 interface_ethernet.name = "en5";
163 interface_ethernet.friendly_name = "en5";
164 interface_ethernet.address =
165 // Link-local IPv6 address
166 IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3);
167 list.push_back(interface_ethernet);
168
169 #if BUILDFLAG(IS_APPLE)
170 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
171 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
172 #else
173 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_ETHERNET,
174 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
175 #endif
176 }
177
TEST(NetworkChangeNotifierTest,IgnoreVMInterfaces)178 TEST(NetworkChangeNotifierTest, IgnoreVMInterfaces) {
179 NetworkInterfaceList list;
180 NetworkInterface interface_vmnet_linux;
181 interface_vmnet_linux.type = NetworkChangeNotifier::CONNECTION_ETHERNET;
182 interface_vmnet_linux.name = "vmnet1";
183 interface_vmnet_linux.friendly_name = "vmnet1";
184 list.push_back(interface_vmnet_linux);
185
186 NetworkInterface interface_vmnet_win;
187 interface_vmnet_win.type = NetworkChangeNotifier::CONNECTION_ETHERNET;
188 interface_vmnet_win.name = "virtualdevice";
189 interface_vmnet_win.friendly_name = "VMware Network Adapter VMnet1";
190 list.push_back(interface_vmnet_win);
191
192 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
193 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(list));
194 }
195
TEST(NetworkChangeNotifierTest,GetConnectionSubtype)196 TEST(NetworkChangeNotifierTest, GetConnectionSubtype) {
197 // Call GetConnectionSubtype() and ensure that there is no crash.
198 NetworkChangeNotifier::GetConnectionSubtype();
199 }
200
201 class NetworkChangeNotifierMockedTest : public TestWithTaskEnvironment {
202 protected:
203 test::ScopedMockNetworkChangeNotifier mock_notifier_;
204 };
205
206 class TestDnsObserver : public NetworkChangeNotifier::DNSObserver {
207 public:
OnDNSChanged()208 void OnDNSChanged() override { ++dns_changed_calls_; }
209
dns_changed_calls() const210 int dns_changed_calls() const { return dns_changed_calls_; }
211
212 private:
213 int dns_changed_calls_ = 0;
214 };
215
TEST_F(NetworkChangeNotifierMockedTest,TriggerNonSystemDnsChange)216 TEST_F(NetworkChangeNotifierMockedTest, TriggerNonSystemDnsChange) {
217 TestDnsObserver observer;
218 NetworkChangeNotifier::AddDNSObserver(&observer);
219
220 ASSERT_EQ(0, observer.dns_changed_calls());
221
222 NetworkChangeNotifier::TriggerNonSystemDnsChange();
223 base::RunLoop().RunUntilIdle();
224
225 EXPECT_EQ(1, observer.dns_changed_calls());
226
227 NetworkChangeNotifier::RemoveDNSObserver(&observer);
228 }
229
TEST_F(NetworkChangeNotifierMockedTest,TriggerConnectionCostChange)230 TEST_F(NetworkChangeNotifierMockedTest, TriggerConnectionCostChange) {
231 TestConnectionCostObserver observer;
232 NetworkChangeNotifier::AddConnectionCostObserver(&observer);
233
234 ASSERT_EQ(0u, observer.cost_changed_calls());
235
236 NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeForTests(
237 NetworkChangeNotifier::CONNECTION_COST_METERED);
238 base::RunLoop().RunUntilIdle();
239
240 EXPECT_EQ(1u, observer.cost_changed_calls());
241 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_METERED,
242 observer.cost_changed_inputs()[0]);
243
244 NetworkChangeNotifier::RemoveConnectionCostObserver(&observer);
245 NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeForTests(
246 NetworkChangeNotifier::CONNECTION_COST_UNMETERED);
247 base::RunLoop().RunUntilIdle();
248
249 EXPECT_EQ(1u, observer.cost_changed_calls());
250 }
251
TEST_F(NetworkChangeNotifierMockedTest,ConnectionCostDefaultsToCellular)252 TEST_F(NetworkChangeNotifierMockedTest, ConnectionCostDefaultsToCellular) {
253 mock_notifier_.mock_network_change_notifier()
254 ->SetUseDefaultConnectionCostImplementation(true);
255
256 mock_notifier_.mock_network_change_notifier()->SetConnectionType(
257 NetworkChangeNotifier::CONNECTION_4G);
258 EXPECT_TRUE(NetworkChangeNotifier::IsConnectionCellular(
259 NetworkChangeNotifier::GetConnectionType()));
260 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_METERED,
261 NetworkChangeNotifier::GetConnectionCost());
262
263 mock_notifier_.mock_network_change_notifier()->SetConnectionType(
264 NetworkChangeNotifier::CONNECTION_WIFI);
265 EXPECT_FALSE(NetworkChangeNotifier::IsConnectionCellular(
266 NetworkChangeNotifier::GetConnectionType()));
267 EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_UNMETERED,
268 NetworkChangeNotifier::GetConnectionCost());
269 }
270
271 class NetworkChangeNotifierConnectionCostTest : public TestWithTaskEnvironment {
272 public:
SetUp()273 void SetUp() override {
274 network_change_notifier_ = NetworkChangeNotifier::CreateIfNeeded();
275 }
276
277 private:
278 // Allows creating a new NetworkChangeNotifier. Must be created before
279 // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
280 NetworkChangeNotifier::DisableForTest disable_for_test_;
281 std::unique_ptr<NetworkChangeNotifier> network_change_notifier_;
282 };
283
TEST_F(NetworkChangeNotifierConnectionCostTest,GetConnectionCost)284 TEST_F(NetworkChangeNotifierConnectionCostTest, GetConnectionCost) {
285 EXPECT_NE(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
286 NetworkChangeNotifier::GetConnectionCost());
287 }
288
TEST_F(NetworkChangeNotifierConnectionCostTest,AddObserver)289 TEST_F(NetworkChangeNotifierConnectionCostTest, AddObserver) {
290 TestConnectionCostObserver observer;
291 EXPECT_NO_FATAL_FAILURE(
292 NetworkChangeNotifier::AddConnectionCostObserver(&observer));
293 // RunUntilIdle because the secondary work resulting from adding an observer
294 // may be posted to a task queue.
295 base::RunLoop().RunUntilIdle();
296 }
297
298 } // namespace net
299