blob: 7ed4079467693c73af56aa4dacf9dab3aebb2e08 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/network/metrics/hotspot_metrics_helper.h"
#include "ash/constants/ash_features.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chromeos/ash/components/dbus/shill/shill_clients.h"
#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#include "chromeos/ash/components/network/enterprise_managed_metadata_store.h"
#include "chromeos/ash/components/network/hotspot_allowed_flag_handler.h"
#include "chromeos/ash/components/network/hotspot_capabilities_provider.h"
#include "chromeos/ash/components/network/hotspot_configuration_handler.h"
#include "chromeos/ash/components/network/hotspot_controller.h"
#include "chromeos/ash/components/network/hotspot_enabled_state_notifier.h"
#include "chromeos/ash/components/network/hotspot_state_handler.h"
#include "chromeos/ash/components/network/metrics/hotspot_feature_usage_metrics.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power/power_policy_controller.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
const char kCellularServicePath[] = "/service/cellular0";
const char kCellularServiceGuid[] = "cellular_guid0";
const char kCellularServiceName[] = "cellular_name0";
} // namespace
class HotspotMetricsHelperTest : public testing::Test {
public:
HotspotMetricsHelperTest() = default;
HotspotMetricsHelperTest(const HotspotMetricsHelperTest&) = delete;
HotspotMetricsHelperTest& operator=(const HotspotMetricsHelperTest&) = delete;
~HotspotMetricsHelperTest() override = default;
void SetUp() override {
LoginState::Initialize();
chromeos::PowerManagerClient::InitializeFake();
chromeos::PowerPolicyController::Initialize(
chromeos::FakePowerManagerClient::Get());
enterprise_managed_metadata_store_ =
std::make_unique<EnterpriseManagedMetadataStore>();
hotspot_capabilities_provider_ =
std::make_unique<HotspotCapabilitiesProvider>();
hotspot_allowed_flag_handler_ =
std::make_unique<HotspotAllowedFlagHandler>();
hotspot_capabilities_provider_->Init(
network_state_test_helper_.network_state_handler(),
hotspot_allowed_flag_handler_.get());
hotspot_feature_usage_metrics_ =
std::make_unique<HotspotFeatureUsageMetrics>();
hotspot_feature_usage_metrics_->Init(
enterprise_managed_metadata_store_.get(),
hotspot_capabilities_provider_.get());
technology_state_controller_ =
std::make_unique<TechnologyStateController>();
technology_state_controller_->Init(
network_state_test_helper_.network_state_handler());
hotspot_state_handler_ = std::make_unique<HotspotStateHandler>();
hotspot_state_handler_->Init();
hotspot_controller_ = std::make_unique<HotspotController>();
hotspot_controller_->Init(hotspot_capabilities_provider_.get(),
hotspot_feature_usage_metrics_.get(),
hotspot_state_handler_.get(),
technology_state_controller_.get());
hotspot_configuration_handler_ =
std::make_unique<HotspotConfigurationHandler>();
hotspot_configuration_handler_->Init();
hotspot_enabled_state_notifier_ =
std::make_unique<HotspotEnabledStateNotifier>();
hotspot_enabled_state_notifier_->Init(hotspot_state_handler_.get(),
hotspot_controller_.get());
hotspot_metrics_helper_ = std::make_unique<HotspotMetricsHelper>();
hotspot_metrics_helper_->Init(
enterprise_managed_metadata_store_.get(),
hotspot_capabilities_provider_.get(), hotspot_state_handler_.get(),
hotspot_controller_.get(), hotspot_configuration_handler_.get(),
hotspot_enabled_state_notifier_.get(),
network_state_test_helper_.network_state_handler());
base::RunLoop().RunUntilIdle();
}
void PrepareEnableHotspotForTesting() {
SetHotspotStateInShill(shill::kTetheringStateIdle);
SetHotspotAllowStatus(hotspot_config::mojom::HotspotAllowStatus::kAllowed);
network_state_test_helper_.manager_test()
->SetSimulateCheckTetheringReadinessResult(
FakeShillSimulatedResult::kSuccess,
shill::kTetheringReadinessReady);
network_state_test_helper_.manager_test()->SetSimulateTetheringEnableResult(
FakeShillSimulatedResult::kSuccess,
shill::kTetheringEnableResultSuccess);
}
void SetHotspotAllowStatus(
hotspot_config::mojom::HotspotAllowStatus allow_status) {
hotspot_capabilities_provider_->SetHotspotAllowStatus(allow_status);
}
void SetHotspotStateInShill(const std::string& hotspot_state) {
auto status_dict = base::Value::Dict().Set(
shill::kTetheringStatusStateProperty, hotspot_state);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(std::move(status_dict)));
base::RunLoop().RunUntilIdle();
}
void TearDown() override {
network_state_test_helper_.ClearDevices();
network_state_test_helper_.ClearServices();
hotspot_enabled_state_notifier_.reset();
hotspot_metrics_helper_.reset();
hotspot_configuration_handler_.reset();
hotspot_controller_.reset();
hotspot_feature_usage_metrics_.reset();
hotspot_capabilities_provider_.reset();
hotspot_allowed_flag_handler_.reset();
hotspot_state_handler_.reset();
technology_state_controller_.reset();
enterprise_managed_metadata_store_.reset();
LoginState::Shutdown();
}
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::HistogramTester histogram_tester_;
NetworkStateTestHelper network_state_test_helper_{
/*use_default_devices_and_services=*/false};
std::unique_ptr<EnterpriseManagedMetadataStore>
enterprise_managed_metadata_store_;
std::unique_ptr<HotspotAllowedFlagHandler> hotspot_allowed_flag_handler_;
std::unique_ptr<HotspotCapabilitiesProvider> hotspot_capabilities_provider_;
std::unique_ptr<HotspotStateHandler> hotspot_state_handler_;
std::unique_ptr<HotspotFeatureUsageMetrics> hotspot_feature_usage_metrics_;
std::unique_ptr<TechnologyStateController> technology_state_controller_;
std::unique_ptr<HotspotController> hotspot_controller_;
std::unique_ptr<HotspotConfigurationHandler> hotspot_configuration_handler_;
std::unique_ptr<HotspotEnabledStateNotifier> hotspot_enabled_state_notifier_;
std::unique_ptr<HotspotMetricsHelper> hotspot_metrics_helper_;
};
TEST_F(HotspotMetricsHelperTest, HotspotAllowStatusHistogram) {
using hotspot_config::mojom::HotspotAllowStatus;
LoginState::Get()->SetLoggedInState(
LoginState::LoggedInState::LOGGED_IN_ACTIVE,
LoginState::LoggedInUserType::LOGGED_IN_USER_OWNER);
SetHotspotAllowStatus(
hotspot_config::mojom::HotspotAllowStatus::kDisallowedNoMobileData);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotAllowStatusHistogram, 2);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotAllowStatusHistogram,
HotspotMetricsHelper::HotspotMetricsAllowStatus::kDisallowedNoMobileData,
2);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotAllowStatusAtLoginHistogram, 0);
task_environment_.FastForwardBy(
HotspotMetricsHelper::kLogAllowStatusAtLoginTimeout);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotAllowStatusHistogram, 2);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotAllowStatusAtLoginHistogram, 1);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotAllowStatusAtLoginHistogram,
HotspotMetricsHelper::HotspotMetricsAllowStatus::kDisallowedNoMobileData,
1);
SetHotspotAllowStatus(hotspot_config::mojom::HotspotAllowStatus::kAllowed);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotAllowStatusHistogram, 3);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotAllowStatusHistogram,
HotspotMetricsHelper::HotspotMetricsAllowStatus::kAllowed, 1);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotAllowStatusAtLoginHistogram, 1);
}
TEST_F(HotspotMetricsHelperTest, HotspotUsageConfigHistogram) {
LoginState::Get()->SetLoggedInState(
LoginState::LoggedInState::LOGGED_IN_ACTIVE,
LoginState::LoggedInUserType::LOGGED_IN_USER_OWNER);
auto mojom_config = hotspot_config::mojom::HotspotConfig::New();
mojom_config->auto_disable = true;
mojom_config->band = hotspot_config::mojom::WiFiBand::kAutoChoose;
mojom_config->ssid = "test_ssid";
mojom_config->passphrase = "test_password";
mojom_config->bssid_randomization = true;
hotspot_configuration_handler_->SetHotspotConfig(std::move(mojom_config),
base::DoNothing());
base::RunLoop().RunUntilIdle();
PrepareEnableHotspotForTesting();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotUsageConfigAutoDisable, 1);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotUsageConfigAutoDisable, true, 1);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotUsageConfigMAR, 1);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotUsageConfigMAR, true, 1);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotUsageConfigCompatibilityMode, 1);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotUsageConfigCompatibilityMode, false, 1);
}
TEST_F(HotspotMetricsHelperTest, HotspotUsageDurationHistogram) {
const base::TimeDelta kHotspotUsageTime = base::Seconds(123);
PrepareEnableHotspotForTesting();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
task_environment_.FastForwardBy(kHotspotUsageTime);
SetHotspotStateInShill(shill::kTetheringStateActive);
hotspot_controller_->DisableHotspot(
base::DoNothing(), hotspot_config::mojom::DisableReason::kUserInitiated);
SetHotspotStateInShill(shill::kTetheringStateIdle);
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectTimeBucketCount(
HotspotMetricsHelper::kHotspotUsageDuration, kHotspotUsageTime, 1);
// Verifies that the usage duration is logged if hotspot is torn down by
// internal error.
hotspot_controller_->EnableHotspot(base::DoNothing());
SetHotspotStateInShill(shill::kTetheringStateActive);
base::RunLoop().RunUntilIdle();
task_environment_.FastForwardBy(kHotspotUsageTime);
auto status_dict =
base::Value::Dict()
.Set(shill::kTetheringStatusStateProperty, shill::kTetheringStateIdle)
.Set(shill::kTetheringStatusIdleReasonProperty,
shill::kTetheringIdleReasonError);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(std::move(status_dict)));
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectTimeBucketCount(
HotspotMetricsHelper::kHotspotUsageDuration, kHotspotUsageTime, 2);
}
TEST_F(HotspotMetricsHelperTest, HotspotMaxClientCountHistogram) {
PrepareEnableHotspotForTesting();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
base::Value::Dict status_dict;
status_dict.Set(shill::kTetheringStatusStateProperty,
shill::kTetheringStateActive);
// Update tethering status with one active client.
base::Value::List active_clients_list;
active_clients_list.Append(
base::Value::Dict()
.Set(shill::kTetheringStatusClientIPv4Property, "IPV4:001")
.Set(shill::kTetheringStatusClientHostnameProperty, "hostname1")
.Set(shill::kTetheringStatusClientMACProperty, "persist"));
status_dict.Set(shill::kTetheringStatusClientsProperty,
active_clients_list.Clone());
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(status_dict.Clone()));
base::RunLoop().RunUntilIdle();
hotspot_controller_->DisableHotspot(
base::DoNothing(), hotspot_config::mojom::DisableReason::kUserInitiated);
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotMaxClientCount,
/*sample=*/1, /*expected_count=*/1);
SetHotspotStateInShill(shill::kTetheringStateIdle);
// Verifies that the max client count is logged if hotspot is torn down by
// internal error.
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
// Add one more connected client.
active_clients_list.Append(
base::Value::Dict()
.Set(shill::kTetheringStatusClientIPv4Property, "IPV4:002")
.Set(shill::kTetheringStatusClientHostnameProperty, "hostname2"));
status_dict.Set(shill::kTetheringStatusClientsProperty,
std::move(active_clients_list));
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(status_dict.Clone()));
base::RunLoop().RunUntilIdle();
status_dict.Set(shill::kTetheringStatusStateProperty,
shill::kTetheringStateIdle);
status_dict.Set(shill::kTetheringStatusIdleReasonProperty,
shill::kTetheringIdleReasonError);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(status_dict.Clone()));
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotMaxClientCount,
/*sample=*/2, /*expected_count=*/1);
}
TEST_F(HotspotMetricsHelperTest, HotspotIsDeviceManagedHistogram) {
PrepareEnableHotspotForTesting();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotIsDeviceManaged, false,
/*expected_count=*/1);
hotspot_controller_->DisableHotspot(
base::DoNothing(), hotspot_config::mojom::DisableReason::kUserInitiated);
base::RunLoop().RunUntilIdle();
enterprise_managed_metadata_store_->set_is_enterprise_managed(
/*is_enterprise_managed=*/true);
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotIsDeviceManaged, true,
/*expected_count=*/1);
}
TEST_F(HotspotMetricsHelperTest, HotspotEnabledUpstreamStatusHistogram) {
ShillServiceClient::TestInterface* service_test =
network_state_test_helper_.service_test();
service_test->AddService(kCellularServicePath, kCellularServiceGuid,
kCellularServiceName, shill::kTypeCellular,
shill::kStateOnline, /*visible=*/true);
PrepareEnableHotspotForTesting();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotUpstreamStatusWhenEnabled,
HotspotMetricsHelper::HotspotMetricsUpstreamStatus::
kWifiWithCellularConnected,
/*expected_count=*/1);
hotspot_controller_->DisableHotspot(
base::DoNothing(), hotspot_config::mojom::DisableReason::kUserInitiated);
base::RunLoop().RunUntilIdle();
// Bring the cellular network down.
service_test->RemoveService(kCellularServicePath);
base::RunLoop().RunUntilIdle();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotUpstreamStatusWhenEnabled,
HotspotMetricsHelper::HotspotMetricsUpstreamStatus::
kWifiWithCellularNotConnected,
/*expected_count=*/1);
}
TEST_F(HotspotMetricsHelperTest, HotspotDisableReasonHistogram) {
PrepareEnableHotspotForTesting();
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
SetHotspotStateInShill(shill::kTetheringStateActive);
hotspot_controller_->DisableHotspot(
base::DoNothing(), hotspot_config::mojom::DisableReason::kUserInitiated);
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotDisableReasonHistogram,
HotspotMetricsHelper::HotspotMetricsDisableReason::kUserInitiated, 1);
SetHotspotStateInShill(shill::kTetheringStateActive);
// Verifies that the disabel reason is logged if hotspot is torn down by
// internal error.
auto status_dict =
base::Value::Dict()
.Set(shill::kTetheringStatusStateProperty, shill::kTetheringStateIdle)
.Set(shill::kTetheringStatusIdleReasonProperty,
shill::kTetheringIdleReasonError);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(status_dict.Clone()));
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotDisableReasonHistogram,
HotspotMetricsHelper::HotspotMetricsDisableReason::kInternalError, 1);
hotspot_controller_->EnableHotspot(base::DoNothing());
base::RunLoop().RunUntilIdle();
SetHotspotStateInShill(shill::kTetheringStateActive);
// When user actions result in hotspot being disabled, we have to skip
// recording disable reason received from the platform as we will be recording
// it from hotspot controller.
status_dict = base::Value::Dict()
.Set(shill::kTetheringStatusStateProperty,
shill::kTetheringStateIdle)
.Set(shill::kTetheringStatusIdleReasonProperty,
shill::kTetheringIdleReasonUserExit);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(status_dict.Clone()));
base::RunLoop().RunUntilIdle();
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotDisableReasonHistogram,
HotspotMetricsHelper::HotspotMetricsDisableReason::kUserInitiated, 1);
}
TEST_F(HotspotMetricsHelperTest, HotspotSetConfigHistogram) {
HotspotMetricsHelper::RecordSetHotspotConfigResult(
hotspot_config::mojom::SetHotspotConfigResult::kSuccess);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram,
HotspotMetricsHelper::HotspotMetricsSetConfigResult::kSuccess, 1);
HotspotMetricsHelper::RecordSetHotspotConfigResult(
hotspot_config::mojom::SetHotspotConfigResult::kFailedShillOperation,
shill::kErrorResultIllegalOperation);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram,
HotspotMetricsHelper::HotspotMetricsSetConfigResult::
kFailedIllegalOperation,
1);
HotspotMetricsHelper::RecordSetHotspotConfigResult(
hotspot_config::mojom::SetHotspotConfigResult::kFailedShillOperation,
shill::kErrorResultInvalidArguments);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram,
HotspotMetricsHelper::HotspotMetricsSetConfigResult::
kFailedInvalidArgument,
1);
}
} // namespace ash