• 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 <utility>
8 
9 #include "base/functional/bind.h"
10 #include "base/run_loop.h"
11 #include "base/task/sequenced_task_runner.h"
12 #include "base/task/single_thread_task_runner.h"
13 #include "net/base/network_change_notifier.h"
14 #include "net/base/network_change_notifier_factory.h"
15 #include "net/test/test_with_task_environment.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 using ::testing::AtLeast;
20 using ::testing::Invoke;
21 using ::testing::Return;
22 using ::testing::StrictMock;
23 
24 namespace net {
25 
26 // Subclass of NetworkChangeNotifierWin that overrides functions so that no
27 // Windows API networking function results effect tests.
28 class TestNetworkChangeNotifierWin : public NetworkChangeNotifierWin {
29  public:
TestNetworkChangeNotifierWin()30   TestNetworkChangeNotifierWin() {
31     last_computed_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
32     last_announced_offline_ = false;
33     last_computed_connection_cost_ = ConnectionCost::CONNECTION_COST_UNKNOWN;
34     sequence_runner_for_registration_ =
35         base::SequencedTaskRunner::GetCurrentDefault();
36   }
37 
38   TestNetworkChangeNotifierWin(const TestNetworkChangeNotifierWin&) = delete;
39   TestNetworkChangeNotifierWin& operator=(const TestNetworkChangeNotifierWin&) =
40       delete;
41 
~TestNetworkChangeNotifierWin()42   ~TestNetworkChangeNotifierWin() override {
43     // This is needed so we don't try to stop watching for IP address changes,
44     // as we never actually started.
45     set_is_watching(false);
46   }
47 
48   // From NetworkChangeNotifierWin.
RecomputeCurrentConnectionTypeOnBlockingSequence(base::OnceCallback<void (ConnectionType)> reply_callback) const49   void RecomputeCurrentConnectionTypeOnBlockingSequence(
50       base::OnceCallback<void(ConnectionType)> reply_callback) const override {
51     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
52         FROM_HERE, base::BindOnce(std::move(reply_callback),
53                                   NetworkChangeNotifier::CONNECTION_UNKNOWN));
54   }
55 
56   // From NetworkChangeNotifierWin.
57   MOCK_METHOD0(WatchForAddressChangeInternal, bool());
58 };
59 
60 class TestIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
61  public:
TestIPAddressObserver()62   TestIPAddressObserver() {
63     NetworkChangeNotifier::AddIPAddressObserver(this);
64   }
65 
66   TestIPAddressObserver(const TestIPAddressObserver&) = delete;
67   TestIPAddressObserver& operator=(const TestIPAddressObserver&) = delete;
68 
~TestIPAddressObserver()69   ~TestIPAddressObserver() override {
70     NetworkChangeNotifier::RemoveIPAddressObserver(this);
71   }
72 
73   MOCK_METHOD0(OnIPAddressChanged, void());
74 };
75 
ExitMessageLoopAndReturnFalse()76 bool ExitMessageLoopAndReturnFalse() {
77   base::RunLoop::QuitCurrentWhenIdleDeprecated();
78   return false;
79 }
80 
81 class NetworkChangeNotifierWinTest : public TestWithTaskEnvironment {
82  public:
83   // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
84   // success.  Expects that |network_change_notifier_| has just been created, so
85   // it's not watching anything yet, and there have been no previous
86   // WatchForAddressChangeInternal failures.
StartWatchingAndSucceed()87   void StartWatchingAndSucceed() {
88     EXPECT_FALSE(network_change_notifier_.is_watching());
89     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
90 
91     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
92     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
93         .Times(1)
94         .WillOnce(Return(true));
95 
96     network_change_notifier_.WatchForAddressChange();
97 
98     EXPECT_TRUE(network_change_notifier_.is_watching());
99     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
100 
101     // If a task to notify observers of the IP address change event was
102     // incorrectly posted, make sure it gets run to trigger a failure.
103     base::RunLoop().RunUntilIdle();
104   }
105 
106   // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
107   // failure.
StartWatchingAndFail()108   void StartWatchingAndFail() {
109     EXPECT_FALSE(network_change_notifier_.is_watching());
110     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
111 
112     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
113     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
114         // Due to an expected race, it's theoretically possible for more than
115         // one call to occur, though unlikely.
116         .Times(AtLeast(1))
117         .WillRepeatedly(Return(false));
118 
119     network_change_notifier_.WatchForAddressChange();
120 
121     EXPECT_FALSE(network_change_notifier_.is_watching());
122     EXPECT_LT(0, network_change_notifier_.sequential_failures());
123 
124     // If a task to notify observers of the IP address change event was
125     // incorrectly posted, make sure it gets run.
126     base::RunLoop().RunUntilIdle();
127   }
128 
129   // Simulates a network change event, resulting in a call to OnObjectSignaled.
130   // The resulting call to WatchForAddressChangeInternal then succeeds.
SignalAndSucceed()131   void SignalAndSucceed() {
132     EXPECT_TRUE(network_change_notifier_.is_watching());
133     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
134 
135     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
136     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
137         .Times(1)
138         .WillOnce(Return(true));
139 
140     network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
141 
142     EXPECT_TRUE(network_change_notifier_.is_watching());
143     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
144 
145     // Run the task to notify observers of the IP address change event.
146     base::RunLoop().RunUntilIdle();
147   }
148 
149   // Simulates a network change event, resulting in a call to OnObjectSignaled.
150   // The resulting call to WatchForAddressChangeInternal then fails.
SignalAndFail()151   void SignalAndFail() {
152     EXPECT_TRUE(network_change_notifier_.is_watching());
153     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
154 
155     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
156     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
157         // Due to an expected race, it's theoretically possible for more than
158         // one call to occur, though unlikely.
159         .Times(AtLeast(1))
160         .WillRepeatedly(Return(false));
161 
162     network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
163 
164     EXPECT_FALSE(network_change_notifier_.is_watching());
165     EXPECT_LT(0, network_change_notifier_.sequential_failures());
166 
167     // Run the task to notify observers of the IP address change event.
168     base::RunLoop().RunUntilIdle();
169   }
170 
171   // Runs the message loop until WatchForAddressChange is called again, as a
172   // result of the already posted task after a WatchForAddressChangeInternal
173   // failure.  Simulates a success on the resulting call to
174   // WatchForAddressChangeInternal.
RetryAndSucceed()175   void RetryAndSucceed() {
176     EXPECT_FALSE(network_change_notifier_.is_watching());
177     EXPECT_LT(0, network_change_notifier_.sequential_failures());
178 
179     base::RunLoop run_loop;
180 
181     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged())
182         .Times(1)
183         .WillOnce(Invoke(&run_loop, &base::RunLoop::QuitWhenIdle));
184     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
185         .Times(1).WillOnce(Return(true));
186 
187     run_loop.Run();
188 
189     EXPECT_TRUE(network_change_notifier_.is_watching());
190     EXPECT_EQ(0, network_change_notifier_.sequential_failures());
191   }
192 
193   // Runs the message loop until WatchForAddressChange is called again, as a
194   // result of the already posted task after a WatchForAddressChangeInternal
195   // failure.  Simulates a failure on the resulting call to
196   // WatchForAddressChangeInternal.
RetryAndFail()197   void RetryAndFail() {
198     EXPECT_FALSE(network_change_notifier_.is_watching());
199     EXPECT_LT(0, network_change_notifier_.sequential_failures());
200 
201     int initial_sequential_failures =
202         network_change_notifier_.sequential_failures();
203 
204     EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
205     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
206         // Due to an expected race, it's theoretically possible for more than
207         // one call to occur, though unlikely.
208         .Times(AtLeast(1))
209         .WillRepeatedly(Invoke(ExitMessageLoopAndReturnFalse));
210 
211     base::RunLoop().Run();
212 
213     EXPECT_FALSE(network_change_notifier_.is_watching());
214     EXPECT_LT(initial_sequential_failures,
215               network_change_notifier_.sequential_failures());
216 
217     // If a task to notify observers of the IP address change event was
218     // incorrectly posted, make sure it gets run.
219     base::RunLoop().RunUntilIdle();
220   }
221 
HasNetworkCostManager()222   bool HasNetworkCostManager() {
223     return network_change_notifier_.network_cost_manager_.Get() != nullptr;
224   }
225 
HasNetworkCostManagerEventSink()226   bool HasNetworkCostManagerEventSink() {
227     return network_change_notifier_.network_cost_manager_event_sink_.Get() !=
228            nullptr;
229   }
230 
LastComputedConnectionCost()231   NetworkChangeNotifier::ConnectionCost LastComputedConnectionCost() {
232     return network_change_notifier_.last_computed_connection_cost_;
233   }
234 
GetCurrentConnectionCost()235   NetworkChangeNotifier::ConnectionCost GetCurrentConnectionCost() {
236     return network_change_notifier_.GetCurrentConnectionCost();
237   }
238 
239  private:
240   // Note that the order of declaration here is important.
241 
242   // Allows creating a new NetworkChangeNotifier.  Must be created before
243   // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
244   NetworkChangeNotifier::DisableForTest disable_for_test_;
245 
246   StrictMock<TestNetworkChangeNotifierWin> network_change_notifier_;
247 
248   // Must be created after |network_change_notifier_|, so it can add itself as
249   // an IPAddressObserver.
250   StrictMock<TestIPAddressObserver> test_ip_address_observer_;
251 };
252 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinBasic)253 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinBasic) {
254   StartWatchingAndSucceed();
255 }
256 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStart)257 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStart) {
258   StartWatchingAndFail();
259 }
260 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStartOnce)261 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartOnce) {
262   StartWatchingAndFail();
263   RetryAndSucceed();
264 }
265 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStartTwice)266 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartTwice) {
267   StartWatchingAndFail();
268   RetryAndFail();
269   RetryAndSucceed();
270 }
271 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinSignal)272 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinSignal) {
273   StartWatchingAndSucceed();
274   SignalAndSucceed();
275 }
276 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailSignalOnce)277 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalOnce) {
278   StartWatchingAndSucceed();
279   SignalAndFail();
280   RetryAndSucceed();
281 }
282 
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailSignalTwice)283 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalTwice) {
284   StartWatchingAndSucceed();
285   SignalAndFail();
286   RetryAndFail();
287   RetryAndSucceed();
288 }
289 
290 class TestConnectionCostObserver
291     : public NetworkChangeNotifier::ConnectionCostObserver {
292  public:
TestConnectionCostObserver()293   TestConnectionCostObserver() {}
294 
295   TestConnectionCostObserver(const TestConnectionCostObserver&) = delete;
296   TestConnectionCostObserver& operator=(const TestConnectionCostObserver&) =
297       delete;
298 
~TestConnectionCostObserver()299   ~TestConnectionCostObserver() override {
300     NetworkChangeNotifier::RemoveConnectionCostObserver(this);
301   }
302 
OnConnectionCostChanged(NetworkChangeNotifier::ConnectionCost)303   void OnConnectionCostChanged(NetworkChangeNotifier::ConnectionCost) override {
304   }
305 
Register()306   void Register() { NetworkChangeNotifier::AddConnectionCostObserver(this); }
307 };
308 
TEST_F(NetworkChangeNotifierWinTest,NetworkCostManagerIntegration)309 TEST_F(NetworkChangeNotifierWinTest, NetworkCostManagerIntegration) {
310   // Upon creation, none of the NetworkCostManager integration should be
311   // initialized yet.
312   ASSERT_FALSE(HasNetworkCostManager());
313   ASSERT_FALSE(HasNetworkCostManagerEventSink());
314   ASSERT_EQ(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
315             LastComputedConnectionCost());
316 
317   // Asking for the current connection cost should initialize the
318   // NetworkCostManager integration, but not the event sink.
319   // Note that the actual ConnectionCost value return is irrelevant beyond the
320   // fact that it shouldn't be UNKNOWN anymore if the integration is initialized
321   // properly.
322   NetworkChangeNotifier::ConnectionCost current_connection_cost =
323       GetCurrentConnectionCost();
324   EXPECT_NE(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
325             current_connection_cost);
326   EXPECT_EQ(current_connection_cost, LastComputedConnectionCost());
327   EXPECT_TRUE(HasNetworkCostManager());
328   EXPECT_FALSE(HasNetworkCostManagerEventSink());
329 
330   // Adding a ConnectionCostObserver should initialize the event sink. If the
331   // subsequent registration for updates fails, the event sink will get
332   // destroyed.
333   TestConnectionCostObserver test_connection_cost_observer;
334   test_connection_cost_observer.Register();
335   // The actual registration happens on a callback, so need to run until idle.
336   base::RunLoop().RunUntilIdle();
337   EXPECT_TRUE(HasNetworkCostManagerEventSink());
338 }
339 
340 }  // namespace net
341