blob: 59523bfb6acd391f1948af9d9e7e8709e61f2e56 [file] [log] [blame]
// Copyright 2021 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 <string>
#include <vector>
#include <brillo/dbus/mock_dbus_method_response.h>
#include <brillo/errors/error_codes.h>
#include <brillo/message_loops/fake_message_loop.h>
#include <dbus/shill/dbus-constants.h>
#include <gtest/gtest.h>
#include "minios/minios.h"
#include "minios/mock_network_manager.h"
#include "minios/mock_shill_proxy.h"
#include "minios/network_manager.h"
#include "minios/shill_utils.h"
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::IsNull;
using ::testing::NotNull;
using ::testing::StrictMock;
namespace minios {
class NetworkManagerTest : public ::testing::Test {
public:
void SetUp() override {
loop_.SetAsCurrent();
auto mock_shill_proxy_ptr = std::make_unique<MockShillProxy>();
mock_shill_proxy_ptr_ = mock_shill_proxy_ptr.get();
network_manager_ =
std::make_unique<NetworkManager>(std::move(mock_shill_proxy_ptr));
network_manager_->AddObserver(&mock_network_manager_observer_);
}
protected:
MockShillProxy* mock_shill_proxy_ptr_;
StrictMock<MockNetworkManagerObserver> mock_network_manager_observer_;
std::unique_ptr<NetworkManager> network_manager_;
base::SimpleTestClock clock_;
brillo::FakeMessageLoop loop_{&clock_};
};
TEST_F(NetworkManagerTest, Connect) {
EXPECT_CALL(*mock_shill_proxy_ptr_,
ManagerRequestScan(WifiTechnologyType::WIFI, _, _));
network_manager_->Connect("ssid-foo", "passphrase");
// It's okay to request the same SSID for connection, a no-op.
network_manager_->Connect("ssid-foo", "passphrase");
// Passphrase changes for same SSID will be ignored, a no-op.
network_manager_->Connect("ssid-foo", "passphrase-other");
// Connecting to a different SSID should be successful.
EXPECT_CALL(*mock_shill_proxy_ptr_,
ManagerRequestScan(WifiTechnologyType::WIFI, _, _));
network_manager_->Connect("ssid-bar", "passphrase");
}
TEST_F(NetworkManagerTest, Connect_RequestScanSuccess_NoPassphrase) {
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField();
auto iter_no_passphrase = network_manager_->connect_map_.begin();
const brillo::VariantDictionary properties = {
{shill::kModeProperty, brillo::Any(ToString(WifiStationType::MANAGED))},
{shill::kNameProperty, brillo::Any(iter_no_passphrase->first)},
{shill::kSecurityClassProperty,
brillo::Any(ToString(WifiSecurityType::NONE))},
{shill::kTypeProperty, brillo::Any(ToString(WifiTechnologyType::WIFI))},
};
EXPECT_CALL(*mock_shill_proxy_ptr_,
ManagerFindMatchingService(properties, _, _));
network_manager_->RequestScanSuccess(iter_no_passphrase);
}
TEST_F(NetworkManagerTest, Connect_RequestScanSuccess_Passphrase) {
network_manager_->connect_map_["ssid"] =
NetworkManager::ConnectField{.passphrase = "passphrase"};
auto iter_passphrase = network_manager_->connect_map_.begin();
const brillo::VariantDictionary properties = {
{shill::kModeProperty, brillo::Any(ToString(WifiStationType::MANAGED))},
{shill::kNameProperty, brillo::Any(iter_passphrase->first)},
{shill::kSecurityClassProperty,
brillo::Any(ToString(WifiSecurityType::PSK))},
{shill::kTypeProperty, brillo::Any(ToString(WifiTechnologyType::WIFI))},
};
EXPECT_CALL(*mock_shill_proxy_ptr_,
ManagerFindMatchingService(properties, _, _));
network_manager_->RequestScanSuccess(iter_passphrase);
}
TEST_F(NetworkManagerTest, Connect_GetServiceSuccess_GoodStrength) {
network_manager_->connect_map_["ssid"] =
NetworkManager::ConnectField{.passphrase = "passphrase"};
auto iter = network_manager_->connect_map_.begin();
const brillo::VariantDictionary input_properties = {
{shill::kSignalStrengthProperty, brillo::Any(uint8_t(1))},
};
const brillo::VariantDictionary expected_properties = {
{shill::kAutoConnectProperty, brillo::Any(true)},
{shill::kPassphraseProperty, brillo::Any(iter->second.passphrase)},
};
EXPECT_CALL(*mock_shill_proxy_ptr_,
ServiceSetProperties(_, expected_properties, _, _));
network_manager_->GetServiceSuccess(iter, input_properties);
}
TEST_F(NetworkManagerTest, Connect_GetServiceSuccess_NoPassphrase) {
// Empty password does not send `kPassphraseProperty`.
network_manager_->connect_map_["ssid"] =
NetworkManager::ConnectField{.passphrase = ""};
auto iter = network_manager_->connect_map_.begin();
const brillo::VariantDictionary input_properties = {
{shill::kSignalStrengthProperty, brillo::Any(uint8_t(1))},
};
const brillo::VariantDictionary expected_properties = {
{shill::kAutoConnectProperty, brillo::Any(true)},
};
EXPECT_CALL(*mock_shill_proxy_ptr_,
ServiceSetProperties(_, expected_properties, _, _));
network_manager_->GetServiceSuccess(iter, input_properties);
}
TEST_F(NetworkManagerTest, Connect_GetServiceSuccess_BadStrength) {
network_manager_->connect_map_["ssid"] =
NetworkManager::ConnectField{.passphrase = "passphrase"};
auto iter = network_manager_->connect_map_.begin();
const brillo::VariantDictionary input_properties = {
{shill::kSignalStrengthProperty, brillo::Any(uint8_t(0))},
};
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", NotNull()));
network_manager_->GetServiceSuccess(iter, input_properties);
}
TEST_F(NetworkManagerTest, Connect_GetServiceSuccess_MissingStrength) {
network_manager_->connect_map_["ssid"] =
NetworkManager::ConnectField{.passphrase = "passphrase"};
auto iter = network_manager_->connect_map_.begin();
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", NotNull()));
network_manager_->GetServiceSuccess(iter, {});
}
TEST_F(NetworkManagerTest,
Connect_ConnectToNetworkError_InProgressRetriesConnection) {
auto error_ptr =
brillo::Error::Create(FROM_HERE, brillo::errors::dbus::kDomain,
shill::kErrorResultInProgress, "");
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField{
.service_path = dbus::ObjectPath("some-service-path")};
auto iter = network_manager_->connect_map_.begin();
network_manager_->ConnectToNetworkError(iter, error_ptr.get());
EXPECT_CALL(*mock_shill_proxy_ptr_,
ServiceConnect(iter->second.service_path, _, _));
clock_.Advance(base::TimeDelta::FromSeconds(1));
loop_.RunOnce(false);
}
TEST_F(NetworkManagerTest, Connect_ConnectToNetworkError_AlreadyConnected) {
auto error_ptr =
brillo::Error::Create(FROM_HERE, brillo::errors::dbus::kDomain,
shill::kErrorResultAlreadyConnected, "");
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField{
.service_path = dbus::ObjectPath("some-service-path")};
auto iter = network_manager_->connect_map_.begin();
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", IsNull()));
network_manager_->ConnectToNetworkError(iter, error_ptr.get());
}
TEST_F(NetworkManagerTest,
Connect_ConnectToNetworkError_OtherErrorResponsesFromShill) {
auto error_ptr = brillo::Error::Create(
FROM_HERE, brillo::errors::dbus::kDomain, DBUS_ERROR_FAILED, "");
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField();
auto iter = network_manager_->connect_map_.begin();
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", NotNull()));
network_manager_->ConnectToNetworkError(iter, error_ptr.get());
}
TEST_F(NetworkManagerTest,
Connect_GetServiceCheckConnectionSuccess_FailureState) {
const brillo::VariantDictionary input_properties = {
{shill::kStateProperty, brillo::Any(std::string(shill::kStateFailure))},
};
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField{
.service_path = dbus::ObjectPath("some-service-path")};
auto iter = network_manager_->connect_map_.begin();
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", NotNull()));
network_manager_->GetServiceCheckConnectionSuccess(iter, input_properties);
}
TEST_F(NetworkManagerTest,
Connect_GetServiceCheckConnectionSuccess_OnlineState) {
const brillo::VariantDictionary input_properties = {
{shill::kStateProperty, brillo::Any(std::string(shill::kStateOnline))},
};
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField{
.service_path = dbus::ObjectPath("some-service-path")};
auto iter = network_manager_->connect_map_.begin();
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", IsNull()));
network_manager_->GetServiceCheckConnectionSuccess(iter, input_properties);
}
TEST_F(NetworkManagerTest,
Connect_GetServiceCheckConnectionSuccess_MissingState) {
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField{
.service_path = dbus::ObjectPath("some-service-path")};
auto iter = network_manager_->connect_map_.begin();
EXPECT_CALL(mock_network_manager_observer_, OnConnect("ssid", NotNull()));
network_manager_->GetServiceCheckConnectionSuccess(iter, {});
}
TEST_F(NetworkManagerTest,
Connect_GetServiceCheckConnectionSuccess_IntermediateState) {
const brillo::VariantDictionary input_properties = {
{shill::kStateProperty, brillo::Any(std::string(shill::kStateReady))},
};
network_manager_->connect_map_["ssid"] = NetworkManager::ConnectField{
.service_path = dbus::ObjectPath("some-service-path")};
auto iter = network_manager_->connect_map_.begin();
network_manager_->GetServiceCheckConnectionSuccess(iter, input_properties);
EXPECT_CALL(*mock_shill_proxy_ptr_,
ServiceGetProperties(iter->second.service_path, _, _));
clock_.Advance(base::TimeDelta::FromSeconds(
NetworkManager::kCheckConnectionRetryMsDelay * 2));
loop_.RunOnce(false);
}
TEST_F(NetworkManagerTest, GetNetworks) {
EXPECT_TRUE(network_manager_->get_networks_list_.empty());
EXPECT_CALL(*mock_shill_proxy_ptr_,
ManagerRequestScan(WifiTechnologyType::WIFI, _, _));
network_manager_->GetNetworks();
EXPECT_EQ(network_manager_->get_networks_list_.size(), 1);
// Subsequent `GetNetworks()` should be bundled.
network_manager_->GetNetworks();
EXPECT_EQ(network_manager_->get_networks_list_.size(), 1);
}
TEST_F(NetworkManagerTest, GetGlobalPropertiesSuccess_MultipleServices) {
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField());
dbus::ObjectPath object_path("some-service-path");
dbus::ObjectPath other_object_path("other-some-service-path");
std::vector<dbus::ObjectPath> object_paths = {other_object_path, object_path};
const brillo::VariantDictionary input_properties = {
{shill::kServicesProperty, brillo::Any(object_paths)},
};
EXPECT_CALL(*mock_shill_proxy_ptr_, ServiceGetProperties(object_path, _, _));
network_manager_->GetGlobalPropertiesSuccess(iter, input_properties);
// Should still hold `other_object_path` to iterate over and get the Service
// name from as `object_path` was binded into `ServiceGetProperties()`.
EXPECT_EQ(iter->service_paths.size(), 1);
}
TEST_F(NetworkManagerTest, GetGlobalPropertiesSuccess_EmptyServices) {
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField());
EXPECT_CALL(mock_network_manager_observer_,
OnGetNetworks(testing::_, IsNull()));
network_manager_->GetGlobalPropertiesSuccess(iter, {});
}
TEST_F(NetworkManagerTest, IterateOverServicePropertiesSuccess_EmptyServices) {
// Explicitly empty the `service_paths`.
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField{.service_paths = {}});
EXPECT_CALL(mock_network_manager_observer_,
OnGetNetworks(testing::_, IsNull()));
network_manager_->IterateOverServicePropertiesSuccess(iter, {});
}
TEST_F(NetworkManagerTest, IterateOverServicePropertiesSuccess_OneService) {
// Explicitly empty the `service_paths`.
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField{.service_paths = {}});
const std::string kSsid = "some-ssid-name";
const brillo::VariantDictionary input_properties = {
{shill::kNameProperty, brillo::Any(kSsid)},
};
EXPECT_CALL(mock_network_manager_observer_,
OnGetNetworks(testing::_, IsNull()));
network_manager_->IterateOverServicePropertiesSuccess(iter, input_properties);
}
TEST_F(NetworkManagerTest,
IterateOverServicePropertiesSuccess_MoreServicesToIterate) {
dbus::ObjectPath object_path("some-service-path");
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField{.service_paths = {object_path}});
const std::string kSsid = "some-ssid-name";
const brillo::VariantDictionary input_properties = {
{shill::kNameProperty, brillo::Any(kSsid)},
};
EXPECT_TRUE(iter->networks.empty());
EXPECT_CALL(*mock_shill_proxy_ptr_, ServiceGetProperties(object_path, _, _));
network_manager_->IterateOverServicePropertiesSuccess(iter, input_properties);
EXPECT_THAT(iter->networks[0].ssid, kSsid);
EXPECT_TRUE(iter->service_paths.empty());
}
TEST_F(NetworkManagerTest,
IterateOverServicePropertiesError_MoreServicesToIterate) {
dbus::ObjectPath object_path("some-service-path");
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField{.service_paths = {object_path}});
EXPECT_CALL(*mock_shill_proxy_ptr_, ServiceGetProperties(object_path, _, _));
network_manager_->IterateOverServicePropertiesError(iter, nullptr);
EXPECT_TRUE(iter->service_paths.empty());
}
TEST_F(NetworkManagerTest,
IterateOverServicePropertiesError_AlwaysReturnOnEnd) {
const std::string kSsid = "some-ssid-name";
// Explicitly empty the `service_paths`.
// Put `kSsid` into the already parsed `networks` list.
auto iter = network_manager_->get_networks_list_.insert(
network_manager_->get_networks_list_.begin(),
NetworkManager::GetNetworksField{.service_paths = {},
.networks = {{.ssid = kSsid}}});
EXPECT_CALL(mock_network_manager_observer_,
OnGetNetworks(testing::_, IsNull()));
network_manager_->IterateOverServicePropertiesError(iter, nullptr);
}
} // namespace minios