diff options
Diffstat (limited to 'cros/connection_manager_unittest.cc')
-rw-r--r-- | cros/connection_manager_unittest.cc | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/cros/connection_manager_unittest.cc b/cros/connection_manager_unittest.cc new file mode 100644 index 00000000..46da8cc9 --- /dev/null +++ b/cros/connection_manager_unittest.cc @@ -0,0 +1,360 @@ +// +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "update_engine/cros/connection_manager.h" + +#include <memory> +#include <set> +#include <string> +#include <utility> + +#include <base/logging.h> +#include <brillo/any.h> +#include <brillo/message_loops/fake_message_loop.h> +#include <brillo/variant_dictionary.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <shill/dbus-constants.h> +#include <shill/dbus-proxies.h> +#include <shill/dbus-proxy-mocks.h> + +#include "update_engine/common/test_utils.h" +#include "update_engine/cros/fake_shill_proxy.h" +#include "update_engine/cros/fake_system_state.h" + +using chromeos_update_engine::connection_utils::StringForConnectionType; +using org::chromium::flimflam::ManagerProxyMock; +using org::chromium::flimflam::ServiceProxyMock; +using std::set; +using std::string; +using testing::_; +using testing::Return; +using testing::SetArgPointee; + +namespace chromeos_update_engine { + +class ConnectionManagerTest : public ::testing::Test { + public: + ConnectionManagerTest() : fake_shill_proxy_(new FakeShillProxy()) {} + + void SetUp() override { + loop_.SetAsCurrent(); + FakeSystemState::CreateInstance(); + FakeSystemState::Get()->set_connection_manager(&cmut_); + } + + void TearDown() override { EXPECT_FALSE(loop_.PendingTasks()); } + + protected: + // Sets the default_service object path in the response from the + // ManagerProxyMock instance. + void SetManagerReply(const char* default_service, bool reply_succeeds); + + // Sets the |service_type|, |physical_technology| and |service_tethering| + // properties in the mocked service |service_path|. If any of the three + // const char* is a nullptr, the corresponding property will not be included + // in the response. + void SetServiceReply(const string& service_path, + const char* service_type, + const char* physical_technology, + const char* service_tethering); + + void TestWithServiceType(const char* service_type, + const char* physical_technology, + ConnectionType expected_type); + + void TestWithServiceDisconnected(ConnectionType expected_type); + + void TestWithServiceTethering(const char* service_tethering, + ConnectionTethering expected_tethering); + + brillo::FakeMessageLoop loop_{nullptr}; + FakeShillProxy* fake_shill_proxy_; + + // ConnectionManager under test. + ConnectionManager cmut_{fake_shill_proxy_}; +}; + +void ConnectionManagerTest::SetManagerReply(const char* default_service, + bool reply_succeeds) { + ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy(); + if (!reply_succeeds) { + EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _)) + .WillOnce(Return(false)); + return; + } + + // Create a dictionary of properties and optionally include the default + // service. + brillo::VariantDictionary reply_dict; + reply_dict["SomeOtherProperty"] = 0xC0FFEE; + + if (default_service) { + reply_dict[shill::kDefaultServiceProperty] = + dbus::ObjectPath(default_service); + } + EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true))); +} + +void ConnectionManagerTest::SetServiceReply(const string& service_path, + const char* service_type, + const char* physical_technology, + const char* service_tethering) { + brillo::VariantDictionary reply_dict; + reply_dict["SomeOtherProperty"] = 0xC0FFEE; + + if (service_type) + reply_dict[shill::kTypeProperty] = string(service_type); + + if (physical_technology) { + reply_dict[shill::kPhysicalTechnologyProperty] = + string(physical_technology); + } + + if (service_tethering) + reply_dict[shill::kTetheringProperty] = string(service_tethering); + + std::unique_ptr<ServiceProxyMock> service_proxy_mock(new ServiceProxyMock()); + + // Plumb return value into mock object. + EXPECT_CALL(*service_proxy_mock.get(), GetProperties(_, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true))); + + fake_shill_proxy_->SetServiceForPath(dbus::ObjectPath(service_path), + std::move(service_proxy_mock)); +} + +void ConnectionManagerTest::TestWithServiceType(const char* service_type, + const char* physical_technology, + ConnectionType expected_type) { + SetManagerReply("/service/guest/network", true); + SetServiceReply("/service/guest/network", + service_type, + physical_technology, + shill::kTetheringNotDetectedState); + + ConnectionType type; + ConnectionTethering tethering; + EXPECT_TRUE(cmut_.GetConnectionProperties(&type, &tethering)); + EXPECT_EQ(expected_type, type); + testing::Mock::VerifyAndClearExpectations( + fake_shill_proxy_->GetManagerProxy()); +} + +void ConnectionManagerTest::TestWithServiceTethering( + const char* service_tethering, ConnectionTethering expected_tethering) { + SetManagerReply("/service/guest/network", true); + SetServiceReply( + "/service/guest/network", shill::kTypeWifi, nullptr, service_tethering); + + ConnectionType type; + ConnectionTethering tethering; + EXPECT_TRUE(cmut_.GetConnectionProperties(&type, &tethering)); + EXPECT_EQ(expected_tethering, tethering); + testing::Mock::VerifyAndClearExpectations( + fake_shill_proxy_->GetManagerProxy()); +} + +void ConnectionManagerTest::TestWithServiceDisconnected( + ConnectionType expected_type) { + SetManagerReply("/", true); + + ConnectionType type; + ConnectionTethering tethering; + EXPECT_TRUE(cmut_.GetConnectionProperties(&type, &tethering)); + EXPECT_EQ(expected_type, type); + testing::Mock::VerifyAndClearExpectations( + fake_shill_proxy_->GetManagerProxy()); +} + +TEST_F(ConnectionManagerTest, SimpleTest) { + TestWithServiceType(shill::kTypeEthernet, nullptr, ConnectionType::kEthernet); + TestWithServiceType(shill::kTypeWifi, nullptr, ConnectionType::kWifi); + TestWithServiceType(shill::kTypeCellular, nullptr, ConnectionType::kCellular); +} + +TEST_F(ConnectionManagerTest, PhysicalTechnologyTest) { + TestWithServiceType(shill::kTypeVPN, nullptr, ConnectionType::kUnknown); + TestWithServiceType( + shill::kTypeVPN, shill::kTypeVPN, ConnectionType::kUnknown); + TestWithServiceType(shill::kTypeVPN, shill::kTypeWifi, ConnectionType::kWifi); +} + +TEST_F(ConnectionManagerTest, TetheringTest) { + TestWithServiceTethering(shill::kTetheringConfirmedState, + ConnectionTethering::kConfirmed); + TestWithServiceTethering(shill::kTetheringNotDetectedState, + ConnectionTethering::kNotDetected); + TestWithServiceTethering(shill::kTetheringSuspectedState, + ConnectionTethering::kSuspected); + TestWithServiceTethering("I'm not a valid property value =)", + ConnectionTethering::kUnknown); +} + +TEST_F(ConnectionManagerTest, UnknownTest) { + TestWithServiceType("foo", nullptr, ConnectionType::kUnknown); +} + +TEST_F(ConnectionManagerTest, DisconnectTest) { + TestWithServiceDisconnected(ConnectionType::kDisconnected); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOverEthernetTest) { + // Updates over Ethernet are allowed even if there's no policy. + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOverWifiTest) { + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOnlyOver3GPerPolicyTest) { + policy::MockDevicePolicy allow_3g_policy; + + FakeSystemState::Get()->set_device_policy(&allow_3g_policy); + + // This test tests cellular (3G) being the only connection type being allowed. + set<string> allowed_set; + allowed_set.insert(StringForConnectionType(ConnectionType::kCellular)); + + EXPECT_CALL(allow_3g_policy, GetAllowedConnectionTypesForUpdate(_)) + .Times(1) + .WillOnce(DoAll(SetArgPointee<0>(allowed_set), Return(true))); + + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOver3GAndOtherTypesPerPolicyTest) { + policy::MockDevicePolicy allow_3g_policy; + + FakeSystemState::Get()->set_device_policy(&allow_3g_policy); + + // This test tests multiple connection types being allowed, with + // 3G one among them. Only Cellular is currently enforced by the policy + // setting. + set<string> allowed_set; + allowed_set.insert(StringForConnectionType(ConnectionType::kCellular)); + + EXPECT_CALL(allow_3g_policy, GetAllowedConnectionTypesForUpdate(_)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(allowed_set), Return(true))); + + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet, + ConnectionTethering::kUnknown)); + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet, + ConnectionTethering::kNotDetected)); + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular, + ConnectionTethering::kUnknown)); + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi, + ConnectionTethering::kUnknown)); + + // Tethered networks are treated in the same way as Cellular networks and + // thus allowed. + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet, + ConnectionTethering::kConfirmed)); + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi, + ConnectionTethering::kConfirmed)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOverCellularByDefaultTest) { + policy::MockDevicePolicy device_policy; + // Set an empty device policy. + FakeSystemState::Get()->set_device_policy(&device_policy); + + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOverTetheredNetworkByDefaultTest) { + policy::MockDevicePolicy device_policy; + // Set an empty device policy. + FakeSystemState::Get()->set_device_policy(&device_policy); + + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi, + ConnectionTethering::kConfirmed)); + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet, + ConnectionTethering::kConfirmed)); + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi, + ConnectionTethering::kSuspected)); +} + +TEST_F(ConnectionManagerTest, BlockUpdatesOver3GPerPolicyTest) { + policy::MockDevicePolicy block_3g_policy; + + FakeSystemState::Get()->set_device_policy(&block_3g_policy); + + // Test that updates for 3G are blocked while updates are allowed + // over several other types. + set<string> allowed_set; + allowed_set.insert(StringForConnectionType(ConnectionType::kEthernet)); + allowed_set.insert(StringForConnectionType(ConnectionType::kWifi)); + + EXPECT_CALL(block_3g_policy, GetAllowedConnectionTypesForUpdate(_)) + .Times(1) + .WillOnce(DoAll(SetArgPointee<0>(allowed_set), Return(true))); + + EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOver3GIfPolicyIsNotSet) { + policy::MockDevicePolicy device_policy; + + FakeSystemState::Get()->set_device_policy(&device_policy); + + // Return false for GetAllowedConnectionTypesForUpdate and see + // that updates are allowed as device policy is not set. Further + // check is left to |OmahaRequestAction|. + EXPECT_CALL(device_policy, GetAllowedConnectionTypesForUpdate(_)) + .Times(1) + .WillOnce(Return(false)); + + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, AllowUpdatesOverCellularIfPolicyFailsToBeLoaded) { + FakeSystemState::Get()->set_device_policy(nullptr); + + EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular, + ConnectionTethering::kUnknown)); +} + +TEST_F(ConnectionManagerTest, StringForConnectionTypeTest) { + EXPECT_STREQ(shill::kTypeEthernet, + StringForConnectionType(ConnectionType::kEthernet)); + EXPECT_STREQ(shill::kTypeWifi, + StringForConnectionType(ConnectionType::kWifi)); + EXPECT_STREQ(shill::kTypeCellular, + StringForConnectionType(ConnectionType::kCellular)); + EXPECT_STREQ("Unknown", StringForConnectionType(ConnectionType::kUnknown)); + EXPECT_STREQ("Unknown", + StringForConnectionType(static_cast<ConnectionType>(999999))); +} + +TEST_F(ConnectionManagerTest, MalformedServiceList) { + SetManagerReply("/service/guest/network", false); + + ConnectionType type; + ConnectionTethering tethering; + EXPECT_FALSE(cmut_.GetConnectionProperties(&type, &tethering)); +} + +} // namespace chromeos_update_engine |