// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/webui/diagnostics_ui/backend/connectivity/network_health_provider.h"
#include <utility>
#include "ash/system/diagnostics/diagnostics_log_controller.h"
#include "ash/system/diagnostics/fake_diagnostics_browser_delegate.h"
#include "ash/system/diagnostics/networking_log.h"
#include "ash/test/ash_test_base.h"
#include "ash/webui/diagnostics_ui/backend/common/histogram_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromeos/ash/components/dbus/shill/shill_ipconfig_client.h"
#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/network_cert_loader.h"
#include "chromeos/ash/components/network/network_device_handler.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/network/network_profile_handler.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/network_type_pattern.h"
#include "chromeos/ash/components/network/onc/network_onc_utils.h"
#include "chromeos/ash/components/network/system_token_cert_db_storage.h"
#include "chromeos/ash/components/network/technology_state_controller.h"
#include "chromeos/ash/components/test/ash_test_suite.h"
#include "chromeos/ash/services/network_config/cros_network_config.h"
#include "chromeos/ash/services/network_config/in_process_instance.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "chromeos/services/network_config/public/mojom/network_types.mojom-shared.h"
#include "components/onc/onc_constants.h"
#include "components/onc/onc_pref_names.h"
#include "components/prefs/testing_pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "dbus/object_path.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
#include "ui/base/resource/resource_bundle.h"
namespace ash::diagnostics {
namespace {
constexpr char kEth0DevicePath[] = "/device/eth0";
constexpr char kEth0Name[] = "eth0_name";
constexpr char kEth0NetworkGuid[] = "eth0_network_guid";
constexpr char kWlan0DevicePath[] = "/device/wlan0";
constexpr char kWlan0Name[] = "wlan0_name";
constexpr char kWlan0NetworkGuid[] = "wlan0_network_guid";
constexpr char kCellular0DevicePath[] = "/device/cellular0";
constexpr char kCellular0Name[] = "cellular0_name";
constexpr char kCellular0NetworkGuid[] = "cellular0_network_guid";
constexpr char kFormattedMacAddress[] = "01:23:45:67:89:AB";
constexpr char kTestIPConfigPath[] = "test_ip_config_path";
constexpr char kNetworkDataError[] = "ChromeOS.DiagnosticsUi.Error.Network";
// Due to how CrosNetworkConfig notifies observers of changes, the
// expectation_not_met_error will be triggered 4 times for every change.
constexpr int kExpectationNotMetErrorCount = 4;
class FakeNetworkListObserver : public mojom::NetworkListObserver {
public:
void OnNetworkListChanged(const std::vector<std::string>& observer_guids,
const std::string& active_guid) override {
observer_guids_ = observer_guids;
active_guid_ = active_guid;
call_count_++;
}
mojo::PendingRemote<mojom::NetworkListObserver> pending_remote() {
return receiver_.BindNewPipeAndPassRemote();
}
const std::vector<std::string>& observer_guids() const {
return observer_guids_;
}
const std::string& active_guid() const { return active_guid_; }
size_t call_count() const { return call_count_; }
private:
std::vector<std::string> observer_guids_;
std::string active_guid_;
size_t call_count_ = 0;
mojo::Receiver<mojom::NetworkListObserver> receiver_{this};
};
class FakeNetworkStateObserver : public mojom::NetworkStateObserver {
public:
void OnNetworkStateChanged(mojom::NetworkPtr network_ptr) override {
network_state_updates_.push_back(std::move(network_ptr));
}
mojo::PendingRemote<mojom::NetworkStateObserver> pending_remote() {
return receiver_.BindNewPipeAndPassRemote();
}
const mojom::NetworkPtr& GetLatestState() const {
DCHECK(HasFired());
return network_state_updates_.back();
}
size_t GetCallCount() const { return network_state_updates_.size(); }
bool HasFired() const { return GetCallCount() > 0; }
private:
// Tracks calls to OnNetworkStateChanged. Each call adds an element to
// the vector.
std::vector<mojom::NetworkPtr> network_state_updates_;
mojo::Receiver<mojom::NetworkStateObserver> receiver_{this};
};
// Expects that the call count increases and returns the new call count.
void ExpectListObserverFired(const FakeNetworkListObserver& observer,
size_t* prior_call_count) {
DCHECK(prior_call_count);
const size_t current_call_count = observer.call_count();
EXPECT_GT(current_call_count, *prior_call_count);
*prior_call_count = current_call_count;
}
// Expects that the call count increases and returns the new call count.
void ExpectStateObserverFired(const FakeNetworkStateObserver& observer,
size_t* prior_call_count) {
DCHECK(prior_call_count);
const size_t current_call_count = observer.GetCallCount();
EXPECT_GT(current_call_count, *prior_call_count);
*prior_call_count = current_call_count;
}
void VerifyNetworkDataErrorBucketCounts(
const base::HistogramTester& tester,
size_t expected_no_data_error,
size_t expected_not_a_number_error,
size_t expected_expectation_not_met_error) {
tester.ExpectBucketCount(kNetworkDataError, metrics::DataError::kNoData,
expected_no_data_error);
tester.ExpectBucketCount(kNetworkDataError, metrics::DataError::kNotANumber,
expected_not_a_number_error);
tester.ExpectBucketCount(kNetworkDataError,
metrics::DataError::kExpectationNotMet,
expected_expectation_not_met_error);
}
} // namespace
class NetworkHealthProviderTest : public AshTestBase {
public:
NetworkHealthProviderTest() = default;
NetworkHealthProviderTest(const NetworkHealthProviderTest&) = delete;
NetworkHealthProviderTest& operator=(const NetworkHealthProviderTest&) =
delete;
~NetworkHealthProviderTest() override = default;
void SetUp() override {
ui::ResourceBundle::CleanupSharedInstance();
AshTestSuite::LoadTestResources();
AshTestBase::SetUp();
SystemTokenCertDbStorage::Initialize();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::make_unique<user_manager::FakeUserManager>());
// NetworkHandler has pieces that depend on NetworkCertLoader so it's better
// to initialize NetworkHandlerTestHelper after
// NetworkCertLoader::Initialize(). Same with CrosNetworkConfig since it
// depends on NetworkHandler
NetworkCertLoader::Initialize();
network_handler_test_helper_ = std::make_unique<NetworkHandlerTestHelper>();
network_handler_test_helper_->AddDefaultProfiles();
network_handler_test_helper_->RegisterPrefs(user_prefs_.registry(),
local_state_.registry());
PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry());
PrefProxyConfigTrackerImpl::RegisterPrefs(local_state_.registry());
network_handler_test_helper_->InitializePrefs(&user_prefs_, &local_state_);
ClearDevicesAndServices();
cros_network_config_ =
std::make_unique<network_config::CrosNetworkConfig>();
network_config::OverrideInProcessInstanceForTesting(
cros_network_config_.get());
base::RunLoop().RunUntilIdle();
ManagedNetworkConfigurationHandler* managed_network_configuration_handler =
NetworkHandler::Get()->managed_network_configuration_handler();
managed_network_configuration_handler->SetPolicy(
::onc::ONC_SOURCE_DEVICE_POLICY,
/*userhash=*/std::string(),
/*network_configs_onc=*/base::Value::List(),
/*global_network_config=*/base::Value::Dict());
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
network_health_provider_ = std::make_unique<NetworkHealthProvider>();
DiagnosticsLogController::Initialize(
std::make_unique<FakeDiagnosticsBrowserDelegate>());
}
void TearDown() override {
// Clear in process instance prior to destroying cros_network_config_ to
// avoid UaF errors.
network_config::OverrideInProcessInstanceForTesting(nullptr);
// Ordering here is based on dependencies between classes,
// CrosNetworkConfig depends on NetworkHandler and NetworkHandler
// indirectly depends on NetworkCertLoader.
network_health_provider_.reset();
cros_network_config_.reset();
network_handler_test_helper_.reset();
NetworkCertLoader::Shutdown();
scoped_user_manager_.reset();
SystemTokenCertDbStorage::Shutdown();
AshTestBase::TearDown();
}
protected:
void CreateEthernetDevice() {
network_handler_test_helper_->manager_test()->AddTechnology(
shill::kTypeEthernet, true);
network_handler_test_helper_->device_test()->AddDevice(
kEth0DevicePath, shill::kTypeEthernet, kEth0Name);
base::RunLoop().RunUntilIdle();
}
void CreateWifiDevice() {
network_handler_test_helper_->manager_test()->AddTechnology(
shill::kTypeWifi, true);
network_handler_test_helper_->device_test()->AddDevice(
kWlan0DevicePath, shill::kTypeWifi, kWlan0Name);
base::RunLoop().RunUntilIdle();
}
void AssociateIPConfigWithWifiDevice() {
network_handler_test_helper_->device_test()->SetDeviceProperty(
kWlan0DevicePath, shill::kSavedIPConfigProperty,
base::Value(kTestIPConfigPath),
/*notify_changed=*/true);
base::RunLoop().RunUntilIdle();
}
void CreateVpnDevice() {
network_handler_test_helper_->manager_test()->AddTechnology(shill::kTypeVPN,
true);
network_handler_test_helper_->device_test()->AddDevice(
"/device/vpn", shill::kTypeVPN, "vpn_name");
base::RunLoop().RunUntilIdle();
}
// The device must have been created with CreateEthernetDevice().
void AssociateEthernet() {
network_handler_test_helper_->service_test()->AddService(
kEth0DevicePath, kEth0NetworkGuid, kEth0Name, shill::kTypeEthernet,
shill::kStateAssociation, true);
base::RunLoop().RunUntilIdle();
}
void AssociateWifi() {
network_handler_test_helper_->service_test()->AddService(
kWlan0DevicePath, kWlan0NetworkGuid, kWlan0Name, shill::kTypeWifi,
shill::kStateAssociation, true);
base::RunLoop().RunUntilIdle();
}
void AssociateWifiWithIPConfig() {
network_handler_test_helper_->service_test()->AddServiceWithIPConfig(
kWlan0DevicePath, kWlan0NetworkGuid, kWlan0Name, shill::kTypeWifi,
shill::kStateAssociation, kTestIPConfigPath, true);
base::RunLoop().RunUntilIdle();
}
void AssociateAndConnectVpn() {
network_handler_test_helper_->service_test()->AddService(
"/device/vpn", "vpn guid", "vpn_name", shill::kTypeVPN,
shill::kStateAssociation, true);
SetNetworkState("/device/vpn", shill::kStateOnline);
base::RunLoop().RunUntilIdle();
}
void SetNetworkState(const std::string& device_path,
const std::string& state) {
network_handler_test_helper_->SetServiceProperty(
device_path, shill::kStateProperty, base::Value(state));
base::RunLoop().RunUntilIdle();
}
void SetEthernetConnected() {
// NOTE: `kStateReady` is connected but not "online".
SetNetworkState(kEth0DevicePath, shill::kStateReady);
}
void SetEthernetOnline() {
SetNetworkState(kEth0DevicePath, shill::kStateOnline);
}
void SetEthernetIdle() {
SetNetworkState(kEth0DevicePath, shill::kStateIdle);
}
void SetDeviceState(const std::string& type, bool enabled) {
NetworkTypePattern pattern = type == shill::kTypeEthernet
? NetworkTypePattern::Ethernet()
: NetworkTypePattern::WiFi();
NetworkHandler::Get()
->technology_state_controller()
->SetTechnologiesEnabled(pattern, enabled,
network_handler::ErrorCallback());
base::RunLoop().RunUntilIdle();
}
void SetEthernetDisabled() { SetDeviceState(shill::kTypeEthernet, false); }
void SetEthernetEnabled() { SetDeviceState(shill::kTypeEthernet, true); }
void SetWifiDisabled() { SetDeviceState(shill::kTypeWifi, false); }
void SetWifiEnabled() { SetDeviceState(shill::kTypeWifi, true); }
void SetWifiConnected() {
// NOTE: `kStateReady` is connected but not "online".
SetNetworkState(kWlan0DevicePath, shill::kStateReady);
}
void SetWifiOnline() {
SetNetworkState(kWlan0DevicePath, shill::kStateOnline);
}
void SetWifiIdle() { SetNetworkState(kWlan0DevicePath, shill::kStateIdle); }
void SetWifiPortal() {
SetNetworkState(kWlan0DevicePath, shill::kStateRedirectFound);
}
void SetCellularConnected() {
SetNetworkState(kCellular0DevicePath, shill::kStateReady);
}
void SetCellularIdle() {
SetNetworkState(kCellular0DevicePath, shill::kStateIdle);
}
void SetCellularOnline() {
SetNetworkState(kCellular0DevicePath, shill::kStateOnline);
}
void AssociateCellular() {
network_handler_test_helper_->service_test()->AddService(
kCellular0DevicePath, kCellular0NetworkGuid, kCellular0Name,
shill::kTypeCellular, shill::kStateAssociation, true);
network_handler_test_helper_->profile_test()->AddService(
NetworkProfileHandler::GetSharedProfilePath(), kCellular0DevicePath);
base::RunLoop().RunUntilIdle();
}
void CreateCellularDevice() {
network_handler_test_helper_->manager_test()->AddTechnology(
shill::kTypeCellular, true);
network_handler_test_helper_->device_test()->AddDevice(
kCellular0DevicePath, shill::kTypeCellular, kCellular0Name);
base::RunLoop().RunUntilIdle();
}
void SetCellularProperty(std::string property, base::ValueView value) {
network_handler_test_helper_->SetServiceProperty(kCellular0DevicePath,
property, value.ToValue());
base::RunLoop().RunUntilIdle();
}
void SetCellularIccid(std::string iccid) {
SetCellularProperty(shill::kIccidProperty, iccid);
}
void SetCellularNetworkTechnology(std::string technology) {
SetCellularProperty(shill::kNetworkTechnologyProperty, technology);
}
void SetCellularEid(std::string eid) {
SetCellularProperty(shill::kEidProperty, eid);
}
void SetCellularSignalStrength(int signal_strength) {
SetCellularProperty(shill::kSignalStrengthProperty, signal_strength);
}
void SetCellularSimLockStatus(std::string lock_type, bool sim_locked) {
base::Value::Dict sim_lock_status;
sim_lock_status.Set(shill::kSIMLockEnabledProperty, sim_locked);
sim_lock_status.Set(shill::kSIMLockTypeProperty, lock_type);
sim_lock_status.Set(shill::kSIMLockRetriesLeftProperty, 3);
network_handler_test_helper_->device_test()->SetDeviceProperty(
kCellular0DevicePath, shill::kSIMLockStatusProperty,
base::Value(std::move(sim_lock_status)),
/*notify_changed=*/true);
base::RunLoop().RunUntilIdle();
}
void SetCellularRoamingState(std::string roaming_state) {
SetCellularProperty(shill::kRoamingStateProperty, roaming_state);
}
void SetWifiProperty(std::string property, base::ValueView value) {
network_handler_test_helper_->SetServiceProperty(kWlan0DevicePath, property,
value.ToValue());
base::RunLoop().RunUntilIdle();
}
void SetWifiSignalStrength(int signal_strength) {
SetWifiProperty(shill::kSignalStrengthProperty, signal_strength);
}
void SetWifiFrequency(int frequency) {
SetWifiProperty(shill::kWifiFrequency, frequency);
}
void SetWifiBssid(std::string bssid) {
SetWifiProperty(shill::kWifiBSsid, bssid);
}
void SetEthernetMacAddress(const std::string& mac_address) {
network_handler_test_helper_->device_test()->SetDeviceProperty(
kEth0DevicePath, shill::kAddressProperty, base::Value(mac_address),
/*notify_changed=*/true);
base::RunLoop().RunUntilIdle();
}
void SetWifiMacAddress(const std::string& mac_address) {
network_handler_test_helper_->device_test()->SetDeviceProperty(
kWlan0DevicePath, shill::kAddressProperty, base::Value(mac_address),
/*notify_changed=*/true);
base::RunLoop().RunUntilIdle();
}
void SetGatewayForIPConfig(const std::string& gateway) {
ShillIPConfigClient::Get()->SetProperty(
dbus::ObjectPath(kTestIPConfigPath), shill::kGatewayProperty,
base::Value(gateway), base::DoNothing());
base::RunLoop().RunUntilIdle();
}
void SetIPAddressForIPConfig(const std::string& ip_address) {
ShillIPConfigClient::Get()->SetProperty(
dbus::ObjectPath(kTestIPConfigPath), shill::kAddressProperty,
base::Value(ip_address), base::DoNothing());
base::RunLoop().RunUntilIdle();
}
void SetNameServersForIPConfig(base::Value::List dns_servers) {
ShillIPConfigClient::Get()->SetProperty(
dbus::ObjectPath(kTestIPConfigPath), shill::kNameServersProperty,
base::Value(std::move(dns_servers)), base::DoNothing());
base::RunLoop().RunUntilIdle();
}
void SetRoutingPrefixForIPConfig(int routing_prefix) {
ShillIPConfigClient::Get()->SetProperty(
dbus::ObjectPath(kTestIPConfigPath), shill::kPrefixlenProperty,
base::Value(routing_prefix), base::DoNothing());
base::RunLoop().RunUntilIdle();
}
void SetWifiSecurity(const std::string& securityClass,
const std::string& eapKeyMgmt) {
SetWifiSecurity(securityClass);
SetWifiProperty(shill::kEapKeyMgmtProperty, eapKeyMgmt);
}
void SetWifiSecurity(const std::string& securityClass) {
SetWifiProperty(shill::kSecurityClassProperty, securityClass);
}
void SetupObserver(FakeNetworkListObserver* observer) {
network_health_provider_->ObserveNetworkList(observer->pending_remote());
base::RunLoop().RunUntilIdle();
}
void SetupObserver(FakeNetworkStateObserver* observer,
const std::string& observer_guid) {
network_health_provider_->ObserveNetwork(observer->pending_remote(),
observer_guid);
base::RunLoop().RunUntilIdle();
}
void ClearDevicesAndServices() {
// Clear test devices and services.
task_environment()->RunUntilIdle();
network_handler_test_helper_->ClearDevices();
network_handler_test_helper_->ClearServices();
task_environment()->RunUntilIdle();
}
mojom::IPConfigPropertiesPtr SetupRoutingPrefixToTestDataError(
int routing_prefix) {
// Observe the network list.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
// Create a wifi device.
CreateWifiDevice();
AssociateIPConfigWithWifiDevice();
const std::string guid = list_observer.observer_guids()[0];
// Observe the network.
FakeNetworkStateObserver observer;
SetupObserver(&observer, guid);
// Set IP Config properties.
SetRoutingPrefixForIPConfig(routing_prefix);
AssociateWifiWithIPConfig();
SetWifiOnline();
auto ip_config = observer.GetLatestState()->ip_config.Clone();
return ip_config;
}
sync_preferences::TestingPrefServiceSyncable user_prefs_;
TestingPrefServiceSimple local_state_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
std::unique_ptr<NetworkHandlerTestHelper> network_handler_test_helper_;
std::unique_ptr<network_config::CrosNetworkConfig> cros_network_config_;
std::unique_ptr<NetworkHealthProvider> network_health_provider_;
base::ScopedTempDir temp_dir_;
};
TEST_F(NetworkHealthProviderTest, ZeroNetworksAvailable) {
FakeNetworkListObserver observer;
SetupObserver(&observer);
size_t prior_call_count = 0;
ExpectListObserverFired(observer, &prior_call_count);
EXPECT_TRUE(observer.observer_guids().empty());
EXPECT_TRUE(observer.active_guid().empty());
}
TEST_F(NetworkHealthProviderTest, ObserveNonExistantNetwork) {
// Observe a guid that doesn't exist and nothing happens.
FakeNetworkStateObserver observer;
SetupObserver(&observer, "unknown_guid");
EXPECT_FALSE(observer.HasFired());
}
TEST_F(NetworkHealthProviderTest, UnsupportedNetworkTypeIgnored) {
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
// Create a VPN device, and it should not be visible to the observer.
CreateVpnDevice();
EXPECT_TRUE(list_observer.observer_guids().empty());
EXPECT_TRUE(list_observer.active_guid().empty());
// Associate and connect the VPN but it should still not be visible.
AssociateAndConnectVpn();
EXPECT_TRUE(list_observer.observer_guids().empty());
EXPECT_TRUE(list_observer.active_guid().empty());
// Create an ethernet device and verify that the observer list added the
// network.
CreateEthernetDevice();
ExpectListObserverFired(list_observer, &list_call_count);
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string guid = list_observer.observer_guids()[0];
ASSERT_FALSE(guid.empty());
// Observe the guid and verify that it's the ethernet.
FakeNetworkStateObserver eth_observer;
SetupObserver(ð_observer, guid);
EXPECT_EQ(eth_observer.GetLatestState()->type, mojom::NetworkType::kEthernet);
}
// Test the setup and all intermediate states for ethernet network.
TEST_F(NetworkHealthProviderTest, SetupEthernetNetwork) {
// Observe the network list.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
// No networks are present and no active network.
ASSERT_EQ(0u, list_observer.observer_guids().size());
EXPECT_TRUE(list_observer.active_guid().empty());
// Create an ethernet device and verify `list_observer` fired.
CreateEthernetDevice();
ExpectListObserverFired(list_observer, &list_call_count);
// Verify a new network is created, but there is no active guid because
// the network isn't connected.
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string observer_guid = list_observer.observer_guids()[0];
EXPECT_FALSE(observer_guid.empty());
EXPECT_TRUE(list_observer.active_guid().empty());
// Observe the network and verify the observer fired.
FakeNetworkStateObserver observer;
SetupObserver(&observer, observer_guid);
size_t state_call_count = 0;
ExpectStateObserverFired(observer, &state_call_count);
// Get latest state and verify ethernet in not connected state.
EXPECT_EQ(observer.GetLatestState()->observer_guid, observer_guid);
EXPECT_EQ(observer.GetLatestState()->type, mojom::NetworkType::kEthernet);
EXPECT_EQ(observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
EXPECT_EQ(observer.GetLatestState()->type_properties.get(), nullptr);
// Put the ethernet device into the connecting/associating state and verify
// the new state and there is still no active guid.
AssociateEthernet();
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kConnecting);
EXPECT_TRUE(list_observer.active_guid().empty());
// Put ethernet into connected (but not online) state. It's guid should now
// be the active one.
SetEthernetConnected();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kConnected);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// Verify ethernet authentication is none for non-EAP Ethernet.
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_ethernet()
->authentication,
mojom::AuthenticationType::kNone);
// TODO(ashleydp): Add test for authentication k8021x when fake shill service
// can support and required configuration is known.
// Put ethernet into online state. It's guid should remain active.
SetEthernetOnline();
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// Simulate unplug and network goes back to kNotConnected, and the active
// guid should be cleared.
SetEthernetIdle();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
EXPECT_TRUE(list_observer.active_guid().empty());
// Simulate plug in and back to online state. The active guid should be set.
SetEthernetOnline();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// AFter disabling ethernet, verify network state is kNotConnected and device
// state is kDisabled.
SetEthernetDisabled();
EXPECT_TRUE(list_observer.active_guid().empty());
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kDisabled);
// Enable ethernet and verify that it's guid becomes active again.
SetEthernetEnabled();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
}
// Test the setup and all intermediate states for ethernet network.
TEST_F(NetworkHealthProviderTest, SetupWifiNetwork) {
// Observe the network list.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
// No networks are present and no active network.
ASSERT_EQ(0u, list_observer.observer_guids().size());
EXPECT_TRUE(list_observer.active_guid().empty());
// Create a wifi device and verify `list_observer` fired.
CreateWifiDevice();
ExpectListObserverFired(list_observer, &list_call_count);
// Verify a new network is created, but there is no active guid because
// the network isn't connected.
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string observer_guid = list_observer.observer_guids()[0];
EXPECT_FALSE(observer_guid.empty());
EXPECT_TRUE(list_observer.active_guid().empty());
// Observe the network and verify the observer fired.
FakeNetworkStateObserver observer;
SetupObserver(&observer, observer_guid);
size_t state_call_count = 0;
ExpectStateObserverFired(observer, &state_call_count);
// Get latest state and verify wifi in not connected state.
EXPECT_EQ(observer.GetLatestState()->observer_guid, observer_guid);
EXPECT_EQ(observer.GetLatestState()->type, mojom::NetworkType::kWiFi);
EXPECT_EQ(observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
EXPECT_EQ(observer.GetLatestState()->type_properties.get(), nullptr);
// Put the wifi device into the connecting/associating state and verify
// the new state and there is still no active guid.
AssociateWifi();
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kConnecting);
EXPECT_TRUE(list_observer.active_guid().empty());
// Put wifi into connected (but not online) state. It's guid should now
// be the active one.
SetWifiConnected();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kConnected);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// TODO(michaelcheco): Verify encryption properties once added to the API.
// Put wifi into online state. It's guid should remain active.
SetWifiOnline();
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// Simulate disconnect and network goes back to kNotConnected, and the
// active guid should be cleared.
SetWifiIdle();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
EXPECT_TRUE(list_observer.active_guid().empty());
// Simulate reconnect and back to online state. The active guid should be
// set.
SetWifiOnline();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// AFter disabling wifi, verify network state is kNotConnected and device
// state is kDisabled.
SetWifiDisabled();
EXPECT_TRUE(list_observer.active_guid().empty());
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kDisabled);
// Enable wifi and verify that it's guid becomes active again.
SetWifiEnabled();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
}
// Test the setup and all intermediate states for cellular network.
TEST_F(NetworkHealthProviderTest, SetupCellularNetwork) {
// Observe the network list.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
// No networks are present and no active network.
ASSERT_EQ(0u, list_observer.observer_guids().size());
EXPECT_TRUE(list_observer.active_guid().empty());
// Create a cellular device and verify `list_observer` fired.
CreateCellularDevice();
ExpectListObserverFired(list_observer, &list_call_count);
// Verify a new network is created, but there is no active guid because
// the network isn't connected.
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string observer_guid = list_observer.observer_guids()[0];
EXPECT_FALSE(observer_guid.empty());
EXPECT_TRUE(list_observer.active_guid().empty());
// Observe the network and verify the observer fired.
FakeNetworkStateObserver observer;
SetupObserver(&observer, observer_guid);
size_t state_call_count = 0;
ExpectStateObserverFired(observer, &state_call_count);
// Get latest state and verify wifi in not connected state.
EXPECT_EQ(observer.GetLatestState()->observer_guid, observer_guid);
EXPECT_EQ(observer.GetLatestState()->type, mojom::NetworkType::kCellular);
EXPECT_EQ(observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
// Put the cellular device into the connecting/associating state and verify
// the new state and there is still no active guid.
AssociateCellular();
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kConnecting);
EXPECT_TRUE(list_observer.active_guid().empty());
// Put cellular into connected (but not online) state. It's guid should now
// be the active one.
SetCellularConnected();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kConnected);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// Put cellular into online state. It's guid should remain active.
SetCellularOnline();
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
// Simulate disconnect and network goes back to kNotConnected, and the
// active guid should be cleared.
SetCellularIdle();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
EXPECT_TRUE(list_observer.active_guid().empty());
// Simulate reconnect and back to online state. The active guid should be
// set.
SetCellularOnline();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(observer_guid, list_observer.active_guid());
}
// Test modifying wifi properties
TEST_F(NetworkHealthProviderTest, ChangingWifiProperties) {
// Create a wifi device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateWifiDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string guid = list_observer.observer_guids()[0];
// Put wifi online and validate it is active.
FakeNetworkStateObserver observer;
SetupObserver(&observer, guid);
AssociateWifi();
SetWifiOnline();
size_t state_call_count = 0;
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(guid, list_observer.active_guid());
// Set signal strength.
const int signal_strength_1 = 40;
SetWifiSignalStrength(signal_strength_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_wifi()->signal_strength,
signal_strength_1);
// Change the signal strength.
const int signal_strength_2 = 55;
SetWifiSignalStrength(signal_strength_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_wifi()->signal_strength,
signal_strength_2);
// Set BSSID.
const std::string bssid_1("01:23:cd:67:89:ab");
const std::string bssid_formatted_1("01:23:CD:67:89:AB");
SetWifiBssid(bssid_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->bssid,
bssid_formatted_1);
// Change BSSID.
const std::string bssid_2("01:aa:45:67:89:ab");
const std::string bssid_formatted_2("01:AA:45:67:89:AB");
SetWifiBssid(bssid_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->bssid,
bssid_formatted_2);
// Set frequency.
const int frequency_1 = 2400;
SetWifiFrequency(frequency_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->frequency,
frequency_1);
// Change frequency.
const int frequency_2 = 2450;
SetWifiFrequency(frequency_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->frequency,
frequency_2);
// By default security should be NONE.
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kNone);
// Enable security as WEP_8021x.
mojom::SecurityType security_2 = mojom::SecurityType::kWep8021x;
SetWifiSecurity(shill::kSecurityClassWep, shill::kKeyManagementIEEE8021X);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
security_2);
// Verify all properties are still set.
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_wifi()->signal_strength,
signal_strength_2);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->bssid,
bssid_formatted_2);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->frequency,
frequency_2);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
security_2);
}
// Test modifying cellular properties
TEST_F(NetworkHealthProviderTest, ChangingCellularProperties) {
// Create a cellular device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateCellularDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string guid = list_observer.observer_guids()[0];
// Put cellular online and validate it is active.
FakeNetworkStateObserver observer;
SetupObserver(&observer, guid);
AssociateCellular();
SetCellularOnline();
size_t state_call_count = 0;
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(guid, list_observer.active_guid());
// Set iccid.
const std::string iccid_1 = "1234567890";
SetCellularIccid(iccid_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_cellular()->iccid,
iccid_1);
// Change the iccid.
const std::string iccid_2 = "0987654321";
SetCellularIccid(iccid_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_cellular()->iccid,
iccid_2);
// Set network_technology.
const std::string network_technology_1 = shill::kNetworkTechnologyEdge;
SetCellularNetworkTechnology(network_technology_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_cellular()
->network_technology,
network_technology_1);
// Change the network_technology.
const std::string network_technology_2 = shill::kNetworkTechnologyLte;
SetCellularNetworkTechnology(network_technology_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_cellular()
->network_technology,
network_technology_2);
// Set eid.
const std::string eid_1 = "03928509238502395213124";
SetCellularEid(eid_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_cellular()->eid,
eid_1);
// Change the eid.
const std::string eid_2 = "89012375908213750982315";
SetCellularEid(eid_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_cellular()->eid,
eid_2);
// Set signal strength.
const int signal_strength_1 = 40;
SetCellularSignalStrength(signal_strength_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_cellular()
->signal_strength,
signal_strength_1);
// Change the signal strength.
const int signal_strength_2 = 55;
SetCellularSignalStrength(signal_strength_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_cellular()
->signal_strength,
signal_strength_2);
// Set roaming state.
const std::string roaming_state_1 = shill::kRoamingStateHome;
SetCellularRoamingState(roaming_state_1);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->roaming_state,
mojom::RoamingState::kHome);
// Change roaming state.
const std::string roaming_state_2 = shill::kRoamingStateRoaming;
SetCellularRoamingState(roaming_state_2);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->roaming_state,
mojom::RoamingState::kRoaming);
SetCellularSimLockStatus(shill::kSIMLockPin, /**sim_locked=*/true);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->lock_type,
mojom::LockType::kSimPin);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->sim_locked,
true);
SetCellularSimLockStatus(shill::kSIMLockNetworkPin, /**sim_locked=*/true);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
mojom::LockType::kNetworkPin,
observer.GetLatestState()->type_properties->get_cellular()->lock_type);
EXPECT_EQ(
true,
observer.GetLatestState()->type_properties->get_cellular()->sim_locked);
SetCellularSimLockStatus(/**lock_type=*/"", /**sim_locked=*/false);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->lock_type,
mojom::LockType::kNone);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->sim_locked,
false);
// Verify all properties are still set.
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_cellular()
->signal_strength,
signal_strength_2);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_cellular()->iccid,
iccid_2);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_cellular()->eid,
eid_2);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->roaming_state,
mojom::RoamingState::kRoaming);
EXPECT_EQ(observer.GetLatestState()
->type_properties->get_cellular()
->network_technology,
network_technology_2);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->lock_type,
mojom::LockType::kNone);
EXPECT_EQ(
observer.GetLatestState()->type_properties->get_cellular()->sim_locked,
false);
}
// Start with an online ethernet connection and validate the interaction
// with a newly added wifi network.
TEST_F(NetworkHealthProviderTest, EthernetOnlineThenConnectWifi) {
// Create an ethernet device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateEthernetDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string eth_guid = list_observer.observer_guids()[0];
// Put ethernet online and validate it is active.
FakeNetworkStateObserver eth_observer;
SetupObserver(ð_observer, eth_guid);
AssociateEthernet();
SetEthernetOnline();
size_t state_call_count = 0;
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(eth_observer, &state_call_count);
EXPECT_EQ(eth_observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.active_guid());
// Create Wifi device and verify it was added to the network list. The
// ethernet network should remain active.
CreateWifiDevice();
ExpectListObserverFired(list_observer, &list_call_count);
ASSERT_EQ(2u, list_observer.observer_guids().size());
const std::string wifi_guid = (list_observer.observer_guids()[0] == eth_guid)
? list_observer.observer_guids()[1]
: list_observer.observer_guids()[0];
ASSERT_NE(eth_guid, wifi_guid);
EXPECT_FALSE(list_observer.active_guid().empty());
ASSERT_EQ(eth_guid, list_observer.active_guid());
// Observe and associate the Wifi network. The wifi network should be in
// the connecting state, and the active guid should still be ethernet.
FakeNetworkStateObserver wifi_observer;
SetupObserver(&wifi_observer, wifi_guid);
AssociateWifi();
state_call_count = 0;
ExpectStateObserverFired(wifi_observer, &state_call_count);
EXPECT_EQ(wifi_observer.GetLatestState()->state,
mojom::NetworkState::kConnecting);
EXPECT_EQ(eth_guid, list_observer.active_guid());
// Put wifi network online. With both networks online, the ethernet should
// still remain the active network.
SetWifiOnline();
ExpectStateObserverFired(wifi_observer, &state_call_count);
EXPECT_EQ(wifi_observer.GetLatestState()->state,
mojom::NetworkState::kOnline);
EXPECT_EQ(eth_guid, list_observer.active_guid());
// Disconnect ethernet and wifi should become the active network.
SetEthernetIdle();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(eth_observer, &state_call_count);
EXPECT_EQ(eth_observer.GetLatestState()->state,
mojom::NetworkState::kNotConnected);
EXPECT_EQ(wifi_observer.GetLatestState()->state,
mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
ASSERT_EQ(wifi_guid, list_observer.active_guid());
// Reconnect ethernet and it becomes the active network again.
SetEthernetOnline();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(eth_observer, &state_call_count);
EXPECT_EQ(eth_observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_EQ(wifi_observer.GetLatestState()->state,
mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
ASSERT_EQ(eth_guid, list_observer.active_guid());
}
TEST_F(NetworkHealthProviderTest, SetupEthernetNetworkWithMacAddress) {
// Create an ethernet device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateEthernetDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string eth_guid = list_observer.observer_guids()[0];
// Put ethernet online and validate it is active.
FakeNetworkStateObserver eth_observer;
SetupObserver(ð_observer, eth_guid);
AssociateEthernet();
SetEthernetOnline();
size_t eth_state_call_count = 0;
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(eth_observer, ð_state_call_count);
EXPECT_EQ(eth_observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.active_guid());
SetEthernetMacAddress(kFormattedMacAddress);
ExpectStateObserverFired(eth_observer, ð_state_call_count);
EXPECT_EQ(eth_observer.GetLatestState()->mac_address, kFormattedMacAddress);
}
TEST_F(NetworkHealthProviderTest, SetupWifiNetworkWithMacAddress) {
// Create a wifi device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateWifiDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string guid = list_observer.observer_guids()[0];
size_t state_call_count = 0;
size_t list_call_count = 0;
// Put wifi online and validate it is active.
FakeNetworkStateObserver observer;
SetupObserver(&observer, guid);
AssociateWifi();
SetWifiOnline();
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(guid, list_observer.active_guid());
SetWifiMacAddress(kFormattedMacAddress);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->mac_address, kFormattedMacAddress);
}
TEST_F(NetworkHealthProviderTest, IPConfig) {
// Observe the network list.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
size_t list_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
// No networks are present and no active network.
ASSERT_EQ(0u, list_observer.observer_guids().size());
EXPECT_TRUE(list_observer.active_guid().empty());
// Create a wifi device and verify `list_observer` fired.
CreateWifiDevice();
AssociateIPConfigWithWifiDevice();
ExpectListObserverFired(list_observer, &list_call_count);
// Verify a new network is created, but there is no active guid because
// the network isn't connected.
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string guid = list_observer.observer_guids()[0];
EXPECT_FALSE(guid.empty());
EXPECT_TRUE(list_observer.active_guid().empty());
// Observe the network and verify the observer fired.
FakeNetworkStateObserver observer;
SetupObserver(&observer, guid);
// Set IP Config properties.
const std::string gateway("192.0.0.1");
SetGatewayForIPConfig(gateway);
const std::string ip_address("192.168.1.1");
SetIPAddressForIPConfig(ip_address);
const int routing_prefix = 1;
SetRoutingPrefixForIPConfig(routing_prefix);
base::Value::List dns_servers;
const std::string dns_server_1 = "192.168.1.100";
const std::string dns_server_2 = "192.168.1.101";
dns_servers.Append(dns_server_1);
dns_servers.Append(dns_server_2);
SetNameServersForIPConfig(std::move(dns_servers));
AssociateWifiWithIPConfig();
SetWifiOnline();
list_call_count = 0;
size_t state_call_count = 0;
ExpectListObserverFired(list_observer, &list_call_count);
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(guid, list_observer.active_guid());
auto ip_config = observer.GetLatestState()->ip_config.Clone();
EXPECT_EQ(ip_config->gateway.value(), gateway);
EXPECT_EQ(ip_config->routing_prefix, routing_prefix);
EXPECT_EQ(ip_config->ip_address.value(), ip_address);
auto name_servers = ip_config->name_servers.value();
EXPECT_EQ(name_servers.size(), 2U);
EXPECT_EQ(name_servers[0], dns_server_1);
EXPECT_EQ(name_servers[1], dns_server_2);
}
TEST_F(NetworkHealthProviderTest, IPConfigRoutingPrefixExpectationNotMet) {
base::HistogramTester histogram_tester;
VerifyNetworkDataErrorBucketCounts(histogram_tester,
/*expected_no_data_error=*/0,
/*expected_not_a_number_error=*/0,
/*expected_expectation_not_met_error=*/0);
auto ip_config = SetupRoutingPrefixToTestDataError(33);
// routing_prefix should be default to 0.
EXPECT_EQ(ip_config->routing_prefix, 0);
VerifyNetworkDataErrorBucketCounts(histogram_tester,
/*expected_no_data_error=*/0,
/*expected_not_a_number_error=*/0,
kExpectationNotMetErrorCount);
}
TEST_F(NetworkHealthProviderTest,
IPConfigRoutingPrefixExpectationNotMetAsNegative) {
base::HistogramTester histogram_tester;
VerifyNetworkDataErrorBucketCounts(histogram_tester,
/*expected_no_data_error=*/0,
/*expected_not_a_number_error=*/0,
/*expected_expectation_not_met_error=*/0);
auto ip_config = SetupRoutingPrefixToTestDataError(-1);
// routing_prefix should be default to 0.
EXPECT_EQ(ip_config->routing_prefix, 0);
VerifyNetworkDataErrorBucketCounts(histogram_tester,
/*expected_no_data_error=*/0,
/*expected_not_a_number_error=*/0,
kExpectationNotMetErrorCount);
}
TEST_F(NetworkHealthProviderTest, SetupWifiNetworkWithSecurity) {
// Create a wifi device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateWifiDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string guid = list_observer.observer_guids()[0];
size_t state_call_count = 0;
size_t list_call_count = 0;
// Put wifi online and validate it is active.
FakeNetworkStateObserver observer;
SetupObserver(&observer, guid);
AssociateWifi();
SetWifiOnline();
ExpectListObserverFired(list_observer,
/*prior_call_count=*/&list_call_count);
EXPECT_EQ(observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(guid, list_observer.active_guid());
// By default security should be NONE.
ExpectStateObserverFired(observer, &state_call_count);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kNone);
// Enable security as WEP_8021x.
SetWifiSecurity(shill::kSecurityClassWep, shill::kKeyManagementIEEE8021X);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kWep8021x);
ExpectStateObserverFired(observer, &state_call_count);
// Enable security as WEP_PSK.
SetWifiSecurity(shill::kSecurityClassWep, std::string());
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kWepPsk);
ExpectStateObserverFired(observer, &state_call_count);
// Enable security as WPA_EAP.
SetWifiSecurity(shill::kSecurityClass8021x);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kWpaEap);
ExpectStateObserverFired(observer, &state_call_count);
// Enable security as WPA_PSK.
SetWifiSecurity(shill::kSecurityClassPsk);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kWpaPsk);
ExpectStateObserverFired(observer, &state_call_count);
// Enable security as NONE.
SetWifiSecurity(shill::kSecurityClassNone);
EXPECT_EQ(observer.GetLatestState()->type_properties->get_wifi()->security,
mojom::SecurityType::kNone);
ExpectStateObserverFired(observer, &state_call_count);
}
// Verifies that the list of observer guids and the active guid are set
// properly through various state transitions.
TEST_F(NetworkHealthProviderTest, EthernetAndWifiOrderedCorrectly) {
// Create an ethernet device.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
CreateEthernetDevice();
ASSERT_EQ(1u, list_observer.observer_guids().size());
const std::string eth_guid = list_observer.observer_guids()[0];
// Put ethernet online and validate it is active.
FakeNetworkStateObserver eth_observer;
SetupObserver(ð_observer, eth_guid);
AssociateEthernet();
SetEthernetOnline();
EXPECT_EQ(eth_observer.GetLatestState()->state, mojom::NetworkState::kOnline);
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.active_guid());
CreateWifiDevice();
const std::string wifi_guid = list_observer.observer_guids()[1];
FakeNetworkStateObserver wifi_observer;
SetupObserver(&wifi_observer, wifi_guid);
AssociateWifi();
// Ethernet should still be active and WiFi guid should be second in list of
// observer guids.
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.active_guid());
EXPECT_EQ(wifi_guid, list_observer.observer_guids()[1]);
// Ethernet should remain active, despite WiFi also being online.
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.active_guid());
EXPECT_EQ(wifi_guid, list_observer.observer_guids()[1]);
SetWifiOnline();
// Now that Ethernet is disconnected, WiFi should be active and Ethernet
// should be the second guid in the list of observer guids.
SetEthernetIdle();
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(wifi_guid, list_observer.active_guid());
EXPECT_EQ(eth_guid, list_observer.observer_guids()[1]);
// With both Ethernet and WiFi disconnected, neither of them should be
// active and the Ethernet guid should be the first observer guid.
SetWifiIdle();
EXPECT_TRUE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.observer_guids()[0]);
EXPECT_EQ(wifi_guid, list_observer.observer_guids()[1]);
// With WiFi in a portal state, it should be the active guid and
// Ethernet should be the second guid in the list of observer guids.
SetWifiPortal();
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(wifi_guid, list_observer.active_guid());
EXPECT_EQ(eth_guid, list_observer.observer_guids()[1]);
// With Ethernet online and WiFi in a portal state, Ethernet should
// be the active guid and WiFi should be the second guid in the list
// of observer guids.
SetEthernetOnline();
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(eth_guid, list_observer.active_guid());
EXPECT_EQ(wifi_guid, list_observer.observer_guids()[1]);
// With Ethernet connected and WiFi in a portal state, WiFi should
// be the active guid and Ethernet should be the second guid in the list
// of observer guids.
SetEthernetConnected();
EXPECT_FALSE(list_observer.active_guid().empty());
EXPECT_EQ(wifi_guid, list_observer.active_guid());
EXPECT_EQ(eth_guid, list_observer.observer_guids()[1]);
}
TEST_F(NetworkHealthProviderTest, NetworkingLog) {
DiagnosticsLogController::Get()->SetNetworkingLogForTesting(
std::make_unique<NetworkingLog>(temp_dir_.GetPath()));
size_t list_call_count = 0;
// Observe the network list.
FakeNetworkListObserver list_observer;
SetupObserver(&list_observer);
// Create a wifi device and verify `list_observer` fired.
CreateWifiDevice();
// Observe the network and verify the observer fired.
FakeNetworkStateObserver observer;
SetupObserver(&observer, list_observer.observer_guids()[0]);
AssociateWifi();
ExpectListObserverFired(list_observer, &list_call_count);
// List Oberver is fired but UpdateNetworkList() is not called because
// active_guid_ is empty.
EXPECT_EQ(0u, DiagnosticsLogController::Get()
->GetNetworkingLog()
.update_network_list_call_count_for_testing());
EXPECT_TRUE(list_observer.active_guid().empty());
// The non-active network still appears in the log.
EXPECT_FALSE(DiagnosticsLogController::Get()
->GetNetworkingLog()
.GetNetworkInfo()
.empty());
// Put wifi into online state.
SetWifiOnline();
// Log is populated with network info now that WiFi is online.
// Log contents tested in networking_log_unittest.cc -
// NetworkingLogTest.DetailedLogContentsWiFi.
EXPECT_FALSE(DiagnosticsLogController::Get()
->GetNetworkingLog()
.GetNetworkInfo()
.empty());
// List Oberver is fired and UpdateNetworkList() is called because
// active_guid_ is not empty.
ExpectListObserverFired(list_observer, &list_call_count);
EXPECT_GE(DiagnosticsLogController::Get()
->GetNetworkingLog()
.update_network_list_call_count_for_testing(),
0u);
EXPECT_FALSE(list_observer.active_guid().empty());
}
TEST_F(NetworkHealthProviderTest, ResetReceiverOnBindInterface) {
// This test simulates a user refreshing the WebUI page. The receiver should
// be reset before binding the new receiver. Otherwise we would get a DCHECK
// error from mojo::Receiver
mojo::Remote<mojom::NetworkHealthProvider> remote;
network_health_provider_->BindInterface(remote.BindNewPipeAndPassReceiver());
base::RunLoop().RunUntilIdle();
remote.reset();
network_health_provider_->BindInterface(remote.BindNewPipeAndPassReceiver());
base::RunLoop().RunUntilIdle();
}
} // namespace ash::diagnostics