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