| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/metrics/cros_healthd_metrics_provider.h" |
| |
| #include <cstdint> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/functional/bind.h" |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "chromeos/ash/components/mojo_service_manager/fake_mojo_service_manager.h" |
| #include "chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.h" |
| #include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom.h" |
| #include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/metrics_proto/system_profile.pb.h" |
| |
| namespace { |
| |
| constexpr uint64_t kSizeMb = 1024; |
| constexpr uint64_t kSize = kSizeMb * 1e6; |
| constexpr char kModel[] = "fabulous"; |
| constexpr uint32_t kVendorIdNvme = 25; |
| constexpr uint16_t kVendorIdEmmc = 0xA5; |
| constexpr uint16_t kVendorIdEmmcLegacy = 0x5050; |
| constexpr uint16_t kVendorIdUfs = 0x1337; |
| constexpr uint32_t kProductIdNvme = 17; |
| constexpr uint64_t kProductIdEmmc = 0x4D4E504D4E50; |
| constexpr uint64_t kProductIdUfs = |
| 3210611189; // base::PersistentHash("fabulous") = 3210611189. |
| constexpr uint32_t kRevisionNvme = 92; |
| constexpr uint8_t kRevisionEmmc = 0x8; |
| constexpr uint64_t kFwVersionNvme = 0xA0EF1; |
| constexpr uint64_t kFwVersionEmmc = 0x1223344556677889; |
| constexpr uint64_t kFwVersionUfs = 0x32323032; |
| constexpr char kSubsystemNvme[] = "block:nvme:pcie"; |
| constexpr char kSubsystemEmmc[] = "block:mmc"; |
| constexpr char kSubsystemUfs[] = "block:scsi:scsi:scsi:pci"; |
| constexpr auto kTypeNvme = |
| metrics::SystemProfileProto::Hardware::InternalStorageDevice::TYPE_NVME; |
| constexpr auto kTypeEmmc = |
| metrics::SystemProfileProto::Hardware::InternalStorageDevice::TYPE_EMMC; |
| constexpr auto kTypeUfs = |
| metrics::SystemProfileProto::Hardware::InternalStorageDevice::TYPE_UFS; |
| constexpr auto kMojoPurpose = |
| ash::cros_healthd::mojom::StorageDevicePurpose::kBootDevice; |
| constexpr auto kUmaPurpose = |
| metrics::SystemProfileProto::Hardware::InternalStorageDevice::PURPOSE_BOOT; |
| |
| } // namespace |
| |
| class CrosHealthdMetricsProviderTest : public testing::Test { |
| public: |
| CrosHealthdMetricsProviderTest() { |
| ash::cros_healthd::FakeCrosHealthd::Initialize(); |
| } |
| |
| void SetFakeCrosHealthdData( |
| ash::cros_healthd::mojom::NonRemovableBlockDeviceInfoPtr storage_info) { |
| std::vector<ash::cros_healthd::mojom::NonRemovableBlockDeviceInfoPtr> devs; |
| devs.push_back(std::move(storage_info)); |
| auto info = ash::cros_healthd::mojom::TelemetryInfo::New(); |
| info->block_device_result = ash::cros_healthd::mojom:: |
| NonRemovableBlockDeviceResult::NewBlockDeviceInfo(std::move(devs)); |
| ash::cros_healthd::FakeCrosHealthd::Get() |
| ->SetProbeTelemetryInfoResponseForTesting(info); |
| } |
| |
| ~CrosHealthdMetricsProviderTest() override { |
| ash::cros_healthd::FakeCrosHealthd::Shutdown(); |
| } |
| |
| protected: |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| ::ash::mojo_service_manager::FakeMojoServiceManager fake_service_manager_; |
| }; |
| |
| TEST_F(CrosHealthdMetricsProviderTest, EndToEndWithNvme) { |
| ash::cros_healthd::mojom::NonRemovableBlockDeviceInfo storage_info; |
| storage_info.device_info = |
| ash::cros_healthd::mojom::BlockDeviceInfo::NewNvmeDeviceInfo( |
| ash::cros_healthd::mojom::NvmeDeviceInfo::New( |
| kVendorIdNvme, kProductIdNvme, kRevisionNvme, kFwVersionNvme)); |
| storage_info.vendor_id = |
| ash::cros_healthd::mojom::BlockDeviceVendor::NewNvmeSubsystemVendor( |
| kVendorIdNvme); |
| storage_info.product_id = |
| ash::cros_healthd::mojom::BlockDeviceProduct::NewNvmeSubsystemDevice( |
| kProductIdNvme); |
| storage_info.revision = |
| ash::cros_healthd::mojom::BlockDeviceRevision::NewNvmePcieRev( |
| kRevisionNvme); |
| storage_info.firmware_version = |
| ash::cros_healthd::mojom::BlockDeviceFirmware::NewNvmeFirmwareRev( |
| kFwVersionNvme); |
| storage_info.size = kSize; |
| storage_info.name = kModel; |
| storage_info.type = kSubsystemNvme; |
| storage_info.purpose = kMojoPurpose; |
| SetFakeCrosHealthdData(storage_info.Clone()); |
| |
| base::RunLoop run_loop; |
| CrosHealthdMetricsProvider provider; |
| provider.AsyncInit(base::BindOnce( |
| [](base::OnceClosure callback) { std::move(callback).Run(); }, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(provider.IsInitialized()); |
| metrics::SystemProfileProto profile; |
| provider.ProvideSystemProfileMetrics(&profile); |
| |
| const auto& hardware = profile.hardware(); |
| ASSERT_EQ(1, hardware.internal_storage_devices_size()); |
| |
| const auto& dev = hardware.internal_storage_devices(0); |
| |
| EXPECT_EQ(kVendorIdNvme, dev.vendor_id()); |
| EXPECT_EQ(kProductIdNvme, dev.product_id()); |
| EXPECT_EQ(kRevisionNvme, dev.revision()); |
| EXPECT_EQ(kFwVersionNvme, dev.firmware_version()); |
| EXPECT_EQ(kSizeMb, dev.size_mb()); |
| EXPECT_EQ(kModel, dev.model()); |
| EXPECT_EQ(kTypeNvme, dev.type()); |
| EXPECT_EQ(kUmaPurpose, dev.purpose()); |
| } |
| |
| TEST_F(CrosHealthdMetricsProviderTest, EndToEndWithEmmc) { |
| ash::cros_healthd::mojom::NonRemovableBlockDeviceInfo storage_info; |
| storage_info.device_info = |
| ash::cros_healthd::mojom::BlockDeviceInfo::NewEmmcDeviceInfo( |
| ash::cros_healthd::mojom::EmmcDeviceInfo::New( |
| kVendorIdEmmc, kProductIdEmmc, kRevisionEmmc, kFwVersionEmmc)); |
| storage_info.vendor_id = |
| ash::cros_healthd::mojom::BlockDeviceVendor::NewEmmcOemid( |
| kVendorIdEmmcLegacy); |
| storage_info.product_id = |
| ash::cros_healthd::mojom::BlockDeviceProduct::NewEmmcPnm(kProductIdEmmc); |
| storage_info.revision = |
| ash::cros_healthd::mojom::BlockDeviceRevision::NewEmmcPrv(kRevisionEmmc); |
| storage_info.firmware_version = |
| ash::cros_healthd::mojom::BlockDeviceFirmware::NewEmmcFwrev( |
| kFwVersionEmmc); |
| storage_info.size = kSize; |
| storage_info.name = kModel; |
| storage_info.type = kSubsystemEmmc; |
| storage_info.purpose = kMojoPurpose; |
| SetFakeCrosHealthdData(storage_info.Clone()); |
| |
| base::RunLoop run_loop; |
| CrosHealthdMetricsProvider provider; |
| provider.AsyncInit(base::BindOnce( |
| [](base::OnceClosure callback) { std::move(callback).Run(); }, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(provider.IsInitialized()); |
| metrics::SystemProfileProto profile; |
| provider.ProvideSystemProfileMetrics(&profile); |
| |
| const auto& hardware = profile.hardware(); |
| ASSERT_EQ(1, hardware.internal_storage_devices_size()); |
| |
| const auto& dev = hardware.internal_storage_devices(0); |
| |
| EXPECT_EQ(kVendorIdEmmc, dev.vendor_id()); |
| EXPECT_EQ(kProductIdEmmc, dev.product_id()); |
| EXPECT_EQ(kRevisionEmmc, dev.revision()); |
| EXPECT_EQ(kFwVersionEmmc, dev.firmware_version()); |
| EXPECT_EQ(kSizeMb, dev.size_mb()); |
| EXPECT_EQ(kModel, dev.model()); |
| EXPECT_EQ(kTypeEmmc, dev.type()); |
| EXPECT_EQ(kUmaPurpose, dev.purpose()); |
| } |
| |
| TEST_F(CrosHealthdMetricsProviderTest, EndToEndWithUfs) { |
| ash::cros_healthd::mojom::NonRemovableBlockDeviceInfo storage_info; |
| storage_info.device_info = |
| ash::cros_healthd::mojom::BlockDeviceInfo::NewUfsDeviceInfo( |
| ash::cros_healthd::mojom::UfsDeviceInfo::New(kVendorIdUfs, |
| kFwVersionUfs)); |
| storage_info.vendor_id = |
| ash::cros_healthd::mojom::BlockDeviceVendor::NewJedecManfid(kVendorIdUfs); |
| storage_info.product_id = |
| ash::cros_healthd::mojom::BlockDeviceProduct::NewOther(0); |
| storage_info.revision = |
| ash::cros_healthd::mojom::BlockDeviceRevision::NewOther(0); |
| storage_info.firmware_version = |
| ash::cros_healthd::mojom::BlockDeviceFirmware::NewUfsFwrev(kFwVersionUfs); |
| storage_info.size = kSize; |
| storage_info.name = kModel; |
| storage_info.type = kSubsystemUfs; |
| storage_info.purpose = kMojoPurpose; |
| SetFakeCrosHealthdData(storage_info.Clone()); |
| |
| base::RunLoop run_loop; |
| CrosHealthdMetricsProvider provider; |
| provider.AsyncInit(base::BindOnce( |
| [](base::OnceClosure callback) { std::move(callback).Run(); }, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(provider.IsInitialized()); |
| metrics::SystemProfileProto profile; |
| provider.ProvideSystemProfileMetrics(&profile); |
| |
| const auto& hardware = profile.hardware(); |
| ASSERT_EQ(1, hardware.internal_storage_devices_size()); |
| |
| const auto& dev = hardware.internal_storage_devices(0); |
| |
| EXPECT_EQ(kVendorIdUfs, dev.vendor_id()); |
| EXPECT_EQ(kProductIdUfs, dev.product_id()); |
| EXPECT_EQ(kFwVersionUfs, dev.firmware_version()); |
| EXPECT_EQ(kSizeMb, dev.size_mb()); |
| EXPECT_EQ(kModel, dev.model()); |
| EXPECT_EQ(kTypeUfs, dev.type()); |
| EXPECT_EQ(kUmaPurpose, dev.purpose()); |
| } |
| |
| TEST_F(CrosHealthdMetricsProviderTest, EndToEndTimeout) { |
| ash::cros_healthd::FakeCrosHealthd::Get()->SetCallbackDelay( |
| CrosHealthdMetricsProvider::GetTimeout() + base::Seconds(5)); |
| |
| base::RunLoop run_loop; |
| CrosHealthdMetricsProvider provider; |
| provider.AsyncInit(base::BindOnce( |
| [](base::OnceClosure callback) { std::move(callback).Run(); }, |
| run_loop.QuitClosure())); |
| |
| // FastForward by timeout period. |
| task_environment_.FastForwardBy(CrosHealthdMetricsProvider::GetTimeout()); |
| run_loop.Run(); |
| |
| EXPECT_FALSE(provider.IsInitialized()); |
| |
| metrics::SystemProfileProto profile; |
| provider.ProvideSystemProfileMetrics(&profile); |
| |
| const auto& hardware = profile.hardware(); |
| EXPECT_EQ(0, hardware.internal_storage_devices_size()); |
| } |