blob: 12134bd1caa999034b1c70598e092ec9499b7503 [file]
#include "chassis.hpp"
#include <memory>
#include <string>
#include <system_error> // NOLINT
#include <unordered_set>
#include <utility>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/strings/str_cat.h"
#include "async_resp.hpp"
#include "dbus_utility.hpp" // IWYU pragma: keep
#include "subprocess_utils.hpp"
#include "subprocess_utils_fake.hpp"
#include "test/redfish-core/lib/snapshot_fixture.hpp"
#include <nlohmann/json.hpp>
#include "managed_store.hpp"
#include "managed_store_types.hpp"
#include "test/g3/mock_managed_store.hpp"
#include "test/g3/mock_managed_store_test.hpp"
#include "sdbusplus/message/native_types.hpp"
namespace redfish {
namespace {
using ::managedStore::KeyType;
using ::managedStore::ManagedType;
using ::testing::Contains;
using ::testing::NotNull;
constexpr char fakeChassis[] = "fakeChassis";
TEST(HandleChassisResetActionInfoGet, StaticAttributesAreExpected) {
auto response = std::make_shared<bmcweb::AsyncResp>();
std::error_code err;
validateChassisResetActionInfoHandler(response, fakeChassis, err,
"RackMount");
nlohmann::json& json = response->res.jsonValue;
EXPECT_EQ(json["@odata.type"], "#ActionInfo.v1_1_2.ActionInfo");
EXPECT_EQ(json["@odata.id"], absl::StrCat("/redfish/v1/Chassis/", fakeChassis,
"/ResetActionInfo"));
EXPECT_EQ(json["Name"], "Reset Action Info");
EXPECT_EQ(json["Id"], "ResetActionInfo");
nlohmann::json::array_t parameters;
nlohmann::json::object_t delayParameter;
delayParameter["Name"] = "Delay";
delayParameter["Required"] = false;
delayParameter["DataType"] = "Number";
nlohmann::json::object_t parameter;
parameter["Name"] = "ResetType";
parameter["Required"] = true;
parameter["DataType"] = "String";
nlohmann::json::array_t allowed;
allowed.push_back("PowerCycle");
parameter["AllowableValues"] = std::move(allowed);
parameters.push_back(std::move(parameter));
parameters.push_back(std::move(delayParameter));
EXPECT_EQ(json["Parameters"], parameters);
}
TEST_F(SnapshotFixture, ChassisTypeTestReturnsCorrectResponse) {
auto response = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = response->res.jsonValue;
json["ChassisType"] = "RackMount";
addChassisReset(response, fakeChassis, "UnsupportedType");
RunIoUntilDone();
EXPECT_EQ(json["ChassisType"], "UnsupportedType");
}
TEST_F(SnapshotFixture, GetChassisCollectionTestReturnsCorrectResposne) {
handleChassisCollectionGet(app_, CreateRequest(), share_async_resp_);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"], "/redfish/v1/Chassis");
EXPECT_EQ(json["@odata.type"], "#ChassisCollection.ChassisCollection");
EXPECT_EQ(json["Name"], "Chassis Collection");
EXPECT_EQ(json["Members@odata.count"], json["Members"].size());
std::unordered_set<std::string> chassis_set{
{"/redfish/v1/Chassis/Bigchassis2_1", "/redfish/v1/Chassis/chassis1V2ND",
"/redfish/v1/Chassis/chassis3_1", "/redfish/v1/Chassis/chassis4_1",
"/redfish/v1/Chassis/coin_battery", "/redfish/v1/Chassis/i2cool_0",
"/redfish/v1/Chassis/i2cool_1", "/redfish/v1/Chassis/i2cool_2",
"/redfish/v1/Chassis/ioadapter_x16_1", "/redfish/v1/Chassis/platform1"}};
EXPECT_EQ(json["Members"].size(), chassis_set.size());
for (const auto& member : json["Members"]) {
ASSERT_TRUE(member.contains("@odata.id"));
const std::string* chassis =
member["@odata.id"].get_ptr<const std::string*>();
ASSERT_THAT(chassis, NotNull());
EXPECT_THAT(chassis_set, Contains(*chassis));
}
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
void CheckChassisProcessorsAndSubsystems(nlohmann::json& json,
const std::string& systemPath,
const bool expectPcieMemory) {
EXPECT_EQ(json["Links"]["Processors"][0]["@odata.id"],
systemPath + "/Processors/cpu0");
EXPECT_EQ(json["Links"]["Processors"][1]["@odata.id"],
systemPath + "/Processors/cpu1");
if (expectPcieMemory) {
EXPECT_EQ(json["Memory"]["@odata.id"], systemPath + "/Memory");
EXPECT_EQ(json["PCIeDevices"]["@odata.id"], systemPath + "/PCIeDevices");
} else {
EXPECT_TRUE(json["Memory"].is_null());
EXPECT_TRUE(json["PCIeDevices"].is_null());
}
}
TEST_F(SnapshotFixture, GetChassisTestReturnsCorrectResposne) {
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
managedStore::KeyType key(
managedStore::ManagedType::kManagedAssociatedSubtreePaths,
"/xyz/openbmc_project/inventory/system/board/platform1/contained_by",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockAssocPaths = {
"/xyz/openbmc_project/inventory/system1"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
mockAssocPaths))
.ok());
managedStore::KeyType processorKey(
managedStore::ManagedType::kManagedProperty,
"xyz.openbmc_project.ObjectMapper",
sdbusplus::message::object_path(
"/xyz/openbmc_project/inventory/system/board/platform1/processors"),
"xyz.openbmc_project.Association", "endpoints");
std::vector<std::string> mockProcessors = {
"/xyz/openbmc_project/inventory/system1/chassis/processors/cpu0",
"/xyz/openbmc_project/inventory/system1/chassis/processors/cpu1"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
processorKey,
managedStore::MockManagedStoreTest::CreateValueType(
dbus::utility::DbusVariantType(mockProcessors)))
.ok());
std::string expectedSystem = "/redfish/v1/Systems/system1";
#else
std::string expectedSystem = "/redfish/v1/Systems/system";
#endif
managedStore::KeyType powerStateKey(
managedStore::ManagedType::kManagedProperty,
"xyz.openbmc_project.State.Chassis1",
sdbusplus::message::object_path(
"/xyz/openbmc_project/state/chassis_system0"),
"xyz.openbmc_project.State.Chassis", "CurrentPowerState");
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
powerStateKey,
managedStore::MockManagedStoreTest::CreateValueType(
dbus::utility::DbusVariantType(std::string(
"xyz.openbmc_project.State.Chassis.PowerState.On"))))
.ok());
handleChassisGet(app_, CreateRequest(), share_async_resp_, "platform1");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"], "/redfish/v1/Chassis/platform1");
EXPECT_EQ(json["@odata.type"], "#Chassis.v1_17_0.Chassis");
EXPECT_EQ(json["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"],
"/redfish/v1/Chassis/platform1/ResetActionInfo");
EXPECT_EQ(json["Actions"]["#Chassis.Reset"]["target"],
"/redfish/v1/Chassis/platform1/Actions/Chassis.Reset");
EXPECT_EQ(json["Assembly"]["@odata.id"],
"/redfish/v1/Chassis/platform1/Assembly");
EXPECT_EQ(json["Certificates"]["@odata.id"],
"/redfish/v1/Chassis/platform1/Certificates");
EXPECT_EQ(json["ChassisType"], "RackMount");
EXPECT_EQ(json["Drives"]["@odata.id"],
"/redfish/v1/Chassis/platform1/Drives");
#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
EXPECT_EQ(json["EnvironmentMetrics"]["@odata.id"],
"/redfish/v1/Chassis/platform1/EnvironmentMetrics");
#endif
EXPECT_EQ(json["Id"], "platform1");
EXPECT_EQ(json["Links"]["Cables"].size(),
json["Links"]["Cables@odata.count"]);
EXPECT_EQ(json["Links"]["Cables"][0]["@odata.id"],
"/redfish/v1/Cables/NcsiCable");
EXPECT_EQ(json["Links"]["ComputerSystems"].size(), 1);
EXPECT_EQ(json["Links"]["ComputerSystems"][0]["@odata.id"], expectedSystem);
EXPECT_EQ(json["Links"]["ManagedBy"].size(), 1);
EXPECT_EQ(json["Links"]["ManagedBy"][0]["@odata.id"],
"/redfish/v1/Managers/bmc");
EXPECT_EQ(json["Links"]["Processors"].size(),
json["Links"]["Processors@odata.count"]);
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
CheckChassisProcessorsAndSubsystems(json, expectedSystem, false);
#else
CheckChassisProcessorsAndSubsystems(json, expectedSystem, true);
#endif
EXPECT_EQ(json["Manufacturer"], "Manufacturer");
EXPECT_EQ(json["Model"], "Model");
EXPECT_EQ(json["Name"], "platform1");
EXPECT_EQ(json["PCIeSlots"]["@odata.id"],
"/redfish/v1/Chassis/platform1/PCIeSlots");
EXPECT_EQ(json["PartNumber"], "PartNumber");
EXPECT_EQ(json["PowerState"], "On");
#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
EXPECT_EQ(json["Power"]["@odata.id"], "/redfish/v1/Chassis/platform1/Power");
#endif
#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
EXPECT_EQ(json["PowerSubsystem"]["@odata.id"],
"/redfish/v1/Chassis/platform1/PowerSubsystem");
#endif
EXPECT_EQ(json["Sensors"]["@odata.id"],
"/redfish/v1/Chassis/platform1/Sensors");
EXPECT_EQ(json["SerialNumber"], "SerialNumber");
EXPECT_EQ(json["Status"]["State"], "Enabled");
#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
EXPECT_EQ(json["Thermal"]["@odata.id"],
"/redfish/v1/Chassis/platform1/Thermal");
#endif
#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
EXPECT_EQ(json["ThermalSubsystem"]["@odata.id"],
"/redfish/v1/Chassis/platform1/ThermalSubsystem");
#endif
EXPECT_EQ(json["TrustedComponents"]["@odata.id"],
"/redfish/v1/Chassis/platform1/TrustedComponents");
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(SnapshotFixture, GetChassisTestPowerStateOff) {
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
managedStore::KeyType key(
managedStore::ManagedType::kManagedAssociatedSubtreePaths,
"/xyz/openbmc_project/inventory/system/board/platform1/contained_by",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockAssocPaths = {
"/xyz/openbmc_project/inventory/system1"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
mockAssocPaths))
.ok());
managedStore::KeyType processorKey(
managedStore::ManagedType::kManagedProperty,
"xyz.openbmc_project.ObjectMapper",
sdbusplus::message::object_path(
"/xyz/openbmc_project/inventory/system/board/platform1/processors"),
"xyz.openbmc_project.Association", "endpoints");
std::vector<std::string> mockProcessors = {
"/xyz/openbmc_project/inventory/system1/chassis/processors/cpu0",
"/xyz/openbmc_project/inventory/system1/chassis/processors/cpu1"};
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
processorKey, managedStore::MockManagedStoreTest::CreateValueType(
dbus::utility::DbusVariantType(mockProcessors)))
.ok());
#endif
managedStore::KeyType powerStateKey(
managedStore::ManagedType::kManagedProperty,
"xyz.openbmc_project.State.Chassis1",
sdbusplus::message::object_path(
"/xyz/openbmc_project/state/chassis_system0"),
"xyz.openbmc_project.State.Chassis", "CurrentPowerState");
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
powerStateKey,
managedStore::MockManagedStoreTest::CreateValueType(
dbus::utility::DbusVariantType(std::string(
"xyz.openbmc_project.State.Chassis.PowerState.Off"))))
.ok());
handleChassisGet(app_, CreateRequest(), share_async_resp_, "platform1");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["PowerState"], "Off");
EXPECT_EQ(json["Status"]["State"], "StandbyOffline");
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
// Restore power state to On for clean state in fixture
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
powerStateKey,
managedStore::MockManagedStoreTest::CreateValueType(
dbus::utility::DbusVariantType(std::string(
"xyz.openbmc_project.State.Chassis.PowerState.On"))))
.ok());
}
TEST_F(SnapshotFixture, PostChassisCycleDelayGood) {
SubprocessUtilsFake subprocessUtilsFake;
SubprocessUtilsBase::setInstance(
std::make_unique<SubprocessUtilsFake>(subprocessUtilsFake));
handleChassisResetActionInfoPost(
app_, CreateRequest("{\"ResetType\":\"PowerCycle\", \"Delay\":1} "),
share_async_resp_, "platform1");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
EXPECT_EQ(share_async_resp_->res.jsonValue["ResetString"],
"systemd-run --on-active=1 --timer-property=AccuracySec=100ms -- "
"systemctl start gbmc-psu-hardreset.target");
}
TEST_F(SnapshotFixture, PostChassisCycleDelayBadResetType) {
handleChassisResetActionInfoPost(
app_, CreateRequest("{\"ResetType\":\"PleaseReset\", \"Delay\":1} "),
share_async_resp_, "platform1");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::bad_request);
}
TEST_F(SnapshotFixture, PostChassisCycleDelayBadTime) {
handleChassisResetActionInfoPost(
app_, CreateRequest("{\"ResetType\":\"PowerCycle\", \"Delay\":3601} "),
share_async_resp_, "platform1");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::bad_request);
}
TEST_F(SnapshotFixture, PostChassisCycleInvalidParam) {
handleChassisResetActionInfoPost(
app_,
CreateRequest("{\"ResetType\":\"PowerCycle\", \"UnknownParm_foo\":30} "),
share_async_resp_, "platform1");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::bad_request);
}
} // namespace
} // namespace redfish