// 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/hotspot_configuration_handler.h"
#include "base/test/bind.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_clients.h"
#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
#include "chromeos/ash/components/network/enterprise_managed_metadata_store.h"
#include "chromeos/ash/components/network/hotspot_capabilities_provider.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/metrics/hotspot_metrics_helper.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "chromeos/ash/services/hotspot_config/public/cpp/hotspot_enabled_state_test_observer.h"
#include "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
namespace ash {
namespace {
const char kHotspotConfigSSID[] = "hotspot_SSID";
const char kHotspotConfigPassphrase[] = "hotspot_passphrase";
hotspot_config::mojom::HotspotConfigPtr GenerateTestConfig() {
auto mojom_config = hotspot_config::mojom::HotspotConfig::New();
mojom_config->auto_disable = false;
mojom_config->band = hotspot_config::mojom::WiFiBand::kAutoChoose;
mojom_config->security = hotspot_config::mojom::WiFiSecurityMode::kWpa2;
mojom_config->ssid = kHotspotConfigSSID;
mojom_config->passphrase = kHotspotConfigPassphrase;
mojom_config->bssid_randomization = false;
return mojom_config;
}
} // namespace
class TestObserver : public HotspotConfigurationHandler::Observer {
public:
TestObserver() = default;
~TestObserver() override = default;
// HotspotConfigurationHandler::Observer:
void OnHotspotConfigurationChanged() override {
hotspot_configuration_changed_count_++;
}
size_t hotspot_configuration_changed_count() {
return hotspot_configuration_changed_count_;
}
private:
size_t hotspot_configuration_changed_count_ = 0u;
};
class HotspotConfigurationHandlerTest : public ::testing::Test {
public:
void SetUp() override {
LoginState::Initialize();
LoginState::Get()->set_always_logged_in(false);
if (hotspot_configuration_handler_ &&
hotspot_configuration_handler_->HasObserver(&observer_)) {
hotspot_configuration_handler_->RemoveObserver(&observer_);
}
hotspot_configuration_handler_ =
std::make_unique<HotspotConfigurationHandler>();
hotspot_configuration_handler_->AddObserver(&observer_);
hotspot_configuration_handler_->Init();
base::RunLoop().RunUntilIdle();
}
void TearDown() override {
network_state_test_helper_.ClearDevices();
network_state_test_helper_.ClearServices();
hotspot_configuration_handler_->RemoveObserver(&observer_);
hotspot_configuration_handler_.reset();
LoginState::Shutdown();
}
hotspot_config::mojom::SetHotspotConfigResult SetHotspotConfig(
hotspot_config::mojom::HotspotConfigPtr mojom_config) {
base::RunLoop run_loop;
hotspot_config::mojom::SetHotspotConfigResult result;
hotspot_configuration_handler_->SetHotspotConfig(
std::move(mojom_config),
base::BindLambdaForTesting(
[&](hotspot_config::mojom::SetHotspotConfigResult success) {
result = success;
run_loop.Quit();
}));
run_loop.Run();
FlushMojoCalls();
return result;
}
void SetHotspotStateInShill(const std::string& state) {
auto status_dict =
base::Value::Dict().Set(shill::kTetheringStatusStateProperty, state);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringStatusProperty, base::Value(std::move(status_dict)));
base::RunLoop().RunUntilIdle();
}
void LoginToRegularUser() {
LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
LoginState::LOGGED_IN_USER_REGULAR);
task_environment_.RunUntilIdle();
}
void Logout() {
LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_NONE,
LoginState::LOGGED_IN_USER_NONE);
task_environment_.RunUntilIdle();
}
void FlushMojoCalls() { base::RunLoop().RunUntilIdle(); }
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::HistogramTester histogram_tester_;
std::unique_ptr<HotspotConfigurationHandler> hotspot_configuration_handler_;
TestObserver observer_;
NetworkStateTestHelper network_state_test_helper_{
/*use_default_devices_and_services=*/false};
};
TEST_F(HotspotConfigurationHandlerTest, UpdateHotspotConfigWhenProfileLoaded) {
const char kInitialSSID[] = "randomized_SSID";
const char kInitialPassphrase[] = "randomized_passphrase";
const char kLoadedSSID[] = "loaded_SSID";
const char kLoadedPassphrase[] = "loaded_passphrase";
auto config =
base::Value::Dict()
.Set(shill::kTetheringConfSSIDProperty,
base::HexEncode(kInitialSSID, std::strlen(kInitialSSID)))
.Set(shill::kTetheringConfPassphraseProperty, kInitialPassphrase)
.Set(shill::kTetheringConfAutoDisableProperty, true)
.Set(shill::kTetheringConfBandProperty, shill::kBandAll)
.Set(shill::kTetheringConfMARProperty, false)
.Set(shill::kTetheringConfSecurityProperty, shill::kSecurityWpa2);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringConfigProperty, base::Value(config.Clone()));
base::RunLoop().RunUntilIdle();
LoginToRegularUser();
EXPECT_EQ(hotspot_configuration_handler_->GetHotspotConfig()->ssid,
kInitialSSID);
EXPECT_EQ(hotspot_configuration_handler_->GetHotspotConfig()->passphrase,
kInitialPassphrase);
// Simulate shill load tethering config from user profile after login.
config.Set(shill::kTetheringConfSSIDProperty,
base::HexEncode(kLoadedSSID, std::strlen(kLoadedSSID)));
config.Set(shill::kTetheringConfPassphraseProperty, kLoadedPassphrase);
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kTetheringConfigProperty, base::Value(config.Clone()));
// Signals "Profiles" property change when user profile is fully loaded.
network_state_test_helper_.manager_test()->SetManagerProperty(
shill::kProfilesProperty, base::Value());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(hotspot_configuration_handler_->GetHotspotConfig()->ssid,
kLoadedSSID);
EXPECT_EQ(hotspot_configuration_handler_->GetHotspotConfig()->passphrase,
kLoadedPassphrase);
}
TEST_F(HotspotConfigurationHandlerTest, SetAndGetHotspotConfig) {
EXPECT_EQ(hotspot_config::mojom::SetHotspotConfigResult::kFailedNotLogin,
SetHotspotConfig(GenerateTestConfig()));
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram, 1);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram,
HotspotMetricsHelper::HotspotMetricsSetConfigResult::kFailedNotLogin, 1);
ASSERT_FALSE(hotspot_configuration_handler_->GetHotspotConfig());
EXPECT_EQ(0u, observer_.hotspot_configuration_changed_count());
LoginToRegularUser();
EXPECT_EQ(hotspot_config::mojom::SetHotspotConfigResult::kSuccess,
SetHotspotConfig(GenerateTestConfig()));
EXPECT_EQ(2u, observer_.hotspot_configuration_changed_count());
auto hotspot_config = hotspot_configuration_handler_->GetHotspotConfig();
EXPECT_TRUE(hotspot_config);
EXPECT_FALSE(hotspot_config->auto_disable);
EXPECT_EQ(hotspot_config->band, hotspot_config::mojom::WiFiBand::kAutoChoose);
EXPECT_EQ(hotspot_config->security,
hotspot_config::mojom::WiFiSecurityMode::kWpa2);
EXPECT_EQ(hotspot_config->ssid, kHotspotConfigSSID);
EXPECT_EQ(hotspot_config->passphrase, kHotspotConfigPassphrase);
EXPECT_FALSE(hotspot_config->bssid_randomization);
histogram_tester_.ExpectTotalCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram, 2);
histogram_tester_.ExpectBucketCount(
HotspotMetricsHelper::kHotspotSetConfigResultHistogram,
HotspotMetricsHelper::HotspotMetricsSetConfigResult::kSuccess, 1);
Logout();
ASSERT_FALSE(hotspot_configuration_handler_->GetHotspotConfig());
EXPECT_EQ(3u, observer_.hotspot_configuration_changed_count());
}
} // namespace ash