Home | History | Annotate | Download | only in shill
      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