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