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/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 NetworkChangeNotifierWin.
34  virtual NetworkChangeNotifier::ConnectionType
35      RecomputeCurrentConnectionType() 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  base::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    base::MessageLoop::current()->RunUntilIdle();
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    base::MessageLoop::current()->RunUntilIdle();
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    base::MessageLoop::current()->RunUntilIdle();
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    base::MessageLoop::current()->RunUntilIdle();
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()).Times(1)
169        .WillOnce(
170            Invoke(base::MessageLoop::current(), &base::MessageLoop::Quit));
171    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
172        .Times(1).WillOnce(Return(true));
173
174    base::MessageLoop::current()->Run();
175
176    EXPECT_TRUE(network_change_notifier_.is_watching());
177    EXPECT_EQ(0, network_change_notifier_.sequential_failures());
178  }
179
180  // Runs the message loop until WatchForAddressChange is called again, as a
181  // result of the already posted task after a WatchForAddressChangeInternal
182  // failure.  Simulates a failure on the resulting call to
183  // WatchForAddressChangeInternal.
184  void RetryAndFail() {
185    EXPECT_FALSE(network_change_notifier_.is_watching());
186    EXPECT_LT(0, network_change_notifier_.sequential_failures());
187
188    int initial_sequential_failures =
189        network_change_notifier_.sequential_failures();
190
191    EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
192    EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
193        // Due to an expected race, it's theoretically possible for more than
194        // one call to occur, though unlikely.
195        .Times(AtLeast(1))
196        .WillRepeatedly(Invoke(ExitMessageLoopAndReturnFalse));
197
198    base::MessageLoop::current()->Run();
199
200    EXPECT_FALSE(network_change_notifier_.is_watching());
201    EXPECT_LT(initial_sequential_failures,
202              network_change_notifier_.sequential_failures());
203
204    // If a task to notify observers of the IP address change event was
205    // incorrectly posted, make sure it gets run.
206    base::MessageLoop::current()->RunUntilIdle();
207  }
208
209 private:
210  // Note that the order of declaration here is important.
211
212  // Allows creating a new NetworkChangeNotifier.  Must be created before
213  // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
214  NetworkChangeNotifier::DisableForTest disable_for_test_;
215
216  StrictMock<TestNetworkChangeNotifierWin> network_change_notifier_;
217
218  // Must be created after |network_change_notifier_|, so it can add itself as
219  // an IPAddressObserver.
220  StrictMock<TestIPAddressObserver> test_ip_address_observer_;
221};
222
223TEST_F(NetworkChangeNotifierWinTest, NetChangeWinBasic) {
224  StartWatchingAndSucceed();
225}
226
227TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStart) {
228  StartWatchingAndFail();
229}
230
231TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartOnce) {
232  StartWatchingAndFail();
233  RetryAndSucceed();
234}
235
236TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartTwice) {
237  StartWatchingAndFail();
238  RetryAndFail();
239  RetryAndSucceed();
240}
241
242TEST_F(NetworkChangeNotifierWinTest, NetChangeWinSignal) {
243  StartWatchingAndSucceed();
244  SignalAndSucceed();
245}
246
247TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalOnce) {
248  StartWatchingAndSucceed();
249  SignalAndFail();
250  RetryAndSucceed();
251}
252
253TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalTwice) {
254  StartWatchingAndSucceed();
255  SignalAndFail();
256  RetryAndFail();
257  RetryAndSucceed();
258}
259
260}  // namespace net
261