network_change_notifier_win_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 "base/message_loop.h"
6#include "net/base/network_change_notifier.h"
7#include "net/base/network_change_notifier_factory.h"
8#include "net/base/network_change_notifier_win.h"
9#include "testing/gmock/include/gmock/gmock.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12using ::testing::AtLeast;
13using ::testing::Invoke;
14using ::testing::Return;
15using ::testing::StrictMock;
16
17namespace net {
18
19namespace {
20
21// Subclass of NetworkChangeNotifierWin that overrides functions so that no
22// Windows API networking functions are ever called.
23class TestNetworkChangeNotifierWin : public NetworkChangeNotifierWin {
24 public:
25  TestNetworkChangeNotifierWin() {}
26
27  virtual ~TestNetworkChangeNotifierWin() {
28    // This is needed so we don't try to stop watching for IP address changes,
29    // as we never actually started.
30    set_is_watching(false);
31  }
32
33  // From NetworkChangeNotifier.
34  virtual NetworkChangeNotifier::ConnectionType
35      GetCurrentConnectionType() const OVERRIDE {
36    return NetworkChangeNotifier::CONNECTION_UNKNOWN;
37  }
38
39  // From NetworkChangeNotifierWin.
40  MOCK_METHOD0(WatchForAddressChangeInternal, bool());
41
42 private:
43  DISALLOW_COPY_AND_ASSIGN(TestNetworkChangeNotifierWin);
44};
45
46class TestIPAddressObserver
47    : public net::NetworkChangeNotifier::IPAddressObserver {
48 public:
49  TestIPAddressObserver() {
50    NetworkChangeNotifier::AddIPAddressObserver(this);
51  }
52
53  ~TestIPAddressObserver() {
54    NetworkChangeNotifier::RemoveIPAddressObserver(this);
55  }
56
57  MOCK_METHOD0(OnIPAddressChanged, void());
58
59 private:
60  DISALLOW_COPY_AND_ASSIGN(TestIPAddressObserver);
61};
62
63bool ExitMessageLoopAndReturnFalse() {
64  MessageLoop::current()->Quit();
65  return false;
66}
67
68}  // namespace
69
70class NetworkChangeNotifierWinTest : public testing::Test {
71 public:
72  // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
73  // success.  Expects that |network_change_notifier_| has just been created, so
74  // it's not watching anything yet, and there have been no previous
75  // WatchForAddressChangeInternal failures.
76  void StartWatchingAndSucceed() {
77    EXPECT_FALSE(network_change_notifier_.is_watching());
78    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
79
80    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
81    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
82        .Times(1)
83        .WillOnce(Return(true));
84
85    network_change_notifier_.WatchForAddressChange();
86
87    EXPECT_TRUE(network_change_notifier_.is_watching());
88    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
89
90    // If a task to notify observers of the IP address change event was
91    // incorrectly posted, make sure it gets run to trigger a failure.
92    MessageLoop::current()->RunAllPending();
93  }
94
95  // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
96  // failure.
97  void StartWatchingAndFail() {
98    EXPECT_FALSE(network_change_notifier_.is_watching());
99    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
100
101    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
102    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
103        // Due to an expected race, it's theoretically possible for more than
104        // one call to occur, though unlikely.
105        .Times(AtLeast(1))
106        .WillRepeatedly(Return(false));
107
108    network_change_notifier_.WatchForAddressChange();
109
110    EXPECT_FALSE(network_change_notifier_.is_watching());
111    EXPECT_LT(0, network_change_notifier_.sequential_failures());
112
113    // If a task to notify observers of the IP address change event was
114    // incorrectly posted, make sure it gets run.
115    MessageLoop::current()->RunAllPending();
116  }
117
118  // Simulates a network change event, resulting in a call to OnObjectSignaled.
119  // The resulting call to WatchForAddressChangeInternal then succeeds.
120  void SignalAndSucceed() {
121    EXPECT_TRUE(network_change_notifier_.is_watching());
122    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
123
124    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
125    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
126        .Times(1)
127        .WillOnce(Return(true));
128
129    network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
130
131    EXPECT_TRUE(network_change_notifier_.is_watching());
132    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
133
134    // Run the task to notify observers of the IP address change event.
135    MessageLoop::current()->RunAllPending();
136  }
137
138  // Simulates a network change event, resulting in a call to OnObjectSignaled.
139  // The resulting call to WatchForAddressChangeInternal then fails.
140  void SignalAndFail() {
141    EXPECT_TRUE(network_change_notifier_.is_watching());
142    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
143
144    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
145    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
146        // Due to an expected race, it's theoretically possible for more than
147        // one call to occur, though unlikely.
148        .Times(AtLeast(1))
149        .WillRepeatedly(Return(false));
150
151    network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
152
153    EXPECT_FALSE(network_change_notifier_.is_watching());
154    EXPECT_LT(0, network_change_notifier_.sequential_failures());
155
156    // Run the task to notify observers of the IP address change event.
157    MessageLoop::current()->RunAllPending();
158  }
159
160  // Runs the message loop until WatchForAddressChange is called again, as a
161  // result of the already posted task after a WatchForAddressChangeInternal
162  // failure.  Simulates a success on the resulting call to
163  // WatchForAddressChangeInternal.
164  void RetryAndSucceed() {
165    EXPECT_FALSE(network_change_notifier_.is_watching());
166    EXPECT_LT(0, network_change_notifier_.sequential_failures());
167
168    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged())
169        .Times(1)
170        .WillOnce(Invoke(MessageLoop::current(), &MessageLoop::Quit));
171    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
172        .Times(1)
173        .WillOnce(Return(true));
174
175    MessageLoop::current()->Run();
176
177    EXPECT_TRUE(network_change_notifier_.is_watching());
178    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
179  }
180
181  // Runs the message loop until WatchForAddressChange is called again, as a
182  // result of the already posted task after a WatchForAddressChangeInternal
183  // failure.  Simulates a failure on the resulting call to
184  // WatchForAddressChangeInternal.
185  void RetryAndFail() {
186    EXPECT_FALSE(network_change_notifier_.is_watching());
187    EXPECT_LT(0, network_change_notifier_.sequential_failures());
188
189    int initial_sequential_failures =
190        network_change_notifier_.sequential_failures();
191
192    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
193    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
194        // Due to an expected race, it's theoretically possible for more than
195        // one call to occur, though unlikely.
196        .Times(AtLeast(1))
197        .WillRepeatedly(Invoke(ExitMessageLoopAndReturnFalse));
198
199    MessageLoop::current()->Run();
200
201    EXPECT_FALSE(network_change_notifier_.is_watching());
202    EXPECT_LT(initial_sequential_failures,
203              network_change_notifier_.sequential_failures());
204
205    // If a task to notify observers of the IP address change event was
206    // incorrectly posted, make sure it gets run.
207    MessageLoop::current()->RunAllPending();
208  }
209
210 private:
211  // Note that the order of declaration here is important.
212
213  // Allows creating a new NetworkChangeNotifier.  Must be created before
214  // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
215  NetworkChangeNotifier::DisableForTest disable_for_test_;
216
217  StrictMock<TestNetworkChangeNotifierWin> network_change_notifier_;
218
219  // Must be created after |network_change_notifier_|, so it can add itself as
220  // an IPAddressObserver.
221  StrictMock<TestIPAddressObserver> test_ip_address_observer_;
222};
223
224TEST_F(NetworkChangeNotifierWinTest, NetChangeWinBasic) {
225  StartWatchingAndSucceed();
226}
227
228TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStart) {
229  StartWatchingAndFail();
230}
231
232TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartOnce) {
233  StartWatchingAndFail();
234  RetryAndSucceed();
235}
236
237TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartTwice) {
238  StartWatchingAndFail();
239  RetryAndFail();
240  RetryAndSucceed();
241}
242
243TEST_F(NetworkChangeNotifierWinTest, NetChangeWinSignal) {
244  StartWatchingAndSucceed();
245  SignalAndSucceed();
246}
247
248TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalOnce) {
249  StartWatchingAndSucceed();
250  SignalAndFail();
251  RetryAndSucceed();
252}
253
254TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalTwice) {
255  StartWatchingAndSucceed();
256  SignalAndFail();
257  RetryAndFail();
258  RetryAndSucceed();
259}
260
261}  // namespace net
262