1 //
2 // Copyright (C) 2011 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "shill/ipconfig.h"
18
19 #include <sys/time.h>
20
21 #include <base/bind.h>
22 #if defined(__ANDROID__)
23 #include <dbus/service_constants.h>
24 #else
25 #include <chromeos/dbus/service_constants.h>
26 #endif // __ANDROID__
27 #include <gmock/gmock.h>
28 #include <gtest/gtest.h>
29
30 #include "shill/logging.h"
31 #include "shill/mock_adaptors.h"
32 #include "shill/mock_control.h"
33 #include "shill/mock_log.h"
34 #include "shill/mock_store.h"
35 #include "shill/net/mock_time.h"
36 #include "shill/static_ip_parameters.h"
37
38 using base::Bind;
39 using base::Unretained;
40 using std::string;
41 using testing::_;
42 using testing::EndsWith;
43 using testing::DoAll;
44 using testing::Mock;
45 using testing::Return;
46 using testing::SaveArg;
47 using testing::SetArgPointee;
48 using testing::SetArgumentPointee;
49 using testing::StrictMock;
50 using testing::Test;
51
52 namespace shill {
53
54 namespace {
55 const char kDeviceName[] = "testdevice";
56 const uint32_t kTimeNow = 10;
57 } // namespace
58
59 class IPConfigTest : public Test {
60 public:
IPConfigTest()61 IPConfigTest() : ipconfig_(new IPConfig(&control_, kDeviceName)) {
62 ipconfig_->time_ = &time_;
63 }
64
SetUp()65 virtual void SetUp() {
66 ScopeLogger::GetInstance()->EnableScopesByName("inet");
67 ScopeLogger::GetInstance()->set_verbose_level(3);
68 }
69
TearDown()70 virtual void TearDown() {
71 ScopeLogger::GetInstance()->EnableScopesByName("-inet");
72 ScopeLogger::GetInstance()->set_verbose_level(0);
73 }
74
DropRef(const IPConfigRefPtr &,bool)75 void DropRef(const IPConfigRefPtr & /*ipconfig*/,
76 bool /*new_lease_acquired*/) {
77 ipconfig_ = nullptr;
78 }
79
80 MOCK_METHOD2(OnIPConfigUpdated,
81 void(const IPConfigRefPtr& ipconfig, bool new_lease_acquired));
82 MOCK_METHOD1(OnIPConfigFailed, void(const IPConfigRefPtr& ipconfig));
83 MOCK_METHOD1(OnIPConfigRefreshed, void(const IPConfigRefPtr& ipconfig));
84 MOCK_METHOD1(OnIPConfigExpired, void(const IPConfigRefPtr& ipconfig));
85
86 protected:
GetAdaptor()87 IPConfigMockAdaptor* GetAdaptor() {
88 return static_cast<IPConfigMockAdaptor*>(ipconfig_->adaptor_.get());
89 }
90
UpdateProperties(const IPConfig::Properties & properties)91 void UpdateProperties(const IPConfig::Properties& properties) {
92 ipconfig_->UpdateProperties(properties, true);
93 }
94
NotifyFailure()95 void NotifyFailure() {
96 ipconfig_->NotifyFailure();
97 }
98
NotifyExpiry()99 void NotifyExpiry() {
100 ipconfig_->NotifyExpiry();
101 }
102
ExpectPropertiesEqual(const IPConfig::Properties & properties)103 void ExpectPropertiesEqual(const IPConfig::Properties& properties) {
104 EXPECT_EQ(properties.address, ipconfig_->properties().address);
105 EXPECT_EQ(properties.subnet_prefix, ipconfig_->properties().subnet_prefix);
106 EXPECT_EQ(properties.broadcast_address,
107 ipconfig_->properties().broadcast_address);
108 EXPECT_EQ(properties.dns_servers.size(),
109 ipconfig_->properties().dns_servers.size());
110 if (properties.dns_servers.size() ==
111 ipconfig_->properties().dns_servers.size()) {
112 for (size_t i = 0; i < properties.dns_servers.size(); ++i) {
113 EXPECT_EQ(properties.dns_servers[i],
114 ipconfig_->properties().dns_servers[i]);
115 }
116 }
117 EXPECT_EQ(properties.domain_search.size(),
118 ipconfig_->properties().domain_search.size());
119 if (properties.domain_search.size() ==
120 ipconfig_->properties().domain_search.size()) {
121 for (size_t i = 0; i < properties.domain_search.size(); ++i) {
122 EXPECT_EQ(properties.domain_search[i],
123 ipconfig_->properties().domain_search[i]);
124 }
125 }
126 EXPECT_EQ(properties.gateway, ipconfig_->properties().gateway);
127 EXPECT_EQ(properties.blackhole_ipv6,
128 ipconfig_->properties().blackhole_ipv6);
129 EXPECT_EQ(properties.mtu, ipconfig_->properties().mtu);
130 }
131
132 MockControl control_;
133 MockTime time_;
134 IPConfigRefPtr ipconfig_;
135 };
136
TEST_F(IPConfigTest,DeviceName)137 TEST_F(IPConfigTest, DeviceName) {
138 EXPECT_EQ(kDeviceName, ipconfig_->device_name());
139 }
140
TEST_F(IPConfigTest,RequestIP)141 TEST_F(IPConfigTest, RequestIP) {
142 EXPECT_FALSE(ipconfig_->RequestIP());
143 }
144
TEST_F(IPConfigTest,RenewIP)145 TEST_F(IPConfigTest, RenewIP) {
146 EXPECT_FALSE(ipconfig_->RenewIP());
147 }
148
TEST_F(IPConfigTest,ReleaseIP)149 TEST_F(IPConfigTest, ReleaseIP) {
150 EXPECT_FALSE(ipconfig_->ReleaseIP(IPConfig::kReleaseReasonDisconnect));
151 }
152
TEST_F(IPConfigTest,UpdateProperties)153 TEST_F(IPConfigTest, UpdateProperties) {
154 IPConfig::Properties properties;
155 properties.address = "1.2.3.4";
156 properties.subnet_prefix = 24;
157 properties.broadcast_address = "11.22.33.44";
158 properties.dns_servers.push_back("10.20.30.40");
159 properties.dns_servers.push_back("20.30.40.50");
160 properties.domain_name = "foo.org";
161 properties.domain_search.push_back("zoo.org");
162 properties.domain_search.push_back("zoo.com");
163 properties.gateway = "5.6.7.8";
164 properties.blackhole_ipv6 = true;
165 properties.mtu = 700;
166 UpdateProperties(properties);
167 ExpectPropertiesEqual(properties);
168
169 // We should not reset on NotifyFailure.
170 NotifyFailure();
171 ExpectPropertiesEqual(properties);
172
173 // We should not reset on NotifyExpiry.
174 NotifyExpiry();
175 ExpectPropertiesEqual(properties);
176
177 // We should reset if ResetProperties is called.
178 ipconfig_->ResetProperties();
179 ExpectPropertiesEqual(IPConfig::Properties());
180 }
181
TEST_F(IPConfigTest,Callbacks)182 TEST_F(IPConfigTest, Callbacks) {
183 ipconfig_->RegisterUpdateCallback(
184 Bind(&IPConfigTest::OnIPConfigUpdated, Unretained(this)));
185 ipconfig_->RegisterFailureCallback(
186 Bind(&IPConfigTest::OnIPConfigFailed, Unretained(this)));
187 ipconfig_->RegisterRefreshCallback(
188 Bind(&IPConfigTest::OnIPConfigRefreshed, Unretained(this)));
189 ipconfig_->RegisterExpireCallback(
190 Bind(&IPConfigTest::OnIPConfigExpired, Unretained(this)));
191
192 EXPECT_CALL(*this, OnIPConfigUpdated(ipconfig_, true));
193 EXPECT_CALL(*this, OnIPConfigFailed(ipconfig_)).Times(0);
194 EXPECT_CALL(*this, OnIPConfigRefreshed(ipconfig_)).Times(0);
195 EXPECT_CALL(*this, OnIPConfigExpired(ipconfig_)).Times(0);
196 UpdateProperties(IPConfig::Properties());
197 Mock::VerifyAndClearExpectations(this);
198
199 EXPECT_CALL(*this, OnIPConfigUpdated(ipconfig_, true)).Times(0);
200 EXPECT_CALL(*this, OnIPConfigFailed(ipconfig_));
201 EXPECT_CALL(*this, OnIPConfigRefreshed(ipconfig_)).Times(0);
202 EXPECT_CALL(*this, OnIPConfigExpired(ipconfig_)).Times(0);
203 NotifyFailure();
204 Mock::VerifyAndClearExpectations(this);
205
206 EXPECT_CALL(*this, OnIPConfigUpdated(ipconfig_, true)).Times(0);
207 EXPECT_CALL(*this, OnIPConfigFailed(ipconfig_)).Times(0);
208 EXPECT_CALL(*this, OnIPConfigRefreshed(ipconfig_));
209 EXPECT_CALL(*this, OnIPConfigExpired(ipconfig_)).Times(0);
210 ipconfig_->Refresh(nullptr);
211 Mock::VerifyAndClearExpectations(this);
212
213 EXPECT_CALL(*this, OnIPConfigUpdated(ipconfig_, true)).Times(0);
214 EXPECT_CALL(*this, OnIPConfigFailed(ipconfig_)).Times(0);
215 EXPECT_CALL(*this, OnIPConfigRefreshed(ipconfig_)).Times(0);
216 EXPECT_CALL(*this, OnIPConfigExpired(ipconfig_));
217 NotifyExpiry();
218 Mock::VerifyAndClearExpectations(this);
219 }
220
TEST_F(IPConfigTest,UpdatePropertiesWithDropRef)221 TEST_F(IPConfigTest, UpdatePropertiesWithDropRef) {
222 // The UpdateCallback should be able to drop a reference to the
223 // IPConfig object without crashing.
224 ipconfig_->RegisterUpdateCallback(
225 Bind(&IPConfigTest::DropRef, Unretained(this)));
226 UpdateProperties(IPConfig::Properties());
227 }
228
TEST_F(IPConfigTest,PropertyChanges)229 TEST_F(IPConfigTest, PropertyChanges) {
230 IPConfigMockAdaptor* adaptor = GetAdaptor();
231
232 StaticIPParameters static_ip_params;
233 EXPECT_CALL(*adaptor, EmitStringChanged(kAddressProperty, _));
234 EXPECT_CALL(*adaptor, EmitStringsChanged(kNameServersProperty, _));
235 ipconfig_->ApplyStaticIPParameters(&static_ip_params);
236 Mock::VerifyAndClearExpectations(adaptor);
237
238 EXPECT_CALL(*adaptor, EmitStringChanged(kAddressProperty, _));
239 EXPECT_CALL(*adaptor, EmitStringsChanged(kNameServersProperty, _));
240 ipconfig_->RestoreSavedIPParameters(&static_ip_params);
241 Mock::VerifyAndClearExpectations(adaptor);
242
243 IPConfig::Properties ip_properties;
244 EXPECT_CALL(*adaptor, EmitStringChanged(kAddressProperty, _));
245 EXPECT_CALL(*adaptor, EmitStringsChanged(kNameServersProperty, _));
246 UpdateProperties(ip_properties);
247 Mock::VerifyAndClearExpectations(adaptor);
248
249 // It is the callback's responsibility for resetting the IPConfig
250 // properties (via IPConfig::ResetProperties()). Since NotifyFailure
251 // by itself doesn't change any properties, it should not emit any
252 // property change events either.
253 EXPECT_CALL(*adaptor, EmitStringChanged(_, _)).Times(0);
254 EXPECT_CALL(*adaptor, EmitStringsChanged(_, _)).Times(0);
255 NotifyFailure();
256 Mock::VerifyAndClearExpectations(adaptor);
257
258 // Similarly, NotifyExpiry() should have no property change side effects.
259 EXPECT_CALL(*adaptor, EmitStringChanged(_, _)).Times(0);
260 EXPECT_CALL(*adaptor, EmitStringsChanged(_, _)).Times(0);
261 NotifyExpiry();
262 Mock::VerifyAndClearExpectations(adaptor);
263
264 EXPECT_CALL(*adaptor, EmitStringChanged(kAddressProperty, _));
265 EXPECT_CALL(*adaptor, EmitStringsChanged(kNameServersProperty, _));
266 ipconfig_->ResetProperties();
267 Mock::VerifyAndClearExpectations(adaptor);
268 }
269
TEST_F(IPConfigTest,UpdateLeaseExpirationTime)270 TEST_F(IPConfigTest, UpdateLeaseExpirationTime) {
271 const struct timeval expected_time_now = {kTimeNow , 0};
272 uint32_t lease_duration = 1;
273 EXPECT_CALL(time_, GetTimeBoottime(_))
274 .WillOnce(DoAll(SetArgPointee<0>(expected_time_now), Return(0)));
275 ipconfig_->UpdateLeaseExpirationTime(lease_duration);
276 EXPECT_EQ(kTimeNow + lease_duration,
277 ipconfig_->current_lease_expiration_time_.tv_sec);
278 }
279
TEST_F(IPConfigTest,TimeToLeaseExpiry_NoDHCPLease)280 TEST_F(IPConfigTest, TimeToLeaseExpiry_NoDHCPLease) {
281 ScopedMockLog log;
282 uint32_t time_left = 0;
283 // |current_lease_expiration_time_| has not been set, so expect an error.
284 EXPECT_CALL(log, Log(_, _,
285 EndsWith("No current DHCP lease")));
286 EXPECT_FALSE(ipconfig_->TimeToLeaseExpiry(&time_left));
287 EXPECT_EQ(0, time_left);
288 }
289
TEST_F(IPConfigTest,TimeToLeaseExpiry_CurrentLeaseExpired)290 TEST_F(IPConfigTest, TimeToLeaseExpiry_CurrentLeaseExpired) {
291 ScopedMockLog log;
292 const struct timeval time_now = {kTimeNow, 0};
293 uint32_t time_left = 0;
294 // Set |current_lease_expiration_time_| so it is expired (i.e. earlier than
295 // current time).
296 ipconfig_->current_lease_expiration_time_ = {kTimeNow - 1, 0};
297 EXPECT_CALL(time_, GetTimeBoottime(_))
298 .WillOnce(DoAll(SetArgPointee<0>(time_now), Return(0)));
299 EXPECT_CALL(log, Log(_, _,
300 EndsWith("Current DHCP lease has already expired")));
301 EXPECT_FALSE(ipconfig_->TimeToLeaseExpiry(&time_left));
302 EXPECT_EQ(0, time_left);
303 }
304
TEST_F(IPConfigTest,TimeToLeaseExpiry_Success)305 TEST_F(IPConfigTest, TimeToLeaseExpiry_Success) {
306 const uint32_t expected_time_to_expiry = 10;
307 const struct timeval time_now = {kTimeNow, 0};
308 uint32_t time_left;
309 // Set |current_lease_expiration_time_| so it appears like we already
310 // have obtained a DHCP lease before.
311 ipconfig_->current_lease_expiration_time_ = {
312 kTimeNow + expected_time_to_expiry, 0};
313 EXPECT_CALL(time_, GetTimeBoottime(_))
314 .WillOnce(DoAll(SetArgPointee<0>(time_now), Return(0)));
315 EXPECT_TRUE(ipconfig_->TimeToLeaseExpiry(&time_left));
316 EXPECT_EQ(expected_time_to_expiry, time_left);
317 }
318
319 } // namespace shill
320