// 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/eche_app_ui/system_info_provider.h"
#include "ash/public/cpp/network_config_service.h"
#include "ash/webui/eche_app_ui/system_info.h"
#include "base/json/json_reader.h"
#include "base/memory/raw_ptr.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/screen.h"
#include "ui/display/tablet_state.h"
#include "ui/display/test/test_screen.h"
namespace ash::eche_app {
namespace network_config = ::chromeos::network_config;
using network_config::mojom::ConnectionStateType;
const char kFakeDeviceName[] = "Guanru's Chromebook";
const char kFakeBoardName[] = "atlas";
const bool kFakeTabletMode = true;
const ConnectionStateType kFakeWifiConnectionState =
ConnectionStateType::kConnected;
const bool kFakeDebugMode = false;
const char kFakeGaiaId[] = "123";
const char kFakeDeviceType[] = "Chromebook";
const char kFakeOsVersion[] = "1.2.3.4";
const char kFakeChannel[] = "Dev";
const bool kFakeMeasureLatency = false;
const bool kFakeSendStartSignaling = true;
const bool kFakeDisableStunServer = false;
const bool kFakeCheckAndroidNetworkInfo = true;
const bool kFakeProcessAndroidAccessibilityTree = true;
void ParseJson(const std::string& json,
std::string& device_name,
std::string& board_name,
bool& tablet_mode,
std::string& wifi_connection_state,
bool& debug_mode,
std::string& gaia_id,
std::string& device_type,
std::string& os_version,
std::string& channel,
bool& measure_latency,
bool& send_start_signaling,
bool& disable_stun_server,
bool& check_android_network_info,
bool& process_android_accessibility_tree) {
std::optional<base::Value> message_value = base::JSONReader::Read(json);
base::Value::Dict* message_dictionary = message_value->GetIfDict();
const std::string* device_name_ptr =
message_dictionary->FindString(kJsonDeviceNameKey);
if (device_name_ptr)
device_name = *device_name_ptr;
const std::string* board_name_ptr =
message_dictionary->FindString(kJsonBoardNameKey);
if (board_name_ptr)
board_name = *board_name_ptr;
std::optional<bool> tablet_mode_opt =
message_dictionary->FindBool(kJsonTabletModeKey);
if (tablet_mode_opt.has_value())
tablet_mode = tablet_mode_opt.value();
const std::string* wifi_connection_state_ptr =
message_dictionary->FindString(kJsonWifiConnectionStateKey);
if (wifi_connection_state_ptr)
wifi_connection_state = *wifi_connection_state_ptr;
std::optional<bool> debug_mode_opt =
message_dictionary->FindBool(kJsonDebugModeKey);
if (debug_mode_opt.has_value())
debug_mode = debug_mode_opt.value();
const std::string* gaia_id_ptr =
message_dictionary->FindString(kJsonGaiaIdKey);
if (gaia_id_ptr)
gaia_id = *gaia_id_ptr;
const std::string* device_type_ptr =
message_dictionary->FindString(kJsonDeviceTypeKey);
if (device_type_ptr)
device_type = *device_type_ptr;
const std::string* os_version_ptr =
message_dictionary->FindString(kJsonOsVersionKey);
if (os_version_ptr) {
os_version = *os_version_ptr;
}
const std::string* channel_ptr =
message_dictionary->FindString(kJsonChannelKey);
if (channel_ptr) {
channel = *channel_ptr;
}
std::optional<bool> measure_latency_opt =
message_dictionary->FindBool(kJsonMeasureLatencyKey);
if (measure_latency_opt.has_value())
measure_latency = measure_latency_opt.value();
std::optional<bool> send_start_signaling_opt =
message_dictionary->FindBool(kJsonSendStartSignalingKey);
if (send_start_signaling_opt.has_value())
send_start_signaling = send_start_signaling_opt.value();
std::optional<bool> disable_stun_server_opt =
message_dictionary->FindBool(kJsonDisableStunServerKey);
if (disable_stun_server_opt.has_value())
disable_stun_server = disable_stun_server_opt.value();
std::optional<bool> check_android_network_info_opt =
message_dictionary->FindBool(kJsonCheckAndroidNetworkInfoKey);
if (check_android_network_info_opt.has_value())
check_android_network_info = check_android_network_info_opt.value();
std::optional<bool> process_android_accessibility_tree_opt =
message_dictionary->FindBool(kJsonProcessAndroidAccessibilityTreeKey);
if (process_android_accessibility_tree_opt.has_value())
process_android_accessibility_tree = process_android_accessibility_tree_opt.value();
}
class TaskRunner {
public:
TaskRunner() = default;
~TaskRunner() = default;
void WaitForResult() { run_loop_.Run(); }
void Finish() { run_loop_.Quit(); }
private:
base::test::SingleThreadTaskEnvironment task_environment_;
base::RunLoop run_loop_;
};
class FakeObserver : public mojom::SystemInfoObserver {
public:
FakeObserver() = default;
~FakeObserver() override = default;
size_t num_backlight_state_calls() const {
return num_backlight_state_calls_;
}
size_t num_tablet_state_calls() const { return num_tablet_state_calls_; }
size_t num_android_state_calls() const { return num_android_state_calls_; }
// mojom::SystemInfoObserver:
void OnScreenBacklightStateChanged(
ash::ScreenBacklightState screen_state) override {
++num_backlight_state_calls_;
if (task_runner_) {
task_runner_->Finish();
}
}
// mojom::SystemInfoObserver:
void OnReceivedTabletModeChanged(bool is_tablet_mode) override {
++num_tablet_state_calls_;
if (task_runner_) {
task_runner_->Finish();
}
}
void OnAndroidDeviceNetworkInfoChanged(
bool is_different_network,
bool android_device_on_cellular) override {
++num_android_state_calls_;
if (task_runner_) {
task_runner_->Finish();
}
}
static void setTaskRunner(TaskRunner* task_runner) {
task_runner_ = task_runner;
}
mojo::Receiver<mojom::SystemInfoObserver> receiver{this};
private:
size_t num_backlight_state_calls_ = 0;
size_t num_tablet_state_calls_ = 0;
size_t num_android_state_calls_ = 0;
static TaskRunner* task_runner_;
};
class Callback {
public:
static void GetSystemInfoCallback(const std::string& system_info) {
system_info_ = system_info;
}
static std::string GetSystemInfo() { return system_info_; }
static void resetSystemInfo() { system_info_ = ""; }
private:
static std::string system_info_;
};
ash::eche_app::TaskRunner* ash::eche_app::FakeObserver::task_runner_ = nullptr;
std::string ash::eche_app::Callback::system_info_ = "";
class SystemInfoProviderTest : public testing::Test {
protected:
SystemInfoProviderTest() {
ash::GetNetworkConfigService(
remote_cros_network_config_.BindNewPipeAndPassReceiver());
}
SystemInfoProviderTest(const SystemInfoProviderTest&) = delete;
SystemInfoProviderTest& operator=(const SystemInfoProviderTest&) = delete;
~SystemInfoProviderTest() override = default;
// testing::Test:
void SetUp() override {
display::Screen::GetScreen()->OverrideTabletStateForTesting(
display::TabletState::kInTabletMode);
system_info_provider_ =
std::make_unique<SystemInfoProvider>(SystemInfo::Builder()
.SetDeviceName(kFakeDeviceName)
.SetBoardName(kFakeBoardName)
.SetGaiaId(kFakeGaiaId)
.SetDeviceType(kFakeDeviceType)
.SetOsVersion(kFakeOsVersion)
.SetChannel(kFakeChannel)
.Build(),
remote_cros_network_config_.get());
fake_observer_ = std::make_unique<FakeObserver>();
system_info_provider_->SetSystemInfoObserver(
fake_observer_->receiver.BindNewPipeAndPassRemote());
SetWifiConnectionStateList();
}
void TearDown() override {
system_info_provider_.reset();
Callback::resetSystemInfo();
}
void GetSystemInfo() {
system_info_provider_->GetSystemInfo(
base::BindOnce(&Callback::GetSystemInfoCallback));
}
void SetWifiConnectionStateList() {
system_info_provider_->OnActiveWifiNetworkListFetched(
GetWifiNetworkStateList());
}
void SetOnScreenBacklightStateChanged() {
system_info_provider_->OnScreenBacklightStateChanged(
ash::ScreenBacklightState::OFF);
}
void SetAndroidDeviceNetworkInfoChanged() {
system_info_provider_->SetAndroidDeviceNetworkInfoChanged(false, false);
}
void StartTabletMode() {
system_info_provider_->OnDisplayTabletStateChanged(
display::TabletState::kInTabletMode);
}
void EndTabletMode() {
system_info_provider_->OnDisplayTabletStateChanged(
display::TabletState::kInClamshellMode);
}
std::vector<network_config::mojom::NetworkStatePropertiesPtr>
GetWifiNetworkStateList() {
std::vector<network_config::mojom::NetworkStatePropertiesPtr> result;
// Create a WiFiStatePropertiesPtr object
network_config::mojom::WiFiStatePropertiesPtr wifi_state_properties =
network_config::mojom::WiFiStateProperties::New();
// Set the required properties
wifi_state_properties->bssid = "00:11:22:33:44:55";
wifi_state_properties->frequency = 2412;
wifi_state_properties->hex_ssid = "48656c6c6f";
wifi_state_properties->security =
network_config::mojom::SecurityType::kNone;
wifi_state_properties->signal_strength = -50;
wifi_state_properties->ssid = "Test";
wifi_state_properties->hidden_ssid = false;
// Create a new NetworkTypeStateProperties object with the
// WiFiStateProperties
network_config::mojom::NetworkTypeStatePropertiesPtr
network_type_state_properties =
network_config::mojom::NetworkTypeStateProperties::NewWifi(
std::move(wifi_state_properties));
auto network = network_config::mojom::NetworkStateProperties::New(
/*connectable=*/true,
/*connect_requested=*/false,
/*connection_state=*/
kFakeWifiConnectionState,
/*error_state=*/std::nullopt,
/*guid=*/"some_guid",
/*name=*/"some_name",
/*portal_state=*/
network_config::mojom::PortalState::kUnknown,
/*portal_probe_url=*/std::nullopt,
/*priority=*/1,
/*proxy_mode=*/network_config::mojom::ProxyMode::kDirect,
/*prohibited_by_policy=*/false,
/*source=*/
network_config::mojom::OncSource::kUser,
/*network_type*/ network_config::mojom::NetworkType::kWiFi,
/*network_type_state*/ std::move(network_type_state_properties));
network->type = network_config::mojom::NetworkType::kWiFi;
network->connection_state = kFakeWifiConnectionState;
result.emplace_back(std::move(network));
return result;
}
size_t GetNumTabletStateObserverCalls() const {
return fake_observer_->num_tablet_state_calls();
}
size_t GetNumBacklightStateObserverCalls() const {
return fake_observer_->num_backlight_state_calls();
}
size_t GetNumAndroidStateObserverCalls() const {
return fake_observer_->num_android_state_calls();
}
TaskRunner task_runner_;
std::unique_ptr<FakeObserver> fake_observer_;
private:
display::test::TestScreen test_screen_{/*create_display=*/true,
/*register_screen=*/true};
std::unique_ptr<SystemInfoProvider> system_info_provider_;
mojo::Remote<network_config::mojom::CrosNetworkConfig>
remote_cros_network_config_;
};
TEST_F(SystemInfoProviderTest, GetSystemInfoHasCorrectJson) {
std::string device_name = "";
std::string board_name = "";
bool tablet_mode = false;
std::string wifi_connection_state = "";
bool debug_mode = true;
std::string gaia_id = "";
std::string device_type = "";
std::string os_version = "";
std::string channel = "";
bool measure_latency = true;
bool send_start_signaling = false;
bool disable_stun_server = true;
bool check_android_network_info = true;
bool process_android_accessibility_tree = true;
GetSystemInfo();
std::string json = Callback::GetSystemInfo();
ParseJson(json, device_name, board_name, tablet_mode, wifi_connection_state,
debug_mode, gaia_id, device_type, os_version, channel,
measure_latency, send_start_signaling, disable_stun_server,
check_android_network_info, process_android_accessibility_tree);
EXPECT_EQ(device_name, kFakeDeviceName);
EXPECT_EQ(board_name, kFakeBoardName);
EXPECT_EQ(tablet_mode, kFakeTabletMode);
EXPECT_EQ(wifi_connection_state, "connected");
EXPECT_EQ(debug_mode, kFakeDebugMode);
EXPECT_EQ(gaia_id, kFakeGaiaId);
EXPECT_EQ(device_type, kFakeDeviceType);
EXPECT_EQ(os_version, kFakeOsVersion);
EXPECT_EQ(channel, kFakeChannel);
EXPECT_EQ(measure_latency, kFakeMeasureLatency);
EXPECT_EQ(send_start_signaling, kFakeSendStartSignaling);
EXPECT_EQ(disable_stun_server, kFakeDisableStunServer);
EXPECT_EQ(check_android_network_info, kFakeCheckAndroidNetworkInfo);
EXPECT_EQ(process_android_accessibility_tree, kFakeProcessAndroidAccessibilityTree);
}
TEST_F(SystemInfoProviderTest, ObserverCalledWhenBacklightChanged) {
FakeObserver::setTaskRunner(&task_runner_);
SetOnScreenBacklightStateChanged();
task_runner_.WaitForResult();
EXPECT_EQ(1u, GetNumBacklightStateObserverCalls());
}
TEST_F(SystemInfoProviderTest, ObserverCalledWhenTabletModeStarted) {
FakeObserver::setTaskRunner(&task_runner_);
StartTabletMode();
task_runner_.WaitForResult();
EXPECT_EQ(1u, GetNumTabletStateObserverCalls());
}
TEST_F(SystemInfoProviderTest, ObserverCalledWhenTabletModeEnded) {
FakeObserver::setTaskRunner(&task_runner_);
EndTabletMode();
task_runner_.WaitForResult();
EXPECT_EQ(1u, GetNumTabletStateObserverCalls());
}
TEST_F(SystemInfoProviderTest,
ObserverCalledWhenAndroidDeviceNetworkStateChanged) {
FakeObserver::setTaskRunner(&task_runner_);
SetAndroidDeviceNetworkInfoChanged();
task_runner_.WaitForResult();
EXPECT_EQ(1u, GetNumAndroidStateObserverCalls());
}
} // namespace ash::eche_app