| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/static_ip_parameters.h" |
| |
| #include <base/check.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <gtest/gtest.h> |
| |
| #include "shill/fake_store.h" |
| #include "shill/ipconfig.h" |
| #include "shill/mock_control.h" |
| #include "shill/mock_ipconfig.h" |
| #include "shill/property_store.h" |
| |
| using testing::_; |
| using testing::DoAll; |
| using testing::Return; |
| using testing::SetArgPointee; |
| using testing::StrictMock; |
| using testing::Test; |
| |
| namespace shill { |
| |
| namespace { |
| |
| const char kAddress[] = "10.0.0.1"; |
| const char kGateway[] = "10.0.0.254"; |
| const int32_t kMtu = 512; |
| |
| const char kNameServer0[] = "10.0.1.253"; |
| const char kNameServer1[] = "10.0.1.252"; |
| const char kNameServers[] = "10.0.1.253,10.0.1.252"; |
| |
| const char kSearchDomains[] = "example.com,chromium.org"; |
| const char kSearchDomain0[] = "example.com"; |
| const char kSearchDomain1[] = "chromium.org"; |
| |
| const char kPeerAddress[] = "10.0.0.2"; |
| const int32_t kPrefixLen = 24; |
| |
| const char kExcludedRoutes[] = "192.168.1.0/24,192.168.2.0/24"; |
| const char kExcludedRoute0[] = "192.168.1.0/24"; |
| const char kExcludedRoute1[] = "192.168.2.0/24"; |
| |
| const char kIncludedRoutes[] = "0.0.0.0/0"; |
| const IPConfig::Route kIncludedRoute0("0.0.0.0", 0, "10.0.0.254"); |
| |
| } // namespace |
| |
| class StaticIPParametersTest : public Test { |
| public: |
| StaticIPParametersTest() = default; |
| |
| void ExpectEmptyIPConfig() { |
| EXPECT_TRUE(ipconfig_props_.address.empty()); |
| EXPECT_TRUE(ipconfig_props_.gateway.empty()); |
| EXPECT_EQ(IPConfig::kUndefinedMTU, ipconfig_props_.mtu); |
| EXPECT_TRUE(ipconfig_props_.dns_servers.empty()); |
| EXPECT_TRUE(ipconfig_props_.domain_search.empty()); |
| EXPECT_TRUE(ipconfig_props_.peer_address.empty()); |
| EXPECT_FALSE(ipconfig_props_.subnet_prefix); |
| EXPECT_TRUE(ipconfig_props_.exclusion_list.empty()); |
| EXPECT_TRUE(ipconfig_props_.routes.empty()); |
| EXPECT_TRUE(ipconfig_props_.default_route); |
| } |
| // Modify an IP address string in some predictable way. There's no need |
| // for the output string to be valid from a networking perspective. |
| std::string VersionedAddress(const std::string& address, int version) { |
| std::string returned_address = address; |
| CHECK(returned_address.length()); |
| returned_address[returned_address.length() - 1] += version; |
| return returned_address; |
| } |
| void ExpectPopulatedIPConfigWithVersion(int version) { |
| EXPECT_EQ(VersionedAddress(kAddress, version), ipconfig_props_.address); |
| EXPECT_EQ(VersionedAddress(kGateway, version), ipconfig_props_.gateway); |
| EXPECT_EQ(kMtu + version, ipconfig_props_.mtu); |
| |
| EXPECT_EQ(2, ipconfig_props_.dns_servers.size()); |
| EXPECT_EQ(VersionedAddress(kNameServer0, version), |
| ipconfig_props_.dns_servers[0]); |
| EXPECT_EQ(VersionedAddress(kNameServer1, version), |
| ipconfig_props_.dns_servers[1]); |
| |
| // VersionedAddress() increments the final character of each domain |
| // name. |
| EXPECT_EQ(2, ipconfig_props_.domain_search.size()); |
| EXPECT_EQ(VersionedAddress(kSearchDomain0, version), |
| ipconfig_props_.domain_search[0]); |
| EXPECT_EQ(VersionedAddress(kSearchDomain1, version), |
| ipconfig_props_.domain_search[1]); |
| |
| EXPECT_EQ(VersionedAddress(kPeerAddress, version), |
| ipconfig_props_.peer_address); |
| EXPECT_EQ(kPrefixLen + version, ipconfig_props_.subnet_prefix); |
| |
| EXPECT_EQ(2, ipconfig_props_.exclusion_list.size()); |
| EXPECT_EQ(VersionedAddress(kExcludedRoute0, version), |
| ipconfig_props_.exclusion_list[0]); |
| EXPECT_EQ(VersionedAddress(kExcludedRoute1, version), |
| ipconfig_props_.exclusion_list[1]); |
| |
| // VersionedAddress() increments the final digit of the prefix on |
| // the IncludedRoutes property, and the final digit of the IP address |
| // on the Gateway property. |
| EXPECT_EQ(1, ipconfig_props_.routes.size()); |
| EXPECT_EQ(kIncludedRoute0.host, ipconfig_props_.routes[0].host); |
| EXPECT_EQ(kIncludedRoute0.prefix + version, |
| ipconfig_props_.routes[0].prefix); |
| EXPECT_EQ(VersionedAddress(kIncludedRoute0.gateway, version), |
| ipconfig_props_.routes[0].gateway); |
| EXPECT_FALSE(ipconfig_props_.default_route); |
| } |
| void ExpectPopulatedIPConfig() { ExpectPopulatedIPConfigWithVersion(0); } |
| void ExpectPropertiesWithVersion(PropertyStore* store, |
| const std::string& property_prefix, |
| int version) { |
| KeyValueStore args; |
| Error unused_error; |
| EXPECT_TRUE(store->GetKeyValueStoreProperty(property_prefix + "Config", |
| &args, &unused_error)); |
| EXPECT_EQ(VersionedAddress(kAddress, version), |
| args.Get<std::string>(kAddressProperty)); |
| EXPECT_EQ(VersionedAddress(kGateway, version), |
| args.Get<std::string>(kGatewayProperty)); |
| EXPECT_EQ(kMtu + version, args.Get<int32_t>(kMtuProperty)); |
| std::vector<std::string> kTestNameServers( |
| {VersionedAddress(kNameServer0, version), |
| VersionedAddress(kNameServer1, version)}); |
| EXPECT_EQ(kTestNameServers, args.Get<Strings>(kNameServersProperty)); |
| std::vector<std::string> kTestSearchDomains( |
| {VersionedAddress(kSearchDomain0, version), |
| VersionedAddress(kSearchDomain1, version)}); |
| EXPECT_EQ(kTestSearchDomains, args.Get<Strings>(kSearchDomainsProperty)); |
| EXPECT_EQ(VersionedAddress(kPeerAddress, version), |
| args.Get<std::string>(kPeerAddressProperty)); |
| EXPECT_EQ(kPrefixLen + version, args.Get<int32_t>(kPrefixlenProperty)); |
| std::vector<std::string> kTestExcludedRoutes( |
| {VersionedAddress(kExcludedRoute0, version), |
| VersionedAddress(kExcludedRoute1, version)}); |
| EXPECT_EQ(kTestExcludedRoutes, args.Get<Strings>(kExcludedRoutesProperty)); |
| std::vector<std::string> kTestIncludedRoutes( |
| {VersionedAddress(kIncludedRoutes, version)}); |
| EXPECT_EQ(kTestIncludedRoutes, args.Get<Strings>(kIncludedRoutesProperty)); |
| } |
| void ExpectProperties(PropertyStore* store, |
| const std::string& property_prefix) { |
| ExpectPropertiesWithVersion(store, property_prefix, 0); |
| } |
| void PopulateIPConfig() { |
| ipconfig_props_.address = kAddress; |
| ipconfig_props_.gateway = kGateway; |
| ipconfig_props_.mtu = kMtu; |
| ipconfig_props_.dns_servers = {kNameServer0, kNameServer1}; |
| ipconfig_props_.domain_search = {kSearchDomain0, kSearchDomain1}; |
| ipconfig_props_.peer_address = kPeerAddress; |
| ipconfig_props_.subnet_prefix = kPrefixLen; |
| ipconfig_props_.exclusion_list = {kExcludedRoute0, kExcludedRoute1}; |
| ipconfig_props_.routes = {kIncludedRoute0}; |
| ipconfig_props_.default_route = false; |
| } |
| void SetStaticProperties(PropertyStore* store) { |
| SetStaticPropertiesWithVersion(store, 0); |
| } |
| void SetStaticPropertiesWithVersion(PropertyStore* store, int version) { |
| KeyValueStore args; |
| args.Set<std::string>(kAddressProperty, |
| VersionedAddress(kAddress, version)); |
| args.Set<std::string>(kGatewayProperty, |
| VersionedAddress(kGateway, version)); |
| args.Set<int32_t>(kMtuProperty, kMtu + version); |
| args.Set<Strings>(kNameServersProperty, |
| {VersionedAddress(kNameServer0, version), |
| VersionedAddress(kNameServer1, version)}); |
| args.Set<Strings>(kSearchDomainsProperty, |
| {VersionedAddress(kSearchDomain0, version), |
| VersionedAddress(kSearchDomain1, version)}); |
| args.Set<std::string>(kPeerAddressProperty, |
| VersionedAddress(kPeerAddress, version)); |
| args.Set<int32_t>(kPrefixlenProperty, kPrefixLen + version); |
| args.Set<Strings>(kExcludedRoutesProperty, |
| {VersionedAddress(kExcludedRoute0, version), |
| VersionedAddress(kExcludedRoute1, version)}); |
| args.Set<Strings>(kIncludedRoutesProperty, |
| {VersionedAddress(kIncludedRoutes, version)}); |
| |
| Error error; |
| store->SetKeyValueStoreProperty(kStaticIPConfigProperty, args, &error); |
| } |
| void SetStaticPropertiesWithoutRoute(PropertyStore* store) { |
| KeyValueStore args; |
| args.Set<std::string>(kAddressProperty, kAddress); |
| args.Set<std::string>(kGatewayProperty, kGateway); |
| args.Set<int32_t>(kMtuProperty, kMtu); |
| Error error; |
| store->SetKeyValueStoreProperty(kStaticIPConfigProperty, args, &error); |
| } |
| KeyValueStore* static_args() { return &static_params_.args_; } |
| KeyValueStore* saved_args() { return &static_params_.saved_args_; } |
| |
| protected: |
| StaticIPParameters static_params_; |
| IPConfig::Properties ipconfig_props_; |
| }; |
| |
| TEST_F(StaticIPParametersTest, InitState) { |
| ExpectEmptyIPConfig(); |
| |
| // Applying an empty set of parameters on an empty set of properties should |
| // be a no-op. |
| static_params_.ApplyTo(&ipconfig_props_); |
| ExpectEmptyIPConfig(); |
| } |
| |
| TEST_F(StaticIPParametersTest, ApplyEmptyParameters) { |
| PopulateIPConfig(); |
| static_params_.ApplyTo(&ipconfig_props_); |
| ExpectPopulatedIPConfig(); |
| } |
| |
| TEST_F(StaticIPParametersTest, DefaultRoute) { |
| IPConfig::Properties props; |
| PropertyStore store; |
| static_params_.PlumbPropertyStore(&store); |
| SetStaticPropertiesWithoutRoute(&store); |
| static_params_.ApplyTo(&props); |
| EXPECT_TRUE(props.default_route); |
| SetStaticProperties(&store); |
| static_params_.ApplyTo(&props); |
| EXPECT_FALSE(props.default_route); |
| } |
| |
| TEST_F(StaticIPParametersTest, ControlInterface) { |
| PropertyStore store; |
| int version = 0; |
| static_params_.PlumbPropertyStore(&store); |
| SetStaticProperties(&store); |
| static_params_.ApplyTo(&ipconfig_props_); |
| ExpectPopulatedIPConfig(); |
| |
| EXPECT_TRUE(static_params_.ContainsAddress()); |
| EXPECT_TRUE(store.Contains("StaticIPConfig")); |
| static_args()->Remove("Address"); |
| EXPECT_FALSE(static_params_.ContainsAddress()); |
| static_args()->Remove("Mtu"); |
| IPConfig::Properties props; |
| const std::string kTestAddress("test_address"); |
| props.address = kTestAddress; |
| const int32_t kTestMtu = 256; |
| props.mtu = kTestMtu; |
| static_params_.ApplyTo(&props); |
| EXPECT_EQ(kTestAddress, props.address); |
| EXPECT_EQ(kTestMtu, props.mtu); |
| |
| EXPECT_FALSE(static_args()->Contains<std::string>("Address")); |
| EXPECT_EQ(kGateway, static_args()->Get<std::string>("Gateway")); |
| EXPECT_FALSE(static_args()->Contains<int32_t>("Mtu")); |
| std::vector<std::string> kTestNameServers( |
| {VersionedAddress(kNameServer0, version), |
| VersionedAddress(kNameServer1, version)}); |
| EXPECT_EQ(kTestNameServers, static_args()->Get<Strings>("NameServers")); |
| std::vector<std::string> kTestSearchDomains( |
| {VersionedAddress(kSearchDomain0, version), |
| VersionedAddress(kSearchDomain1, version)}); |
| EXPECT_EQ(kTestSearchDomains, static_args()->Get<Strings>("SearchDomains")); |
| EXPECT_EQ(VersionedAddress(kPeerAddress, version), |
| static_args()->Get<std::string>("PeerAddress")); |
| EXPECT_EQ(kPrefixLen + version, static_args()->Get<int32_t>("Prefixlen")); |
| std::vector<std::string> kTestExcludedRoutes( |
| {VersionedAddress(kExcludedRoute0, version), |
| VersionedAddress(kExcludedRoute1, version)}); |
| EXPECT_EQ(kTestExcludedRoutes, static_args()->Get<Strings>("ExcludedRoutes")); |
| std::vector<std::string> kTestIncludedRoutes( |
| {VersionedAddress(kIncludedRoutes, version)}); |
| EXPECT_EQ(kTestIncludedRoutes, static_args()->Get<Strings>("IncludedRoutes")); |
| } |
| |
| TEST_F(StaticIPParametersTest, Profile) { |
| FakeStore store; |
| const std::string kID = "storage_id"; |
| store.SetString(kID, "StaticIP.Address", kAddress); |
| store.SetString(kID, "StaticIP.Gateway", kGateway); |
| store.SetInt(kID, "StaticIP.Mtu", kMtu); |
| store.SetString(kID, "StaticIP.NameServers", kNameServers); |
| store.SetString(kID, "StaticIP.SearchDomains", kSearchDomains); |
| store.SetString(kID, "StaticIP.PeerAddress", kPeerAddress); |
| store.SetInt(kID, "StaticIP.Prefixlen", kPrefixLen); |
| store.SetString(kID, "StaticIP.ExcludedRoutes", kExcludedRoutes); |
| store.SetString(kID, "StaticIP.IncludedRoutes", kIncludedRoutes); |
| |
| static_params_.Load(&store, kID); |
| static_params_.ApplyTo(&ipconfig_props_); |
| ExpectPopulatedIPConfig(); |
| |
| static_params_.Save(&store, kID); |
| |
| std::string address; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.Address", &address)); |
| EXPECT_EQ(address, kAddress); |
| std::string gateway; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.Gateway", &gateway)); |
| EXPECT_EQ(gateway, kGateway); |
| int mtu; |
| EXPECT_TRUE(store.GetInt(kID, "StaticIP.Mtu", &mtu)); |
| EXPECT_EQ(mtu, kMtu); |
| std::string nameservers; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.NameServers", &nameservers)); |
| EXPECT_EQ(nameservers, kNameServers); |
| std::string searchdomains; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.SearchDomains", &searchdomains)); |
| EXPECT_EQ(searchdomains, kSearchDomains); |
| std::string peeraddress; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.PeerAddress", &peeraddress)); |
| EXPECT_EQ(peeraddress, kPeerAddress); |
| int prefixlen; |
| EXPECT_TRUE(store.GetInt(kID, "StaticIP.Prefixlen", &prefixlen)); |
| EXPECT_EQ(prefixlen, kPrefixLen); |
| std::string excludedroutes; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.ExcludedRoutes", &excludedroutes)); |
| EXPECT_EQ(excludedroutes, kExcludedRoutes); |
| std::string includedroutes; |
| EXPECT_TRUE(store.GetString(kID, "StaticIP.IncludedRoutes", &includedroutes)); |
| EXPECT_EQ(includedroutes, kIncludedRoutes); |
| } |
| |
| TEST_F(StaticIPParametersTest, SavedParameters) { |
| // Calling RestoreTo() when no parameters are set should not crash or |
| // add any entries. |
| static_params_.RestoreTo(&ipconfig_props_); |
| ExpectEmptyIPConfig(); |
| |
| PopulateIPConfig(); |
| PropertyStore static_params_props; |
| static_params_.PlumbPropertyStore(&static_params_props); |
| SetStaticPropertiesWithVersion(&static_params_props, 1); |
| static_params_.ApplyTo(&ipconfig_props_); |
| |
| // The version 0 properties in |ipconfig_props_| are now in SavedIP.* |
| // properties, while the version 1 StaticIP parameters are now in |
| // |ipconfig_props_|. |
| ExpectPropertiesWithVersion(&static_params_props, "SavedIP", 0); |
| ExpectPopulatedIPConfigWithVersion(1); |
| |
| // Clear all "StaticIP" parameters. |
| static_args()->Clear(); |
| |
| // Another ApplyTo() call rotates the version 1 properties in |
| // |ipconfig_props_| over to SavedIP.*. Since there are no StaticIP |
| // parameters, |ipconfig_props_| should remain populated with version 1 |
| // parameters. |
| static_params_.ApplyTo(&ipconfig_props_); |
| ExpectPropertiesWithVersion(&static_params_props, "SavedIP", 1); |
| ExpectPopulatedIPConfigWithVersion(1); |
| |
| // Reset |ipconfig_props_| to version 0. |
| PopulateIPConfig(); |
| |
| // A RestoreTo() call moves the version 1 "SavedIP" parameters into |
| // |ipconfig_props_|. |
| SetStaticPropertiesWithVersion(&static_params_props, 2); |
| static_params_.RestoreTo(&ipconfig_props_); |
| ExpectPopulatedIPConfigWithVersion(1); |
| |
| // All "SavedIP" parameters should be cleared. |
| EXPECT_TRUE(saved_args()->IsEmpty()); |
| |
| // Static IP parameters should be unchanged. |
| ExpectPropertiesWithVersion(&static_params_props, "StaticIP", 2); |
| } |
| |
| TEST_F(StaticIPParametersTest, IPConfigRefreshed) { |
| MockControl control; |
| scoped_refptr<MockIPConfig> ipconfig = new MockIPConfig(&control, "int0"); |
| static_params_.SetIPConfig(ipconfig->weak_ptr_factory_.GetWeakPtr()); |
| EXPECT_CALL(*ipconfig, Refresh()); |
| PropertyStore store; |
| static_params_.PlumbPropertyStore(&store); |
| SetStaticProperties(&store); |
| } |
| |
| } // namespace shill |