blob: 6fc70962a186e2f605c77915d8c8a8f9c3ff690a [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/optional.h>
#include <gtest/gtest.h>
#include "diagnostics/common/file_test_utils.h"
#include "diagnostics/cros_healthd/fetchers/system_fetcher.h"
#include "diagnostics/cros_healthd/system/mock_context.h"
namespace diagnostics {
namespace {
// Fake cached VPD values used for testing.
const char kFakeFirstPowerDate[] = "2020-40";
const char kFakeManufactureDate[] = "2019-01-01";
const char kFakeSkuNumber[] = "ABCD&^A";
// Fake CrosConfig value used for testing.
constexpr char kFakeMarketingName[] = "Latitude 1234 Chromebook Enterprise";
// Fake DMI values used for testing.
constexpr char kFakeBiosVersion[] = "Google_BoardName.12200.68.0";
constexpr char kFakeBoardName[] = "BoardName";
constexpr char kFakeBoardVersion[] = "rev1234";
constexpr char kFakeChassisType[] = "9";
constexpr uint64_t kFakeChassisTypeOutput = 9;
constexpr char kFakeProductName[] = "ProductName";
} // namespace
class SystemUtilsTest : public ::testing::Test {
protected:
SystemUtilsTest() = default;
SystemUtilsTest(const SystemUtilsTest&) = delete;
SystemUtilsTest& operator=(const SystemUtilsTest&) = delete;
void SetUp() override {
ASSERT_TRUE(mock_context_.Initialize());
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath root_dir = GetTempDirPath();
// Populate fake cached VPD values.
relative_vpd_rw_dir_ = root_dir.Append(kRelativeVpdRwPath);
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_vpd_rw_dir_.Append(kFirstPowerDateFileName),
kFakeFirstPowerDate));
relative_vpd_ro_dir_ = root_dir.Append(kRelativeVpdRoPath);
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_vpd_ro_dir_.Append(kManufactureDateFileName),
kFakeManufactureDate));
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_vpd_ro_dir_.Append(kSkuNumberFileName), kFakeSkuNumber));
// Populate fake DMI values.
relative_dmi_info_path_ = root_dir.Append(kRelativeDmiInfoPath);
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_dmi_info_path_.Append(kBiosVersionFileName),
kFakeBiosVersion));
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_dmi_info_path_.Append(kBoardNameFileName), kFakeBoardName));
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_dmi_info_path_.Append(kBoardVersionFileName),
kFakeBoardVersion));
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_dmi_info_path_.Append(kChassisTypeFileName),
kFakeChassisType));
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_dmi_info_path_.Append(kProductNameFileName),
kFakeProductName));
SetHasSkuNumber(true);
SetMarketingName(kFakeMarketingName);
}
const base::FilePath& GetTempDirPath() const {
DCHECK(temp_dir_.IsValid());
return temp_dir_.GetPath();
}
chromeos::cros_healthd::mojom::SystemResultPtr FetchSystemInfo(
const base::FilePath& root_dir) {
return system_fetcher_.FetchSystemInfo(root_dir);
}
void SetHasSkuNumber(bool val) {
mock_context_.fake_system_config()->SetHasSkuNumber(val);
}
void SetMarketingName(const std::string& val) {
mock_context_.fake_system_config()->SetMarketingName(val);
}
void ValidateCachedVpdInfo(
const chromeos::cros_healthd::mojom::SystemInfoPtr& system_info) {
ASSERT_TRUE(system_info->first_power_date.has_value());
EXPECT_EQ(system_info->first_power_date.value(), kFakeFirstPowerDate);
ASSERT_TRUE(system_info->manufacture_date.has_value());
EXPECT_EQ(system_info->manufacture_date.value(), kFakeManufactureDate);
ASSERT_TRUE(system_info->product_sku_number.has_value());
EXPECT_EQ(system_info->product_sku_number.value(), kFakeSkuNumber);
}
void ValidateCrosConfigInfo(
const chromeos::cros_healthd::mojom::SystemInfoPtr& system_info) {
EXPECT_EQ(system_info->marketing_name, kFakeMarketingName);
}
void ValidateDmiInfo(
const chromeos::cros_healthd::mojom::SystemInfoPtr& system_info) {
ASSERT_TRUE(system_info->bios_version.has_value());
EXPECT_EQ(system_info->bios_version, kFakeBiosVersion);
ASSERT_TRUE(system_info->board_name.has_value());
EXPECT_EQ(system_info->board_name, kFakeBoardName);
ASSERT_TRUE(system_info->board_version.has_value());
EXPECT_EQ(system_info->board_version, kFakeBoardVersion);
ASSERT_TRUE(system_info->chassis_type);
EXPECT_EQ(system_info->chassis_type->value, kFakeChassisTypeOutput);
ASSERT_TRUE(system_info->product_name.has_value());
EXPECT_EQ(system_info->product_name, kFakeProductName);
}
const base::FilePath& relative_vpd_rw_dir() { return relative_vpd_rw_dir_; }
const base::FilePath& relative_vpd_ro_dir() { return relative_vpd_ro_dir_; }
const base::FilePath& relative_dmi_info_path() {
return relative_dmi_info_path_;
}
private:
MockContext mock_context_;
SystemFetcher system_fetcher_{&mock_context_};
base::ScopedTempDir temp_dir_;
base::FilePath relative_vpd_rw_dir_;
base::FilePath relative_vpd_ro_dir_;
base::FilePath relative_dmi_info_path_;
};
// Test that we can read the system info, when it exists.
TEST_F(SystemUtilsTest, TestFetchSystemInfo) {
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
ValidateDmiInfo(system_info);
}
// Test that no first_power_date is reported when |kFirstPowerDateFileName| is
// not found.
TEST_F(SystemUtilsTest, TestNoFirstPowerDate) {
// Delete the file containing first power date.
ASSERT_TRUE(base::DeleteFile(
relative_vpd_rw_dir().Append(kFirstPowerDateFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
// Confirm that cached VPD values except first power date are obtained.
EXPECT_FALSE(system_info->first_power_date.has_value());
ASSERT_TRUE(system_info->manufacture_date.has_value());
EXPECT_EQ(system_info->manufacture_date.value(), kFakeManufactureDate);
ASSERT_TRUE(system_info->product_sku_number.has_value());
EXPECT_EQ(system_info->product_sku_number.value(), kFakeSkuNumber);
ValidateCrosConfigInfo(system_info);
ValidateDmiInfo(system_info);
}
// Test that no manufacture_date is reported when |kManufactureDateFileName| is
// not found.
TEST_F(SystemUtilsTest, TestNoManufactureDate) {
// Delete the file containing manufacture date.
ASSERT_TRUE(base::DeleteFile(
relative_vpd_ro_dir().Append(kManufactureDateFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
// Confirm that cached VPD values except manufacture date are obtained.
ASSERT_TRUE(system_info->first_power_date.has_value());
EXPECT_EQ(system_info->first_power_date.value(), kFakeFirstPowerDate);
EXPECT_FALSE(system_info->manufacture_date.has_value());
ASSERT_TRUE(system_info->product_sku_number.has_value());
EXPECT_EQ(system_info->product_sku_number.value(), kFakeSkuNumber);
ValidateCrosConfigInfo(system_info);
ValidateDmiInfo(system_info);
}
// Test that reading system info that does not have |kSkuNumberFileName| (when
// it should) reports an error.
TEST_F(SystemUtilsTest, TestSkuNumberError) {
// Delete the file containing sku number.
ASSERT_TRUE(base::DeleteFile(relative_vpd_ro_dir().Append(kSkuNumberFileName),
false));
// Confirm that an error is obtained.
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_error());
EXPECT_EQ(system_result->get_error()->type,
chromeos::cros_healthd::mojom::ErrorType::kFileReadError);
}
// Test that no product_sku_number is returned when the device does not have
// |kSkuNumberFileName|.
TEST_F(SystemUtilsTest, TestNoSkuNumber) {
// Delete the file containing sku number.
ASSERT_TRUE(base::DeleteFile(relative_vpd_ro_dir().Append(kSkuNumberFileName),
false));
// Ensure that there is no sku number.
SetHasSkuNumber(false);
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
// Confirm that correct cached VPD values except sku number are obtained.
ASSERT_TRUE(system_info->first_power_date.has_value());
EXPECT_EQ(system_info->first_power_date.value(), kFakeFirstPowerDate);
ASSERT_TRUE(system_info->manufacture_date.has_value());
EXPECT_EQ(system_info->manufacture_date.value(), kFakeManufactureDate);
EXPECT_FALSE(system_info->product_sku_number.has_value());
ValidateCrosConfigInfo(system_info);
ValidateDmiInfo(system_info);
}
// Test that no DMI fields are populated when |kRelativeDmiInfoPath| doesn't
// exist.
TEST_F(SystemUtilsTest, TestNoSysDevicesVirtualDmiId) {
// Delete the directory |kRelativeDmiInfoPath|.
ASSERT_TRUE(base::DeleteFile(relative_dmi_info_path(), true));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
// Confirm that no DMI values are obtained.
EXPECT_FALSE(system_info->bios_version.has_value());
EXPECT_FALSE(system_info->board_name.has_value());
EXPECT_FALSE(system_info->board_version.has_value());
EXPECT_FALSE(system_info->chassis_type);
EXPECT_FALSE(system_info->product_name.has_value());
}
// Test that there is no bios_version when |kBiosVersionFileName| is missing.
TEST_F(SystemUtilsTest, TestNoBiosVersion) {
// Delete the file containing bios version.
ASSERT_TRUE(base::DeleteFile(
relative_dmi_info_path().Append(kBiosVersionFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
// Confirm that the bios_version was not populated.
EXPECT_FALSE(system_info->bios_version.has_value());
ASSERT_TRUE(system_info->board_name.has_value());
EXPECT_EQ(system_info->board_name.value(), kFakeBoardName);
ASSERT_TRUE(system_info->board_version.has_value());
EXPECT_EQ(system_info->board_version.value(), kFakeBoardVersion);
ASSERT_TRUE(system_info->chassis_type);
EXPECT_EQ(system_info->chassis_type->value, kFakeChassisTypeOutput);
ASSERT_TRUE(system_info->product_name.has_value());
EXPECT_EQ(system_info->product_name.value(), kFakeProductName);
}
// Test that there is no board_name when |kBoardNameFileName| is missing.
TEST_F(SystemUtilsTest, TestNoBoardName) {
// Delete the file containing board name.
ASSERT_TRUE(base::DeleteFile(
relative_dmi_info_path().Append(kBoardNameFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
// Confirm that the board_name was not populated.
ASSERT_TRUE(system_info->bios_version.has_value());
EXPECT_EQ(system_info->bios_version.value(), kFakeBiosVersion);
EXPECT_FALSE(system_info->board_name.has_value());
ASSERT_TRUE(system_info->board_version.has_value());
EXPECT_EQ(system_info->board_version.value(), kFakeBoardVersion);
ASSERT_TRUE(system_info->chassis_type);
EXPECT_EQ(system_info->chassis_type->value, kFakeChassisTypeOutput);
ASSERT_TRUE(system_info->product_name.has_value());
EXPECT_EQ(system_info->product_name.value(), kFakeProductName);
}
// Test that there is no board_version when |kBoardVersionFileName| is missing.
TEST_F(SystemUtilsTest, TestNoBoardVersion) {
// Delete the file containing board version.
ASSERT_TRUE(base::DeleteFile(
relative_dmi_info_path().Append(kBoardVersionFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
// Confirm that the board_version was not populated.
ASSERT_TRUE(system_info->bios_version.has_value());
EXPECT_EQ(system_info->bios_version.value(), kFakeBiosVersion);
ASSERT_TRUE(system_info->board_name.has_value());
EXPECT_EQ(system_info->board_name.value(), kFakeBoardName);
EXPECT_FALSE(system_info->board_version.has_value());
ASSERT_TRUE(system_info->chassis_type);
EXPECT_EQ(system_info->chassis_type->value, kFakeChassisTypeOutput);
ASSERT_TRUE(system_info->product_name.has_value());
EXPECT_EQ(system_info->product_name.value(), kFakeProductName);
}
// Test that there is no chassis_type when |kChassisTypeFileName| is missing.
TEST_F(SystemUtilsTest, TestNoChassisType) {
// Delete the file containing chassis type.
ASSERT_TRUE(base::DeleteFile(
relative_dmi_info_path().Append(kChassisTypeFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
// Confirm that the chassis_type was not populated.
ASSERT_TRUE(system_info->bios_version.has_value());
EXPECT_EQ(system_info->bios_version.value(), kFakeBiosVersion);
ASSERT_TRUE(system_info->board_name.has_value());
EXPECT_EQ(system_info->board_name.value(), kFakeBoardName);
ASSERT_TRUE(system_info->board_version.has_value());
EXPECT_EQ(system_info->board_version.value(), kFakeBoardVersion);
EXPECT_FALSE(system_info->chassis_type);
ASSERT_TRUE(system_info->product_name.has_value());
EXPECT_EQ(system_info->product_name.value(), kFakeProductName);
}
// Test that reading a chassis_type that cannot be converted to an unsigned
// integer reports an error.
TEST_F(SystemUtilsTest, TestBadChassisType) {
// Overwrite the contents of |kChassisTypeFileName| with a chassis_type value
// that cannot be parsed into an unsigned integer.
std::string bad_chassis_type = "bad chassis type";
ASSERT_TRUE(WriteFileAndCreateParentDirs(
relative_dmi_info_path().Append(kChassisTypeFileName), bad_chassis_type));
// Confirm that an error is obtained.
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_error());
EXPECT_EQ(system_result->get_error()->type,
chromeos::cros_healthd::mojom::ErrorType::kParseError);
}
// Test that there is no product_name when |kProductNameFileName| is missing.
TEST_F(SystemUtilsTest, TestNoProductName) {
// Delete the file containing product name.
ASSERT_TRUE(base::DeleteFile(
relative_dmi_info_path().Append(kProductNameFileName), false));
auto system_result = FetchSystemInfo(GetTempDirPath());
ASSERT_TRUE(system_result->is_system_info());
const auto& system_info = system_result->get_system_info();
ValidateCachedVpdInfo(system_info);
ValidateCrosConfigInfo(system_info);
// Confirm that the product_name was not populated.
ASSERT_TRUE(system_info->bios_version.has_value());
EXPECT_EQ(system_info->bios_version.value(), kFakeBiosVersion);
ASSERT_TRUE(system_info->board_name.has_value());
EXPECT_EQ(system_info->board_name.value(), kFakeBoardName);
ASSERT_TRUE(system_info->board_version.has_value());
EXPECT_EQ(system_info->board_version.value(), kFakeBoardVersion);
ASSERT_TRUE(system_info->chassis_type);
EXPECT_EQ(system_info->chassis_type->value, kFakeChassisTypeOutput);
EXPECT_FALSE(system_info->product_name.has_value());
}
} // namespace diagnostics