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
76 class NetworkChangeNotifierWinTest : public TestWithTaskEnvironment {
77 public:
78 // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
79 // success. Expects that |network_change_notifier_| has just been created, so
80 // it's not watching anything yet, and there have been no previous
81 // WatchForAddressChangeInternal failures.
StartWatchingAndSucceed()82 void StartWatchingAndSucceed() {
83 EXPECT_FALSE(network_change_notifier_.is_watching());
84 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
85
86 EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
87 EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
88 .Times(1)
89 .WillOnce(Return(true));
90
91 network_change_notifier_.WatchForAddressChange();
92
93 EXPECT_TRUE(network_change_notifier_.is_watching());
94 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
95
96 // If a task to notify observers of the IP address change event was
97 // incorrectly posted, make sure it gets run to trigger a failure.
98 base::RunLoop().RunUntilIdle();
99 }
100
101 // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
102 // failure.
StartWatchingAndFail()103 void StartWatchingAndFail() {
104 EXPECT_FALSE(network_change_notifier_.is_watching());
105 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
106
107 EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
108 EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
109 // Due to an expected race, it's theoretically possible for more than
110 // one call to occur, though unlikely.
111 .Times(AtLeast(1))
112 .WillRepeatedly(Return(false));
113
114 network_change_notifier_.WatchForAddressChange();
115
116 EXPECT_FALSE(network_change_notifier_.is_watching());
117 EXPECT_LT(0, network_change_notifier_.sequential_failures());
118
119 // If a task to notify observers of the IP address change event was
120 // incorrectly posted, make sure it gets run.
121 base::RunLoop().RunUntilIdle();
122 }
123
124 // Simulates a network change event, resulting in a call to OnObjectSignaled.
125 // The resulting call to WatchForAddressChangeInternal then succeeds.
SignalAndSucceed()126 void SignalAndSucceed() {
127 EXPECT_TRUE(network_change_notifier_.is_watching());
128 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
129
130 EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
131 EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
132 .Times(1)
133 .WillOnce(Return(true));
134
135 network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
136
137 EXPECT_TRUE(network_change_notifier_.is_watching());
138 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
139
140 // Run the task to notify observers of the IP address change event.
141 base::RunLoop().RunUntilIdle();
142 }
143
144 // Simulates a network change event, resulting in a call to OnObjectSignaled.
145 // The resulting call to WatchForAddressChangeInternal then fails.
SignalAndFail()146 void SignalAndFail() {
147 EXPECT_TRUE(network_change_notifier_.is_watching());
148 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
149
150 EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
151 EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
152 // Due to an expected race, it's theoretically possible for more than
153 // one call to occur, though unlikely.
154 .Times(AtLeast(1))
155 .WillRepeatedly(Return(false));
156
157 network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
158
159 EXPECT_FALSE(network_change_notifier_.is_watching());
160 EXPECT_LT(0, network_change_notifier_.sequential_failures());
161
162 // Run the task to notify observers of the IP address change event.
163 base::RunLoop().RunUntilIdle();
164 }
165
166 // Runs the message loop until WatchForAddressChange is called again, as a
167 // result of the already posted task after a WatchForAddressChangeInternal
168 // failure. Simulates a success on the resulting call to
169 // WatchForAddressChangeInternal.
RetryAndSucceed()170 void RetryAndSucceed() {
171 EXPECT_FALSE(network_change_notifier_.is_watching());
172 EXPECT_LT(0, network_change_notifier_.sequential_failures());
173
174 base::RunLoop run_loop;
175
176 EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged())
177 .Times(1)
178 .WillOnce(Invoke(&run_loop, &base::RunLoop::QuitWhenIdle));
179 EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
180 .Times(1).WillOnce(Return(true));
181
182 run_loop.Run();
183
184 EXPECT_TRUE(network_change_notifier_.is_watching());
185 EXPECT_EQ(0, network_change_notifier_.sequential_failures());
186 }
187
188 // Runs the message loop until WatchForAddressChange is called again, as a
189 // result of the already posted task after a WatchForAddressChangeInternal
190 // failure. Simulates a failure on the resulting call to
191 // WatchForAddressChangeInternal.
RetryAndFail()192 void RetryAndFail() {
193 base::RunLoop loop;
194 EXPECT_FALSE(network_change_notifier_.is_watching());
195 EXPECT_LT(0, network_change_notifier_.sequential_failures());
196
197 int initial_sequential_failures =
198 network_change_notifier_.sequential_failures();
199
200 EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
201 EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
202 // Due to an expected race, it's theoretically possible for more than
203 // one call to occur, though unlikely.
204 .Times(AtLeast(1))
205 .WillRepeatedly(Invoke([&loop]() {
206 loop.QuitWhenIdle();
207 return false;
208 }));
209
210 loop.Run();
211
212 EXPECT_FALSE(network_change_notifier_.is_watching());
213 EXPECT_LT(initial_sequential_failures,
214 network_change_notifier_.sequential_failures());
215
216 // If a task to notify observers of the IP address change event was
217 // incorrectly posted, make sure it gets run.
218 base::RunLoop().RunUntilIdle();
219 }
220
HasNetworkCostManager()221 bool HasNetworkCostManager() {
222 return network_change_notifier_.network_cost_manager_.Get() != nullptr;
223 }
224
HasNetworkCostManagerEventSink()225 bool HasNetworkCostManagerEventSink() {
226 return network_change_notifier_.network_cost_manager_event_sink_.Get() !=
227 nullptr;
228 }
229
LastComputedConnectionCost()230 NetworkChangeNotifier::ConnectionCost LastComputedConnectionCost() {
231 return network_change_notifier_.last_computed_connection_cost_;
232 }
233
GetCurrentConnectionCost()234 NetworkChangeNotifier::ConnectionCost GetCurrentConnectionCost() {
235 return network_change_notifier_.GetCurrentConnectionCost();
236 }
237
238 private:
239 // Note that the order of declaration here is important.
240
241 // Allows creating a new NetworkChangeNotifier. Must be created before
242 // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
243 NetworkChangeNotifier::DisableForTest disable_for_test_;
244
245 StrictMock<TestNetworkChangeNotifierWin> network_change_notifier_;
246
247 // Must be created after |network_change_notifier_|, so it can add itself as
248 // an IPAddressObserver.
249 StrictMock<TestIPAddressObserver> test_ip_address_observer_;
250 };
251
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinBasic)252 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinBasic) {
253 StartWatchingAndSucceed();
254 }
255
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStart)256 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStart) {
257 StartWatchingAndFail();
258 }
259
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStartOnce)260 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartOnce) {
261 StartWatchingAndFail();
262 RetryAndSucceed();
263 }
264
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailStartTwice)265 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartTwice) {
266 StartWatchingAndFail();
267 RetryAndFail();
268 RetryAndSucceed();
269 }
270
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinSignal)271 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinSignal) {
272 StartWatchingAndSucceed();
273 SignalAndSucceed();
274 }
275
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailSignalOnce)276 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalOnce) {
277 StartWatchingAndSucceed();
278 SignalAndFail();
279 RetryAndSucceed();
280 }
281
TEST_F(NetworkChangeNotifierWinTest,NetChangeWinFailSignalTwice)282 TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalTwice) {
283 StartWatchingAndSucceed();
284 SignalAndFail();
285 RetryAndFail();
286 RetryAndSucceed();
287 }
288
289 class TestConnectionCostObserver
290 : public NetworkChangeNotifier::ConnectionCostObserver {
291 public:
TestConnectionCostObserver()292 TestConnectionCostObserver() {}
293
294 TestConnectionCostObserver(const TestConnectionCostObserver&) = delete;
295 TestConnectionCostObserver& operator=(const TestConnectionCostObserver&) =
296 delete;
297
~TestConnectionCostObserver()298 ~TestConnectionCostObserver() override {
299 NetworkChangeNotifier::RemoveConnectionCostObserver(this);
300 }
301
OnConnectionCostChanged(NetworkChangeNotifier::ConnectionCost)302 void OnConnectionCostChanged(NetworkChangeNotifier::ConnectionCost) override {
303 }
304
Register()305 void Register() { NetworkChangeNotifier::AddConnectionCostObserver(this); }
306 };
307
TEST_F(NetworkChangeNotifierWinTest,NetworkCostManagerIntegration)308 TEST_F(NetworkChangeNotifierWinTest, NetworkCostManagerIntegration) {
309 // Upon creation, none of the NetworkCostManager integration should be
310 // initialized yet.
311 ASSERT_FALSE(HasNetworkCostManager());
312 ASSERT_FALSE(HasNetworkCostManagerEventSink());
313 ASSERT_EQ(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
314 LastComputedConnectionCost());
315
316 // Asking for the current connection cost should initialize the
317 // NetworkCostManager integration, but not the event sink.
318 // Note that the actual ConnectionCost value return is irrelevant beyond the
319 // fact that it shouldn't be UNKNOWN anymore if the integration is initialized
320 // properly.
321 NetworkChangeNotifier::ConnectionCost current_connection_cost =
322 GetCurrentConnectionCost();
323 EXPECT_NE(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
324 current_connection_cost);
325 EXPECT_EQ(current_connection_cost, LastComputedConnectionCost());
326 EXPECT_TRUE(HasNetworkCostManager());
327 EXPECT_FALSE(HasNetworkCostManagerEventSink());
328
329 // Adding a ConnectionCostObserver should initialize the event sink. If the
330 // subsequent registration for updates fails, the event sink will get
331 // destroyed.
332 TestConnectionCostObserver test_connection_cost_observer;
333 test_connection_cost_observer.Register();
334 // The actual registration happens on a callback, so need to run until idle.
335 base::RunLoop().RunUntilIdle();
336 EXPECT_TRUE(HasNetworkCostManagerEventSink());
337 }
338
339 } // namespace net
340