• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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_win.h"
6 
7 #include <memory>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/functional/bind.h"
12 #include "base/run_loop.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "base/test/scoped_os_info_override_win.h"
16 #include "base/win/windows_version.h"
17 #include "net/base/network_change_notifier.h"
18 #include "net/base/network_change_notifier_factory.h"
19 #include "net/base/network_cost_change_notifier_win.h"
20 #include "net/test/test_connection_cost_observer.h"
21 #include "net/test/test_with_task_environment.h"
22 #include "net/test/win/fake_network_cost_manager.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 using ::testing::AtLeast;
27 using ::testing::Invoke;
28 using ::testing::Return;
29 using ::testing::StrictMock;
30 
31 namespace net {
32 
33 // Subclass of NetworkChangeNotifierWin that overrides functions so that no
34 // Windows API networking function results effect tests.
35 class TestNetworkChangeNotifierWin : public NetworkChangeNotifierWin {
36  public:
TestNetworkChangeNotifierWin()37   TestNetworkChangeNotifierWin() {
38     last_computed_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
39     last_announced_offline_ = false;
40     sequence_runner_for_registration_ =
41         base::SequencedTaskRunner::GetCurrentDefault();
42   }
43 
44   TestNetworkChangeNotifierWin(const TestNetworkChangeNotifierWin&) = delete;
45   TestNetworkChangeNotifierWin& operator=(const TestNetworkChangeNotifierWin&) =
46       delete;
47 
~TestNetworkChangeNotifierWin()48   ~TestNetworkChangeNotifierWin() override {
49     // This is needed so we don't try to stop watching for IP address changes,
50     // as we never actually started.
51     set_is_watching(false);
52   }
53 
54   // From NetworkChangeNotifierWin.
RecomputeCurrentConnectionTypeOnBlockingSequence(base::OnceCallback<void (ConnectionType)> reply_callback) const55   void RecomputeCurrentConnectionTypeOnBlockingSequence(
56       base::OnceCallback<void(ConnectionType)> reply_callback) const override {
57     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
58         FROM_HERE, base::BindOnce(std::move(reply_callback),
59                                   NetworkChangeNotifier::CONNECTION_UNKNOWN));
60   }
61 
62   // From NetworkChangeNotifierWin.
63   MOCK_METHOD0(WatchForAddressChangeInternal, bool());
64 
65   // Allow tests to compare results with the default implementation that does
66   // not depend on the `INetworkCostManager` Windows OS API.  The default
67   // implementation is used as a fall back when `INetworkCostManager` fails.
GetCurrentConnectionCostFromDefaultImplementationForTesting()68   ConnectionCost GetCurrentConnectionCostFromDefaultImplementationForTesting() {
69     return NetworkChangeNotifier::GetCurrentConnectionCost();
70   }
71 };
72 
73 class TestIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
74  public:
TestIPAddressObserver()75   TestIPAddressObserver() { NetworkChangeNotifier::AddIPAddressObserver(this); }
76 
77   TestIPAddressObserver(const TestIPAddressObserver&) = delete;
78   TestIPAddressObserver& operator=(const TestIPAddressObserver&) = delete;
79 
~TestIPAddressObserver()80   ~TestIPAddressObserver() override {
81     NetworkChangeNotifier::RemoveIPAddressObserver(this);
82   }
83 
84   MOCK_METHOD0(OnIPAddressChanged, void());
85 };
86 
87 class NetworkChangeNotifierWinTest : public TestWithTaskEnvironment {
88  public:
89   // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
90   // success.  Expects that |network_change_notifier_| has just been created, so
91   // it's not watching anything yet, and there have been no previous
92   // WatchForAddressChangeInternal failures.
StartWatchingAndSucceed()93   void StartWatchingAndSucceed() {
94     EXPECT_FALSE(network_change_notifier_.is_watching());
95     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
96 
97     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
98     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
99         .WillOnce(Return(true));
100 
101     network_change_notifier_.WatchForAddressChange();
102 
103     EXPECT_TRUE(network_change_notifier_.is_watching());
104     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
105 
106     // If a task to notify observers of the IP address change event was
107     // incorrectly posted, make sure it gets run to trigger a failure.
108     base::RunLoop().RunUntilIdle();
109   }
110 
111   // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
112   // failure.
StartWatchingAndFail()113   void StartWatchingAndFail() {
114     EXPECT_FALSE(network_change_notifier_.is_watching());
115     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
116 
117     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
118     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
119         // Due to an expected race, it's theoretically possible for more than
120         // one call to occur, though unlikely.
121         .Times(AtLeast(1))
122         .WillRepeatedly(Return(false));
123 
124     network_change_notifier_.WatchForAddressChange();
125 
126     EXPECT_FALSE(network_change_notifier_.is_watching());
127     EXPECT_LT(0, network_change_notifier_.sequential_failures());
128 
129     // If a task to notify observers of the IP address change event was
130     // incorrectly posted, make sure it gets run.
131     base::RunLoop().RunUntilIdle();
132   }
133 
134   // Simulates a network change event, resulting in a call to OnObjectSignaled.
135   // The resulting call to WatchForAddressChangeInternal then succeeds.
SignalAndSucceed()136   void SignalAndSucceed() {
137     EXPECT_TRUE(network_change_notifier_.is_watching());
138     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
139 
140     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
141     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
142         .WillOnce(Return(true));
143 
144     network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
145 
146     EXPECT_TRUE(network_change_notifier_.is_watching());
147     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
148 
149     // Run the task to notify observers of the IP address change event.
150     base::RunLoop().RunUntilIdle();
151   }
152 
153   // Simulates a network change event, resulting in a call to OnObjectSignaled.
154   // The resulting call to WatchForAddressChangeInternal then fails.
SignalAndFail()155   void SignalAndFail() {
156     EXPECT_TRUE(network_change_notifier_.is_watching());
157     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
158 
159     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
160     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
161         // Due to an expected race, it's theoretically possible for more than
162         // one call to occur, though unlikely.
163         .Times(AtLeast(1))
164         .WillRepeatedly(Return(false));
165 
166     network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
167 
168     EXPECT_FALSE(network_change_notifier_.is_watching());
169     EXPECT_LT(0, network_change_notifier_.sequential_failures());
170 
171     // Run the task to notify observers of the IP address change event.
172     base::RunLoop().RunUntilIdle();
173   }
174 
175   // Runs the message loop until WatchForAddressChange is called again, as a
176   // result of the already posted task after a WatchForAddressChangeInternal
177   // failure.  Simulates a success on the resulting call to
178   // WatchForAddressChangeInternal.
RetryAndSucceed()179   void RetryAndSucceed() {
180     EXPECT_FALSE(network_change_notifier_.is_watching());
181     EXPECT_LT(0, network_change_notifier_.sequential_failures());
182 
183     base::RunLoop run_loop;
184 
185     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged())
186         .WillOnce(Invoke(&run_loop, &base::RunLoop::QuitWhenIdle));
187     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
188         .WillOnce(Return(true));
189 
190     run_loop.Run();
191 
192     EXPECT_TRUE(network_change_notifier_.is_watching());
193     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
194   }
195 
196   // Runs the message loop until WatchForAddressChange is called again, as a
197   // result of the already posted task after a WatchForAddressChangeInternal
198   // failure.  Simulates a failure on the resulting call to
199   // WatchForAddressChangeInternal.
RetryAndFail()200   void RetryAndFail() {
201     base::RunLoop loop;
202     EXPECT_FALSE(network_change_notifier_.is_watching());
203     EXPECT_LT(0, network_change_notifier_.sequential_failures());
204 
205     int initial_sequential_failures =
206         network_change_notifier_.sequential_failures();
207 
208     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
209     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
210         // Due to an expected race, it's theoretically possible for more than
211         // one call to occur, though unlikely.
212         .Times(AtLeast(1))
213         .WillRepeatedly(Invoke([&loop]() {
214           loop.QuitWhenIdle();
215           return false;
216         }));
217 
218     loop.Run();
219 
220     EXPECT_FALSE(network_change_notifier_.is_watching());
221     EXPECT_LT(initial_sequential_failures,
222               network_change_notifier_.sequential_failures());
223 
224     // If a task to notify observers of the IP address change event was
225     // incorrectly posted, make sure it gets run.
226     base::RunLoop().RunUntilIdle();
227   }
228 
GetCurrentConnectionCost()229   NetworkChangeNotifier::ConnectionCost GetCurrentConnectionCost() {
230     return network_change_notifier_.GetCurrentConnectionCost();
231   }
232 
233   NetworkChangeNotifier::ConnectionCost
GetCurrentConnectionCostFromDefaultImplementationForTesting()234   GetCurrentConnectionCostFromDefaultImplementationForTesting() {
235     return network_change_notifier_
236         .GetCurrentConnectionCostFromDefaultImplementationForTesting();
237   }
238 
239  protected:
240   FakeNetworkCostManagerEnvironment fake_network_cost_manager_environment_;
241 
242  private:
243   // Note that the order of declaration here is important.
244 
245   // Allows creating a new NetworkChangeNotifier.  Must be created before
246   // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
247   NetworkChangeNotifier::DisableForTest disable_for_test_;
248 
249   StrictMock<TestNetworkChangeNotifierWin> network_change_notifier_;
250 
251   // Must be created after |network_change_notifier_|, so it can add itself as
252   // an IPAddressObserver.
253   StrictMock<TestIPAddressObserver> test_ip_address_observer_;
254 };
255 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinBasic)256 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinBasic) {
257   StartWatchingAndSucceed();
258 }
259 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStart)260 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStart) {
261   StartWatchingAndFail();
262 }
263 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStartOnce)264 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartOnce) {
265   StartWatchingAndFail();
266   RetryAndSucceed();
267 }
268 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStartTwice)269 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartTwice) {
270   StartWatchingAndFail();
271   RetryAndFail();
272   RetryAndSucceed();
273 }
274 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinSignal)275 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinSignal) {
276   StartWatchingAndSucceed();
277   SignalAndSucceed();
278 }
279 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailSignalOnce)280 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalOnce) {
281   StartWatchingAndSucceed();
282   SignalAndFail();
283   RetryAndSucceed();
284 }
285 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailSignalTwice)286 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalTwice) {
287   StartWatchingAndSucceed();
288   SignalAndFail();
289   RetryAndFail();
290   RetryAndSucceed();
291 }
292 
TEST_F(NetworkChangeNotifierWinTest,GetCurrentCost)293 TEST_F(NetworkChangeNotifierWinTest, GetCurrentCost) {
294   if (base::win::GetVersion() <
295       NetworkCostChangeNotifierWin::kSupportedOsVersion) {
296     GTEST_SKIP();
297   }
298 
299   fake_network_cost_manager_environment_.SetCost(
300       NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
301 
302   // Wait for `NetworkCostChangeNotifierWin` to finish initializing.
303   RunUntilIdle();
304 
305   EXPECT_EQ(GetCurrentConnectionCost(),
306             NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
307 
308   fake_network_cost_manager_environment_.SetCost(
309       NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
310 
311   // Wait for `NetworkCostChangeNotifierWin` to handle the cost changed event.
312   RunUntilIdle();
313 
314   EXPECT_EQ(GetCurrentConnectionCost(),
315             NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
316 }
317 
TEST_F(NetworkChangeNotifierWinTest,CostChangeObserver)318 TEST_F(NetworkChangeNotifierWinTest, CostChangeObserver) {
319   if (base::win::GetVersion() <
320       NetworkCostChangeNotifierWin::kSupportedOsVersion) {
321     GTEST_SKIP();
322   }
323 
324   fake_network_cost_manager_environment_.SetCost(
325       NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
326 
327   // Wait for `NetworkCostChangeNotifierWin` to finish initializing.
328   RunUntilIdle();
329 
330   TestConnectionCostObserver cost_observer;
331   NetworkChangeNotifier::AddConnectionCostObserver(&cost_observer);
332 
333   fake_network_cost_manager_environment_.SetCost(
334       NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
335 
336   cost_observer.WaitForConnectionCostChanged();
337 
338   ASSERT_EQ(cost_observer.cost_changed_calls(), 1u);
339   EXPECT_EQ(cost_observer.last_cost_changed_input(),
340             NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
341 
342   NetworkChangeNotifier::RemoveConnectionCostObserver(&cost_observer);
343 }
344 
345 // Uses the fake implementation of `INetworkCostManager` to simulate `GetCost()`
346 // returning an error `HRESULT`.
347 class NetworkChangeNotifierWinCostErrorTest
348     : public NetworkChangeNotifierWinTest {
SetUp()349   void SetUp() override {
350     if (base::win::GetVersion() <
351         NetworkCostChangeNotifierWin::kSupportedOsVersion) {
352       GTEST_SKIP();
353     }
354 
355     fake_network_cost_manager_environment_.SimulateError(
356         NetworkCostManagerStatus::kErrorGetCostFailed);
357 
358     NetworkChangeNotifierWinTest::SetUp();
359   }
360 };
361 
TEST_F(NetworkChangeNotifierWinCostErrorTest,CostError)362 TEST_F(NetworkChangeNotifierWinCostErrorTest, CostError) {
363   // Wait for `NetworkCostChangeNotifierWin` to finish initializing, which
364   // should fail with an error.
365   RunUntilIdle();
366 
367   // `NetworkChangeNotifierWin` must use the default implementation when
368   // `NetworkCostChangeNotifierWin` returns an unknown cost.
369   EXPECT_EQ(GetCurrentConnectionCost(),
370             GetCurrentConnectionCostFromDefaultImplementationForTesting());
371 }
372 
373 // Override the Windows OS version to simulate running on an OS that does not
374 // support `INetworkCostManager`.
375 class NetworkChangeNotifierWinCostUnsupportedOsTest
376     : public NetworkChangeNotifierWinTest {
377  public:
NetworkChangeNotifierWinCostUnsupportedOsTest()378   NetworkChangeNotifierWinCostUnsupportedOsTest()
379       : os_override_(base::test::ScopedOSInfoOverride::Type::kWinServer2016) {}
380 
381  protected:
382   base::test::ScopedOSInfoOverride os_override_;
383 };
384 
TEST_F(NetworkChangeNotifierWinCostUnsupportedOsTest,CostWithUnsupportedOS)385 TEST_F(NetworkChangeNotifierWinCostUnsupportedOsTest, CostWithUnsupportedOS) {
386   // Wait for `NetworkCostChangeNotifierWin` to finish initializing, which
387   // should initialize with an unknown cost on an unsupported OS.
388   RunUntilIdle();
389 
390   // `NetworkChangeNotifierWin` must use the default implementation when
391   // `NetworkCostChangeNotifierWin` returns an unknown cost.
392   EXPECT_EQ(GetCurrentConnectionCost(),
393             GetCurrentConnectionCostFromDefaultImplementationForTesting());
394 }
395 
396 }  // namespace net
397