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: 61 IPConfigTest() : ipconfig_(new IPConfig(&control_, kDeviceName)) { 62 ipconfig_->time_ = &time_; 63 } 64 65 virtual void SetUp() { 66 ScopeLogger::GetInstance()->EnableScopesByName("inet"); 67 ScopeLogger::GetInstance()->set_verbose_level(3); 68 } 69 70 virtual void TearDown() { 71 ScopeLogger::GetInstance()->EnableScopesByName("-inet"); 72 ScopeLogger::GetInstance()->set_verbose_level(0); 73 } 74 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: 87 IPConfigMockAdaptor* GetAdaptor() { 88 return static_cast<IPConfigMockAdaptor*>(ipconfig_->adaptor_.get()); 89 } 90 91 void UpdateProperties(const IPConfig::Properties& properties) { 92 ipconfig_->UpdateProperties(properties, true); 93 } 94 95 void NotifyFailure() { 96 ipconfig_->NotifyFailure(); 97 } 98 99 void NotifyExpiry() { 100 ipconfig_->NotifyExpiry(); 101 } 102 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 137 TEST_F(IPConfigTest, DeviceName) { 138 EXPECT_EQ(kDeviceName, ipconfig_->device_name()); 139 } 140 141 TEST_F(IPConfigTest, RequestIP) { 142 EXPECT_FALSE(ipconfig_->RequestIP()); 143 } 144 145 TEST_F(IPConfigTest, RenewIP) { 146 EXPECT_FALSE(ipconfig_->RenewIP()); 147 } 148 149 TEST_F(IPConfigTest, ReleaseIP) { 150 EXPECT_FALSE(ipconfig_->ReleaseIP(IPConfig::kReleaseReasonDisconnect)); 151 } 152 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 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 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 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 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 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 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 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